在Python运行时,有没有办法区分文字字符串实例和动态创建的字符串实例?
例如,我希望能够区分这两个值:
{{0, 2, 1}, {0, 1, 2}}
此检查的一个示例用例是保护类似{{0, 2, 1}}
的函数免受任何攻击,例如暴露局部变量的值。
如果不可能,有什么好理由吗?
并附注......
PEP 498 -- Literal String Interpolation引入了 f-strings ,它们是字符串文字,在标记化时可能会分为文字和表达式。
F字符串的工作方式与val1 = "Foo"
var2 = "%s" % "Foo"
非常相似,但输入的强制执行是文字字符串,代价是语言的语法更新。
如果在运行时可以使用这种检查,则f-strings可以作为函数实现。
正如@kevin在他的回答中所指出的,CPython具有优化功能,允许它在不需要创建新实例的情况下重用现有实例。在我的第一个示例中,只会链接到现有的string.Template
实例,跳过string.Template()
。
但这不是语言要求,事实上并非总是如此。除了一些明显的字符串格式之外的任何字符串格式都将导致创建新实例。
在下面的示例中,您可以看到虽然字符串的值相等,但它们不是同一个对象。但是,使用sys.intern()
会给我们提供相同的实例。
"%s" % "Foo"
如sys.intern()
中所述,"通常,Python程序中使用的名称会自动实现,用于保存模块,类或实例属性的字典具有实习键。"换句话说,通常,运算符字符串实例不会被实现。
答案 0 :(得分:3)
不,你不能这样做。或者至少,你不能在运行时这样做。如果您愿意接受编译时分析的限制,您可以使用ast
解析和检查Python代码,但这可能是一个比您正在寻找的更加复杂的工具,当然也会不允许你将f-string实现为函数。"
对于您的示例的特定情况,Python语言规范允许// After custom logic call any onKeyPress passed to this
this.props.onKeyPress && this.props.onKeyPress(e);
和var1
都指向同一个对象(如果您通过{{3功能并比较结果)。由于符合标准的Python实现可以对它们进行别名,因此没有可靠的方法来区分它们。事实上,当我在CPython 3.6.1中尝试它时,它们是别名:
var2
输出:
import dis
def foo():
var1 = "Foo"
var2 = "%s" % "Foo"
return var1 is var2
dis.dis(foo)
print(foo())
请注意,它甚至不会浪费时间来计算 4 0 LOAD_CONST 1 ('Foo')
2 STORE_FAST 0 (var1)
5 4 LOAD_CONST 3 ('Foo')
6 STORE_FAST 1 (var2)
6 8 LOAD_FAST 0 (var1)
10 LOAD_FAST 1 (var2)
12 COMPARE_OP 8 (is)
14 RETURN_VALUE
True
。它得到sys.intern()
字面值var2
,然后使用该函数已用于'Foo'
的其他'Foo'
进行重复数据删除。
(一个更积极的优化器可能会传播这些常量并将var1
转换为var1 is var2
,但CPython不会这样做(但是?),可能是因为很少使用{{1}对于像字符串这样的不可移动的值。大多数其他可以从常量传播中获益的操作都受到各种constant-folded的影响,这样就无法在绝大多数真实用例中进行优化。因此,我假设不值得实施。)
如果不可能,有什么好理由吗?
因为Python与大多数命令式语言一样,使用monkey patching,它会立即抛弃这些信息。使用懒惰评估的语言,这个问题至少是合理的,但我不相信大多数人都会保留这些信息。在大多数处理字符串的编程语言中,字符串是字面值还是非字面值的问题根本不被视为字符串值的一部分。