global关键字是否完全以python中的局部变量声明的形式内联global?

2024-04-19 10:01:18 发布

您现在位置:Python中文网/ 问答频道 /正文

那么这两个与性能是否完全等价(即生成的代码是否完全等价):

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

Tags: inselfforobjectdefdosomethingclass
2条回答

它是快还是慢实际上取决于您的作用域,作用域存储在字典中,字典越小,访问速度就越快。因为字典是作为哈希集实现的,所以查找性能是O(1)。你知道吗

无论何时尝试访问变量,Python都将按以下顺序遍历作用域:

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

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

  • __getattribute__
  • __dict__
  • __getattr__

所有继承的类也是如此。你知道吗

邓肯完美地回答了你剩下的问题

不,虽然差异不大,但它们并不完全相等。你知道吗

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不会生成全局的本地副本,因为没有简单的方法可以确保在代码运行时全局值不会更改。任何东西,甚至另一个线程或调试器,都可以在循环执行时修改该值。你知道吗

相关问题 更多 >