如果我说 x = x 会发生啥? (在低编译器级别)

Posted

技术标签:

【中文标题】如果我说 x = x 会发生啥? (在低编译器级别)【英文标题】:What happens if I say x = x? (On a low, compiler level)如果我说 x = x 会发生什么? (在低编译器级别) 【发布时间】:2016-05-28 23:41:34 【问题描述】:

在 Python(更具体地说是 Python 3.x)中,如果我说 x = x 会发生什么,其中 x 是对可变的引用(如 list)或对不可变的引用(如 @987654324 @) 在低级别?编译器会直接忽略这些废话吗?

更具体地说,如果我们遇到以下情况,编译器会做什么:

class A:
    def __init__(self):
        self.a = self.init_a()

    def init_a(self):
        self.a = some_value
        """
        do stuff with self.a here
        """
        return self.a

对于那些没有注意到的人,self.a 实际上是通过函数init_a(self) 分配给自己的。

我知道上面class A 的这种情况似乎很愚蠢,但我试图通过在__init__(self) 函数中清楚地初始化我的所有成员变量来保持我的代码清洁和可读性(在我正在实现的另一个类中) )。我只是想知道编译器是否优化了该步骤,或者它是否在任何情况下都进行了一些操作,即使该语句没有产生任何结果(我猜它被优化了,但我想成为当然 - 你永远不知道)。

【问题讨论】:

您应该在init_a 中将其称为a,并且仅将其附加到__init__ 中的self。否则,您将违背您的目标或“在 __init__(self) 函数中清楚地初始化我的所有成员变量”。 是的,这可能是一个更好的主意,但无论如何我都想知道上面的情况 【参考方案1】:
from dis import dis

def foo():
    x = 1
    x = x

dis(foo)

结果:

  4           0 LOAD_CONST               1 (1)
              3 STORE_FAST               0 (x)

  5           6 LOAD_FAST                0 (x)
              9 STORE_FAST               0 (x)
             12 LOAD_CONST               0 (None)
             15 RETURN_VALUE 

这表明即使在最微不足道的情况下,x = x 也没有被优化掉(在 CPython 中,dis 就是为了这个)。

【讨论】:

哇,没想到。感谢您展示有关如何获取该字节码的实际代码 - 现在知道要使用哪个库(并且有一个库)【参考方案2】:

出于兴趣,我只是想知道编译器是否优化了该步骤,或者它是否在任何情况下都进行了一些操作,即使该语句没有产生任何结果。

除非 Python 语言参考对此有所说明1,否则任何优化或缺乏它都是特定于实现的2。您可以调查特定的 Python 实现对此做了什么,但您无法推广到所有 Python 实现。


1 - 我粗略地搜索了规范中的this copy 并没有真正进行任何相关的优化讨论。因此,我的阅读是允许但不是必需的有效优化。 (有效的优化不会改变规范明确要求的有效 Python 程序的任何可观察行为。)

2 - 确实,规范是这样说的:“[在规范中列出的]这些实现中的每一个都在某种程度上与本手册中记录的语言有所不同,或者引入了 超出标准 Python 文档所涵盖的特定信息。请参考实施- 特定文档,以确定您需要了解的有关您正在使用的特定实现的其他信息。”

【讨论】:

同意 - 我确实想到它也可能是特定于实现的,因为似乎有很多不同的 Python 解释器。由于 Anaconda 和 Winpython 解释器都提供与 Alex Hall's answer 相同的字节码输出,因此 CPython 3.x 可能不会对此进行优化(假设 Anaconda 和 WinPython 使用 CPython,可能就是这种情况) 是的......但是当字节码被编译为本机代码时会发生什么?例如在 JVM 平台上,我会期望 JIT 编译器优化掉任何冗余分配。 我正在阅读this 答案和this 答案,CPython 解释其字节码,这意味着如果我是正确的,它会逐条指令读取它(即没有进一步优化)。但似乎 PyPy 确实编译了字节码,正如this 答案所示,所以 PyPy 有可能做这样的优化吗? (对于我来说,阅读 Cpython 和 PyPy 的文档来确认这一点为时已晚 - 这次我会相信那些回答者【参考方案3】:

这可能看起来很奇怪,但实际上不可能实现您建议的优化,因为 python 太动态了。

考虑以下代码:

[Definition of your A class]
@property
def sneaky(self):
    return self._a
@sneaky.setter
def sneaky(self, value):
    self._a = value * 2
A.a = sneaky
a = A()

__init__ 方法中的self.a = 突然开始生效!它使 a 的值加倍。 Python 确实非常动态。

【讨论】:

非常正确。在我问了这个问题之后,我实际上想到了描述符。例如,如果我们有一个描述符,为A 的成员a 定义了getter 和setter,那么A_obj.a = A_obj.a 首先调用getter 然后调用setter,所以它不能被优化掉,就像你说的那样。据我了解,描述符构成了 Python 的许多功能的基础,因为 here 他们声明“学习描述符......可以更深入地了解 Python 的工作原理并欣赏其优雅的设计。” (下续) 所以上面描述的 getter 和 setter 的事情在使用 Python 时可能经常发生,程序员不知道。 但这是您在上面发布的一个有趣的示例 - 确实非常狡猾!

以上是关于如果我说 x = x 会发生啥? (在低编译器级别)的主要内容,如果未能解决你的问题,请参考以下文章

如果:char x = short y in c++ 会发生啥

如果名称空间的网站不再可访问,会发生啥情况?

如果用户关闭已经在后台的应用程序会发生啥?

如果未指定 Internet Explorer 兼容性视图会发生啥

如果编译 AOSP/CM 被中断会发生啥

如果使用同一个锁进入不同的临界区会发生啥