어떻게 f-string 평가를 연기/연기합니까?
템플릿 문자열을 사용하여 일부 파일을 생성하고 있으며 이전 템플릿 코드를 다음과 같이 줄일 수 있는 새로운 f-string의 간결성이 좋습니다.
template_a = "The current name is {name}"
names = ["foo", "bar"]
for name in names:
print (template_a.format(**locals()))
이제 변수를 직접 대체하여 이 작업을 수행할 수 있습니다.
names = ["foo", "bar"]
for name in names:
print (f"The current name is {name}")
그러나 때때로 템플릿을 다른 곳(코드의 상위 위치)에서 정의하거나 파일 등에서 가져오는 것이 적절합니다.이는 템플릿이 형식 태그가 포함된 정적 문자열임을 의미합니다.통역사에게 문자열을 새로운 f-string으로 해석하라고 하려면 문자열에 무슨 일이 일어나야 할 텐데, 그런 일이 있는지 모르겠습니다.
을 가져와서 f-string을 할 수 ?.format(**locals())
전화요?
이상적으로 나는 이렇게 코딩할 수 있기를 원합니다.(어디서magic_fstring_function
이해할 수 없는 부분이 들어옵니다.):
template_a = f"The current name is {name}"
# OR [Ideal2] template_a = magic_fstring_function(open('template.txt').read())
names = ["foo", "bar"]
for name in names:
print (template_a)
...파일을 두 번 읽지 않고 원하는 출력을 사용할 경우:
The current name is foo
The current name is bar
...하지만 실제 출력은 다음과 같습니다.
The current name is {name}
The current name is {name}
문자열을 f-string으로 평가하는 간단한 방법은 다음 함수를 사용하는 것입니다.
def fstr(template):
return eval(f"f'{template}'")
그러면 다음을 수행할 수 있습니다.
template_a = "The current name is {name}"
names = ["foo", "bar"]
for name in names:
print(fstr(template_a))
# The current name is foo
# The current name is bar
또한 제안된 다른 많은 솔루션과 달리 다음과 같은 작업도 수행할 수 있습니다.
template_b = "The current name is {name.upper() * 2}"
for name in names:
print(fstr(template_b))
# The current name is FOOFOO
# The current name is BARBAR
여기 완전한 "이상적인 2"가 있습니다.
아니라합니다.f-string은 f-string을 사용합니다.지정된 구문과 정확하게 일치합니다.사용하지 않기 때문에 보안 문제가 없습니다.eval()
.
그것은 약간의 수업을 사용하고 실행합니다.__str__
인쇄에 의해 자동으로 호출됩니다.는 수의제범벗위위어기사해다우용니합리는나한를업된▁the다▁to▁we니사▁use용합▁class▁the▁of우▁escape리는위를 사용합니다.inspect
모듈을 사용하여 한 프레임을 위로 이동하고 발신자가 액세스할 수 있는 변수를 확인합니다.
import inspect
class magic_fstring_function:
def __init__(self, payload):
self.payload = payload
def __str__(self):
vars = inspect.currentframe().f_back.f_globals.copy()
vars.update(inspect.currentframe().f_back.f_locals)
return self.payload.format(**vars)
template = "The current name is {name}"
template_a = magic_fstring_function(template)
# use it inside a function to demonstrate it gets the scoping right
def new_scope():
names = ["foo", "bar"]
for name in names:
print(template_a)
new_scope()
# The current name is foo
# The current name is bar
이는 템플릿이 형식 지정 태그가 포함된 정적 문자열임을 의미합니다.
네, 그래서 우리는 대체 분야를 가진 리터럴과.format
그래서 우리는 우리가 원할 때 언제든지 전화로 필드를 교체를 할 수 있습니다.format
그 위에
해석기가 문자열을 새 f-string으로 해석하도록 하려면 문자열에 어떤 일이 발생해야 합니다.
그게접야사입니다.f/F
함수로 래핑하여 통화 시간 동안 평가를 연기할 수 있지만, 물론 추가 비용이 발생합니다.
def template_a():
return f"The current name is {name}"
names = ["foo", "bar"]
for name in names:
print(template_a())
출력 결과:
The current name is foo
The current name is bar
그러나 교체할 때는 글로벌 네임스페이스만 볼 수 있다는 점에서 문제를 느끼고 제한을 받습니다.지역 이름이 필요한 상황에서 사용하려고 하는 것은 (완전히 요점을 벗어난) 인수로 문자열에 전달되지 않는 한 비참하게 실패할 것입니다.
을 가져와서 f-string을 할 수 ?
.format(**locals())
전화요?
기능(제한 포함) 이외에는 아니요, 그래서 계속하는 것이 나을 수 있습니다..format
.
어때요?
s = 'Hi, {foo}!'
s
> 'Hi, {foo}!'
s.format(foo='Bar')
> 'Hi, Bar!'
.format을 사용하는 것은 이 질문에 대한 정답이 아닙니다.Python f-string은 str.format() 템플릿과 매우 다릅니다...코드 또는 기타 값비싼 작업을 포함할 수 있으므로 연기가 필요합니다.
다음은 지연 로거의 예입니다.이는 logging.getLogger의 일반 프리암블을 사용하지만 로그 수준이 올바른 경우에만 f-string을 해석하는 새 함수를 추가합니다.
log = logging.getLogger(__name__)
def __deferred_flog(log, fstr, level, *args):
if log.isEnabledFor(level):
import inspect
frame = inspect.currentframe().f_back.f_back
try:
fstr = 'f"' + fstr + '"'
log.log(level, eval(fstr, frame.f_globals, frame.f_locals))
finally:
del frame
log.fdebug = lambda fstr, *args: __deferred_flog(log, fstr, logging.DEBUG, *args)
log.finfo = lambda fstr, *args: __deferred_flog(log, fstr, logging.INFO, *args)
은 다음과 같은을 할 수 .log.fdebug("{obj.dump()}")
디버깅이 활성화되지 않은 경우 개체를 덤프하지 않습니다.
IMHO: 이것은 f-string의 기본 동작이어야 했지만, 지금은 너무 늦었습니다.F-string 평가는 막대한 부작용과 의도하지 않은 부작용을 초래할 수 있으며, 지연된 방식으로 발생하면 프로그램 실행이 변경됩니다.
f-string을 적절하게 지연시키려면 python은 동작을 명시적으로 전환하는 어떤 방법이 필요합니다.'g'자를 사용해도 될까요?;)
문자열 변환기에 버그가 있을 경우 지연 로깅이 중단되지 않아야 한다는 지적이 제기되었습니다.위의 솔루션도 이를 수행할 수 있습니다. 변경할 수 있습니다.finally:
except:
그리고 a를 붙입니다.log.exception
저 안에
f-string은 단순히 형식화된 문자열을 만드는 보다 간결한 방법입니다..format(**names)
와 함께f
문자열을 이러한 방식으로 즉시 평가하지 않으려면 문자열을 f-string으로 만들지 마십시오.리터럴로 에 일반문리로저다장한호음출럴터열을 호출합니다.format
당신이 해왔던 것처럼, 나중에 보간을 수행하고 싶을 때 그것에.
물론, 다른 대안이 있습니다.eval
.
template.txt
:
f'현재 이름은 {name}입니다.'
코드:
>>> template_a = open('template.txt').read()
>>> names = 'foo', 'bar'
>>> for name in names:
... print(eval(template_a))
...
The current name is foo
The current name is bar
하지만 당신이 할 수 있는 일이라고는str.format
와 함께eval
그럴만한 가치가 없는 것은 분명합니다.일반 문자열을 계속 사용합니다.format
콜.콜.
당신이 원하는 것은 파이썬 향상으로 간주되고 있는 것으로 보입니다.
한편, 링크된 토론에서 볼 때, 다음은 사용할 필요가 없는 합리적인 해결 방법인 것 같습니다.eval()
:
class FL:
def __init__(self, func):
self.func = func
def __str__(self):
return self.func()
template_a = FL(lambda: f"The current name, number is {name!r}, {number+1}")
names = "foo", "bar"
numbers = 40, 41
for name, number in zip(names, numbers):
print(template_a)
출력:
The current name, number is 'foo', 41
The current name, number is 'bar', 42
카데의 답변에서 영감을 받아, 다음을 사용하여 지연된 f-string 클래스를 정의할 수 있습니다.
class FStr:
def __init__(self, s):
self._s = s
def __repr__(self):
return eval(f"f'{self._s}'")
...
template_a = FStr('The current name is {name}')
names = ["foo", "bar"]
for name in names:
print (template_a)
그것이 정확히 질문이 요구한 것입니다.
또는 f-string을 사용하지 않고 형식만 지정할 수 있습니다.
fun = "The curent name is {name}".format
names = ["foo", "bar"]
for name in names:
print(fun(name=name))
이름이 없는 버전:
fun = "The curent name is {}".format
names = ["foo", "bar"]
for name in names:
print(fun(name))
이 대답들의 대부분은 여러분이 가끔은 현을 빼는 것처럼 행동하는 것을 얻을 것이지만, 어떤 경우에는 모두 잘못될 것입니다.Pypi에 소포가 있습니다.f-yeah
그것은 이 모든 것을 하고, 당신에게 단지 두 개의 추가적인 캐릭터만 비용이 듭니다! (완전한 공개, 나는 작가입니다)
from fyeah import f
print(f("""'{'"all" the quotes'}'"""))
f-string과 형식 호출 사이에는 많은 차이가 있습니다. 여기에는 아마도 불완전한 목록이 있습니다.
- f-paths를 사용하면 python 코드의 임의 평가가 가능
- f-strings는 식에 백슬래시를 포함할 수 없습니다(포맷된 문자열에는 식이 없기 때문에 이것은 차이가 없지만 원시 평가()와 다를 수 있습니다).
- 형식이 지정된 문자열의 dict 조회를 따옴표로 묶어서는 안 됩니다.f-string에서 dict 조회를 인용할 수 있으므로 문자열이 아닌 키도 조회할 수 있습니다.
- 에는 format가 없는 . f-filename 형식은 다음과 같습니다.
f"The argument is {spam=}"
- f-string 식은 비워 둘 수 없습니다.
eval을 사용하라는 제안은 완전한 f-string 형식을 지원하지만 모든 문자열 유형에서 작동하지는 않습니다.
def f_template(the_string):
return eval(f"f'{the_string}'")
print(f_template('some "quoted" string'))
print(f_template("some 'quoted' string"))
some "quoted" string
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in f_template
File "<string>", line 1
f'some 'quoted' string'
^
SyntaxError: invalid syntax
이 예제에서는 경우에 따라 변수 범위 지정이 잘못될 수도 있습니다.
이를 위해 다음과 같은 람다 함수 안에 fstring을 사용하는 것을 선호합니다.
s = lambda x: f'this is your string template to embed {x} in it.'
n = ['a' , 'b' , 'c']
for i in n:
print( s(i) )
를 사용하는 것에 대해 많은 이야기가 있습니다.str.format()
그러나 언급했듯이 산술이나 슬라이스와 같은 f-변수에서 허용되는 대부분의 식을 허용하지 않습니다.용사를 합니다.eval()
분명히 단점도 있습니다.
저는 진자와 같은 템플릿 언어를 알아보는 것을 추천합니다.제 경우에는 꽤 잘 작동합니다.변수 주석 구문을 f-string 구문과 일치하도록 단일 곱슬곱슬한 대괄호로 재정의한 아래 예제를 참조하십시오.이렇게 호출된 f-string과 진자의 차이점을 충분히 검토하지 못했습니다.
from jinja2 import Environment, BaseLoader
a, b, c = 1, 2, "345"
templ = "{a or b}{c[1:]}"
env = Environment(loader=BaseLoader, variable_start_string="{", variable_end_string="}")
env.from_string(templ).render(**locals())
의 결과.
'145'
저는 이 문제가 꽤 흥미로웠고 게으른 f-string을 구현하는 저만의 라이브러리를 썼습니다.
설치:
pip install fazy
사용 방법:
import f
number = 33
print(f('{number} kittens drink milk'))
이 솔루션은 예를 들어 로깅에 적합합니다.링크에서 설명서의 기능 및 제한 사항에 대해 자세히 알아보십시오.
f-string을 사용하는 제안입니다.템플릿이 발생하는 논리적 수준에서 평가를 수행하여 생성기로 전달합니다.F-스트링을 사용하여 원하는 지점에서 풀 수 있습니다.
In [46]: names = (i for i in ('The CIO, Reed', 'The homeless guy, Arnot', 'The security guard Spencer'))
In [47]: po = (f'Strangely, {next(names)} has a nice {i}' for i in (" nice house", " fast car", " big boat"))
In [48]: while True:
...: try:
...: print(next(po))
...: except StopIteration:
...: break
...:
Strangely, The CIO, Reed has a nice nice house
Strangely, The homeless guy, Arnot has a nice fast car
Strangely, The security guard Spencer has a nice big boat
▁a를 사용할 수 ..format
스타일 변경 및 교체된 변수 이름을 명시적으로 정의합니다.
template_a = "The current name is {name}"
names = ["foo", "bar"]
for name in names:
print (template_a.format(name=name))
산출량
The current name is foo
The current name is bar
언급URL : https://stackoverflow.com/questions/42497625/how-to-postpone-defer-the-evaluation-of-f-strings
'programing' 카테고리의 다른 글
AKS(Azure Managed Kubernetes)에서 모든 컴퓨팅을 중지 (0) | 2023.05.11 |
---|---|
Postgre에 행이 있는지 가장 빠르게 확인SQL (0) | 2023.05.11 |
Git를 사용하여 모든 분기에서 문자열을 검색하려면 어떻게 해야 합니까? (0) | 2023.05.06 |
Xcode 빌드 설정에서 "아키텍처"와 "유효한 아키텍처"의 차이점은 무엇입니까? (0) | 2023.05.06 |
C++ std:: 문자열이 특정 문자열로 시작하는지 확인하고 하위 문자열을 int로 변환하려면 어떻게 해야 합니까? (0) | 2023.05.06 |