2 回答

TA貢獻1827條經驗 獲得超9個贊
即使有值得信賴的用戶,使用也eval應該只是最后的手段。
如果您愿意犧牲語法的靈活性以獲得更多的安全性和控制,那么您可以使用str.format并提供它的整個范圍。
這將不允許對表達式求值,但單個變量將被格式化到輸出中。
代碼
x = 3
y = 'foo'
s = input('> ')
print(s.format(**vars()))
例子
> {x} and {y}
3 and foo

TA貢獻1993條經驗 獲得超6個贊
這是我對 f-strings 進行更可靠評估的嘗試,靈感來自kadee對類似問題的優(yōu)雅回答。
但是,我想避免該eval方法的一些基本陷阱。例如,eval(f"f'{template}'")只要模板包含一個撇號就會失敗,例如the string's evaluation成為f'the string's evaluation'它以語法錯誤評估。第一個改進是使用三撇號:
eval(f"f'''{template}'''")
現在在模板中使用撇號(大部分)是安全的,只要它們不是三重撇號。(三引號也可以。)一個值得注意的例外是字符串末尾的撇號:whatcha doin'變成f'''whatcha doin''''在第四個連續(xù)撇號處計算語法錯誤。以下代碼通過去除字符串末尾的撇號并在計算后將它們放回去來避免此特定問題。
import builtins
def fstr_eval(_s: str, raw_string=False, eval=builtins.eval):
r"""str: Evaluate a string as an f-string literal.
Args:
_s (str): The string to evaluate.
raw_string (bool, optional): Evaluate as a raw literal
(don't escape \). Defaults to False.
eval (callable, optional): Evaluation function. Defaults
to Python's builtin eval.
Raises:
ValueError: Triple-apostrophes ''' are forbidden.
"""
# Prefix all local variables with _ to reduce collisions in case
# eval is called in the local namespace.
_TA = "'''" # triple-apostrophes constant, for readability
if _TA in _s:
raise ValueError("Triple-apostrophes ''' are forbidden. " + \
'Consider using """ instead.')
# Strip apostrophes from the end of _s and store them in _ra.
# There are at most two since triple-apostrophes are forbidden.
if _s.endswith("''"):
_ra = "''"
_s = _s[:-2]
elif _s.endswith("'"):
_ra = "'"
_s = _s[:-1]
else:
_ra = ""
# Now the last character of s (if it exists) is guaranteed
# not to be an apostrophe.
_prefix = 'rf' if raw_string else 'f'
return eval(_prefix + _TA + _s + _TA) + _ra
在不指定評估函數的情況下,該函數的局部變量是可訪問的,因此
print(fstr_eval(r"raw_string: {raw_string}\neval: {eval}\n_s: {_s}"))
印刷
raw_string: False
eval: <built-in function eval>
_s: raw_string: {raw_string}\neval: {eval}\n_s: {_s}
雖然前綴_降低了意外碰撞的可能性,但可以通過傳遞適當的評估函數來避免該問題。例如,可以通過以下方式傳遞當前的全局命名空間lambda:
fstr_eval('{_s}', eval=lambda expr: eval(expr))#NameError: name '_s' is not defined
或更一般地,通過將合適的globals和locals參數傳遞給eval,例如
fstr_eval('{x+x}', eval=lambda expr: eval(expr, {}, {'x': 7})) # 14
我還包含了一種機制,\可以通過“原始字符串文字”機制選擇是否應將其視為轉義字符。例如,
print(fstr_eval(r'x\ny'))
產量
x
y
盡管
print(fstr_eval(r'x\ny', raw_string=True))
產量
x\ny
可能還有其他我沒有注意到的陷阱,但出于許多目的,我認為這已經足夠了。
添加回答
舉報