일부 파일을 생성하기 위해 템플릿 문자열을 사용하고 있으며 다음과 같이 이전 템플릿 코드를 줄이기 위해 이러한 목적으로 새 f- 문자열의 간결함을 좋아합니다.
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- 문자열로 해석하도록 지시하기 위해 문자열에 어떤 일이 발생해야하지만 그런 것이 있는지 모르겠습니다.
문자열을 가져와 .format(**locals())
호출을 사용하지 않도록 f- 문자열로 해석하는 방법이 있습니까?
이상적으로는 다음과 같이 코딩 할 수 있기를 원합니다 … ( 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}
답변
여기에 완전한 “이상적인 2″가 있습니다.
f- 문자열이 아닙니다. f- 문자열도 사용하지 않지만 요청한대로 수행합니다. 지정된 구문과 정확히 일치합니다. 을 사용하지 않기 때문에 보안 문제가 없습니다 eval()
.
작은 클래스를 사용하고 __str__
print에 의해 자동으로 호출되는 구현 합니다. 제한된 클래스 범위를 벗어나기 위해 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- 문자열로 해석하도록 지시하려면 문자열에 어떤 일이 발생해야합니다.
그것이 접두사 f/F
입니다. 함수로 래핑하고 호출 시간 동안 평가를 연기 할 수 있지만 물론 추가 오버 헤드가 발생합니다.
template_a = lambda: 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
그러나 잘못된 느낌이 들며 대체 항목에서 전역 네임 스페이스 만 엿볼 수 있다는 사실로 제한됩니다. 로컬 이름이 필요한 상황에서 사용하려고 시도하면 문자열에 인수로 전달되지 않는 한 비참하게 실패합니다 (이는 완전히 요점을 능가합니다).
문자열을 가져와
.format(**locals())
호출을 사용하지 않도록 f- 문자열로 해석하는 방법이 있습니까?
기능 (제한 사항 포함) 외에는 .format
.
답변
문자열을 f- 문자열 (전체 기능 포함)로 평가하는 간결한 방법은 다음 함수를 사용하는 것입니다.
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
답변
f- 문자열은 형식이 지정된 문자열을 만드는보다 간결한 방법 .format(**names)
으로 f
. 문자열이 이러한 방식으로 즉시 평가되는 것을 원하지 않으면 f- 문자열로 만들지 마십시오. 일반 문자열 리터럴로 저장 한 다음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
호출시 일반 문자열을 계속 사용 하십시오.
답변
.format을 사용하는 것은이 질문에 대한 정답이 아닙니다. 파이썬 f- 문자열은 str.format () 템플릿과 매우 다릅니다 … 그들은 코드 나 다른 값 비싼 작업을 포함 할 수 있습니다. 따라서 지연이 필요합니다.
다음은 지연된 로거의 예입니다. 이것은 logging.getLogger의 일반적인 프리앰블을 사용하지만 로그 수준이 올바른 경우에만 f- 문자열을 해석하는 새 함수를 추가합니다.
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- 문자열 의 기본 작업 이어야 했지만 지금은 너무 늦었습니다 . F- 문자열 평가는 방대하고 의도하지 않은 부작용을 가질 수 있으며 지연된 방식으로 발생하면 프로그램 실행이 변경됩니다.
f- 문자열을 적절하게 지연 시키려면 파이썬이 명시 적으로 동작을 전환하는 방법이 필요합니다. 문자 ‘g’를 사용할까요? 😉
문자열 변환기에 버그가 있으면 지연된 로깅이 충돌하지 않아야한다는 지적이 있습니다. 위의 솔루션은 물론 이렇게하려면 변경할 수 있습니다 finally:
에except:
, 그리고 스틱 log.exception
거기에.
답변
당신이 원하는 것은 파이썬 향상 으로 간주되는 것 같습니다 .
한편-연결된 토론에서-다음은 사용할 필요가없는 합리적인 해결 방법 인 것 같습니다 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