【发布时间】:2018-01-27 02:54:18
【问题描述】:
在 Python 运行时,有没有办法区分文字字符串实例和动态创建的实例?
例如,我希望能够区分这两个值:
val1 = "Foo"
var2 = "%s" % "Foo"
此检查的一个示例用例是保护类似string.Template 的函数免受任何攻击,例如暴露局部变量的值。
如果不可能,有什么好的理由吗?
还有一个旁注......
PEP 498 -- Literal String Interpolation 引入了 f-strings,它们是字符串文字,可以在标记化时拆分为文字和表达式。
F-strings 的工作方式与 string.Template() 非常相似,但强制输入为文字字符串,代价是语言的语法更新。
如果这种检查在运行时可用,则 f-strings 可以作为函数实现。
更新 1
正如@kevin 在他的回答中指出的那样,CPython 进行了优化,允许它在不需要创建新实例时重用现有实例。在我的第一个示例中,"%s" % "Foo" 被跳过,仅链接到现有的 "Foo" 实例。
但这不是语言要求,事实上并不总是这样。除了一些明显的字符串格式之外的任何字符串格式都会导致创建一个新实例。
在下面的例子中,你可以看到虽然字符串值相等,但它们不是同一个对象。不过,使用 sys.intern() 会给我们同样的实例。
In [1]: import dis
...: import sys
...:
...: def foo():
...: var1 = "Foo Bar"
...: var2 = "%s %s" % ("Foo", "Bar")
...: print(f'plain eq: {var1 == var2}')
...: print(f'plain is: {var1 is var2}')
...: print(f'intern is: {sys.intern(var1) is sys.intern(var2)}')
...:
...: dis.dis(foo)
...: foo()
...:
5 0 LOAD_CONST 1 ('Foo Bar')
2 STORE_FAST 0 (var1)
6 4 LOAD_CONST 9 ('Foo Bar')
6 STORE_FAST 1 (var2)
7 8 LOAD_GLOBAL 0 (print)
10 LOAD_CONST 5 ('plain eq: ')
12 LOAD_FAST 0 (var1)
14 LOAD_FAST 1 (var2)
16 COMPARE_OP 2 (==)
18 FORMAT_VALUE 0
20 BUILD_STRING 2
22 CALL_FUNCTION 1
24 POP_TOP
8 26 LOAD_GLOBAL 0 (print)
28 LOAD_CONST 6 ('plain is: ')
30 LOAD_FAST 0 (var1)
32 LOAD_FAST 1 (var2)
34 COMPARE_OP 8 (is)
36 FORMAT_VALUE 0
38 BUILD_STRING 2
40 CALL_FUNCTION 1
42 POP_TOP
9 44 LOAD_GLOBAL 0 (print)
46 LOAD_CONST 7 ('intern is: ')
48 LOAD_GLOBAL 1 (sys)
50 LOAD_ATTR 2 (intern)
52 LOAD_FAST 0 (var1)
54 CALL_FUNCTION 1
56 LOAD_GLOBAL 1 (sys)
58 LOAD_ATTR 2 (intern)
60 LOAD_FAST 1 (var2)
62 CALL_FUNCTION 1
64 COMPARE_OP 8 (is)
66 FORMAT_VALUE 0
68 BUILD_STRING 2
70 CALL_FUNCTION 1
72 POP_TOP
74 LOAD_CONST 0 (None)
76 RETURN_VALUE
plain eq: True
plain is: False
intern is: True
如sys.intern() 中所述,“通常,Python 程序中使用的名称是自动实习的,用于保存模块、类或实例属性的字典具有实习键。”换句话说,通常情况下,运行时字符串实例不会被实习。
【问题讨论】:
-
string.Template只会填写你传递给.substitute()的内容,你能演示一下你担心的攻击吗? -
使用
locals()(或*locals())将所有局部变量传递给. substitute()或.format()是很常见的。 -
套用我的医生的话,“如果您这样做时它会泄露信息,请不要这样做。”
标签: python string python-3.x