繁体   English   中英

global 关键字是否与 python 中的局部变量声明完全一样内联全局?

[英]Does the global keyword inline the global exactly as a local variable declaration in python?

那么这两个在 vis 性能方面是否完全等效(即,生成的代码是否完全等效):

class A(object):
    const = 'abc'

    def lengthy_op(self):
        const = self.const
        for i in xrange(AVOGADRO):
            # do something which involves reading const

和:

const = 'abc'
class A(object):

    def lengthy_op(self):
        global const
        for i in xrange(AVOGADRO):
            # do something which involves reading const

不,它们并不完全等效,尽管差异不太可能显着。

class A(object):
    const = 'abc'

    def lengthy_op(self):
        const = self.const
        for i in xrange(AVOGADRO):
            # do something which involves reading const

这将创建一个局部变量,因此对 const 的任何访问都将使用LOAD_FAST操作码。

const = 'abc'
class A(object):

    def lengthy_op(self):
        # global const
        for i in xrange(AVOGADRO):
            # do something which involves reading const

无论有没有冗余的global const使用LOAD_GLOBAL来访问全局变量constxrangeAVOGADRO

在 C Python LOAD_GLOBAL将执行快速字典查找以访问变量(快速因为全局变量位于仅使用字符串键的字典中并且哈希值是预先计算的)。 另一方面, LOAD_FAST只是访问第一个、第二个、第三个等局部变量,这是一个数组索引操作。

其他版本的 Python(例如 PyPy)可能能够优化访问全局变量,在这种情况下可能根本没有任何区别。

第一个代码(以n=i+const作为循环体)反汇编为:

>>> dis.dis(A.lengthy_op)
  5           0 LOAD_FAST                0 (self)
              3 LOAD_ATTR                0 (const)
              6 STORE_FAST               1 (const)

  6           9 SETUP_LOOP              30 (to 42)
             12 LOAD_GLOBAL              1 (xrange)
             15 LOAD_GLOBAL              2 (AVOGADRO)
             18 CALL_FUNCTION            1
             21 GET_ITER            
        >>   22 FOR_ITER                16 (to 41)
             25 STORE_FAST               2 (i)

  8          28 LOAD_FAST                2 (i)
             31 LOAD_FAST                1 (const)
             34 BINARY_ADD          
             35 STORE_FAST               3 (n)
             38 JUMP_ABSOLUTE           22
        >>   41 POP_BLOCK           
        >>   42 LOAD_CONST               0 (None)
             45 RETURN_VALUE        

而第二个块给出:

>>> dis.dis(A.lengthy_op)
  5           0 SETUP_LOOP              30 (to 33)
              3 LOAD_GLOBAL              0 (xrange)
              6 LOAD_GLOBAL              1 (AVOGADRO)
              9 CALL_FUNCTION            1
             12 GET_ITER            
        >>   13 FOR_ITER                16 (to 32)
             16 STORE_FAST               1 (i)

  7          19 LOAD_FAST                1 (i)
             22 LOAD_GLOBAL              2 (const)
             25 BINARY_ADD          
             26 STORE_FAST               2 (n)
             29 JUMP_ABSOLUTE           13
        >>   32 POP_BLOCK           
        >>   33 LOAD_CONST               0 (None)
             36 RETURN_VALUE        

Python 不会制作全局变量的本地副本,因为没有简单的方法可以确保在代码运行时全局值不会改变。 任何东西,甚至是另一个线程或调试器,都可以在循环执行时修改该值。

它是更快还是更慢实际上取决于您的范围,范围存储在字典中,字典越小,访问速度(略微)越快。 由于字典是作为哈希集实现的,因此查找性能是 O(1)。

每当您尝试访问变量时,Python 都会按以下顺序遍历范围:

  • 当地的。 作为当前函数作用域的本地命名空间。
  • 封闭函数局部变量。 根据嵌套函数/ lambda 的数量,可以有更多这些。
  • 全球的。 全局范围只是另一个字典(您可以通过globals()访问)
  • 内置插件。 在所有范围内都可用的标准 Python 内置函数,例如listint等。

访问函数/类属性的工作方式类似,但涉及:

  • __getattribute__
  • __dict__
  • __getattr__

这也适用于所有继承的类。

邓肯完美地回答了您的其余问题

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM