我检查了.__code__
对象的两个函数,我认为它们对于各种表达式而言是不同的,但发现是相同的。据我所知,如果代码对象相同,它们将编译为相同的字节码,因此是“相同”的函数。
下表是在; pass
之前插入的内容,这些内容使g
具有不同的__code__
。由于f
是“不执行任何操作”功能,因此建议对[[从不执行“相同”下的所有内容,包括长运算。此外,元组是“相同”的,但列表和字符串是“ diff”的-因此我们可能得出的结论是,未评估涉及unmutableliteral的unssigned表达式。但是接着是1/0
,由于引发异常可能是“例外”-那么10**99
与10**9
到底是什么? 10**99
不会引发异常,可以分配。
可以
被区分时,总是带有“ diff”。如果“相同”从不执行,那么Python如何确定要执行或不执行什么?如果它们确实执行,它们的代码对象如何相同?相同:
0
,(0,)
,True
,False
,None
10 ** 9
()
-314159.265358 ** (1/12345) / 2.718281828 + 500 - 7j
Diff
[0]
,{0: 0}
10 ** 99
[]
,{}
,""
比较代码
def compare(fn1, fn2):
for name in dir(fn1.__code__):
if (name.startswith("co_") and
name not in ("co_filename", "co_name", "co_firstlineno")):
v1 = getattr(fn1.__code__, name)
v2 = getattr(fn2.__code__, name)
if v1 == v2:
print(name.ljust(18), "same")
else:
print(name.ljust(18), "diff", v1, v2)
def f():
pass
def g():
10 ** 99; pass
以下内容有所不同:co_name
(始终),co_filename
(IPython),co_firstlineno
(来自文件)-但不影响“执行”的内容,如果有误,请纠正我;与docs不同,co_code
应该有所不同。
[]
,{}
)或不适合预评估(例如10 ** 99
小于其值)。 “相同”组的所有表达式求值为常数,可以将其丢弃。检查字节码表明表达式已完全删除:>>> # CPython 3.7.4
>>> def g(): 10/1; pass
>>> dis.dis(g)
1 0 LOAD_CONST 0 (None)
2 RETURN_VALUE
值得注意的是,删除的表达式均未更改可观察的行为。 Python实现是否消除了不可观察的行为,纯粹是实现细节。具有副作用的表达式,例如
1/0
,不会被删除。>>> # CPython 3.7.4 >>> def g(): 10/0; pass >>> dis.dis(g) 1 0 LOAD_CONST 1 (10) 2 LOAD_CONST 2 (0) 4 BINARY_TRUE_DIVIDE 6 POP_TOP 8 LOAD_CONST 0 (None) 10 RETURN_VALUE
对于所示的表达式,字节码在CPython 3.7.4,CPython 3.8.2,PyPy 3.6.9 [PyPy 7.3.0]上是相同的。在CPython 3.4.3上,对常量表达式求值,但不丢弃。
>>> # CPython 3.4.3 >>> def g(): 10/1; pass >>> dis.dis(g) 1 0 LOAD_CONST 3 (10.0) 3 POP_TOP 4 LOAD_CONST 0 (None) 7 RETURN_VALUE