Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
global关键字是否完全像python中的局部变量声明一样内联global?_Python_Performance_Python 2.7_Global_Globals - Fatal编程技术网

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

global关键字是否完全像python中的局部变量声明一样内联global?,python,performance,python-2.7,global,globals,Python,Performance,Python 2.7,Global,Globals,那么这两种性能是否完全相同(即生成的代码是否完全相同): 以及: 不,它们并不完全相同,尽管差别不大可能很大 class A(object): const = 'abc' def lengthy_op(self): const = self.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\u FAST
opcode

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\u global
来访问全局变量
const
xrange
AVOGADRO
的值

在C Python中,LOAD_GLOBAL将执行快速字典查找以访问变量(快速,因为全局变量在字典中仅使用字符串键,并且哈希值是预先计算的)<另一方面,code>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内置程序,如
    list
    int
访问函数/类属性的工作方式类似,但涉及:

  • \uuuu获取属性\uuuuu
  • \uuuu指令
  • \uuuu getattr\uuuuu
这也适用于所有继承类


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

如果您以只读方式使用变量,则不需要全局关键字。我希望点访问会稍微慢一点,但像这样的问题的答案总是“测量它”。无论如何,这不太可能成为性能瓶颈。@Rogalski:我知道不需要它——我的问题是它是否在局部范围内联全局(使其与另一个等效)。在两种情况下仅使用名称“const”的循环中,点访问执行一次,全局查找也执行一次(我的问题是它们之后是否等效)。这将由能够产生字节码的人立即回答,而不是通过测量,它应该是确定的-除非我遗漏了什么…我希望全局访问会更慢,因为变量名首先在局部范围的符号表中搜索,在全局中,只有在找不到任何内容时,
global
说明符才是真正的说明符,虽然对正确性来说是不必要的,但可能会提高性能,因为它会绕过本地范围内的任何检查。@TomKarzes:正是我的观点-现在如果我们可以删除“may”…ha-那么添加global关键字并不等同于
global const;局部常数=常数然后使用本地常量
。有什么原因吗?全局声明这样做没有意义,或者它会破坏某些东西吗?Python不知道全局
const
不会变化,所以它不能只是复制它,或者至少不能不做Python的C实现所不能做的其他优化。所以我想知道的底线是,如果全局变量是只读的,那么它是否会在局部变量中添加一个条目:“任何东西,即使是另一个线程或调试器,都可以在循环执行时修改该值”-非常感谢这正是我想要的:)至于表现,我打赌这种差异会对阿伏伽德罗产生几千年的影响。D:为什么每当有人问到关于表现的问题时,人们总是向你抛出库恩的话,好像你不知道,而不是看着这个问题-嘿男生表演不是禁忌,我们是成年人;)实际上,我认为您会发现您的代码抛出
TypeError:integer参数expected,get float
overflowerrror:Python int太大,无法转换为C long
,具体取决于
AVOGADRO
的值。升级到Python3并使用
range()
,您可能会让它正常工作。
>>> 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