程序是否真的每次都创建了内部对象?

use*_*548 1 python coding-style python-3.x

为什么我问这个问题,因为我总是担心这种风格的代码

def callsomething(x):
    if x in (3,4,5,6):
        #do something
Run Code Online (Sandbox Code Playgroud)

如果函数调用的东西经常被调用,那么(3,4,5,6)是否浪费了太多的空间和时间?在某些语言如C中,它可能被推入数据段,如常量,但在python中,我不知道它是如何工作的,所以我倾向于编写这样的代码

checktypes = (3,4,5,6)#cache it
def callsomething(x):
    global checktypes
    if x in checktypes:
        #do something
Run Code Online (Sandbox Code Playgroud)

但经过测试我发现这种方式使程序变慢,在更复杂的情况下,代码将是这样的:

types = (3,4,5,6)
def callsomething(x):
    global types
    for t in types:
        t += x
        #do something
Run Code Online (Sandbox Code Playgroud)

仍然比这慢

def callsomething(x):
    for t in (3+x,4+x,5+x,6+x):
        #do something
Run Code Online (Sandbox Code Playgroud)

在这种情况下,程序必须创建(3 + x,4 + x,5 + x,6 + x),对吧?但它仍然比第一个版本更快,但不是太多了.

我知道python中的全局var访问会减慢程序,但它与创建结构的比较有多大?

Joh*_*ooy 8

别担心,它存储为常量(这解释了为什么它比你预期的更快)

>>> def callsomething(x):
...     if x in (3,4,5,6): pass
... 
>>> import dis
>>> dis.dis(callsomething)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               5 ((3, 4, 5, 6))
              6 COMPARE_OP               6 (in)
              9 POP_JUMP_IF_FALSE       15
             12 JUMP_FORWARD             0 (to 15)
        >>   15 LOAD_CONST               0 (None)
             18 RETURN_VALUE        
Run Code Online (Sandbox Code Playgroud)

仰望x一个set应该更快,对吗?但是呃哦......

>>> def callsomething(x):
...     if x in {3,4,5,6}: pass
... 
>>> dis.dis(callsomething)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               1 (3)
              6 LOAD_CONST               2 (4)
              9 LOAD_CONST               3 (5)
             12 LOAD_CONST               4 (6)
             15 BUILD_SET                4
             18 COMPARE_OP               6 (in)
             21 POP_JUMP_IF_FALSE       27
             24 JUMP_FORWARD             0 (to 27)
        >>   27 LOAD_CONST               0 (None)
             30 RETURN_VALUE      
Run Code Online (Sandbox Code Playgroud)

set是可变的,所以Python直到最近才进行这种优化.Python3.3认为将其变为冻结集是安全的

Python 3.3.0 (default, Sep 29 2012, 17:17:45) 
[GCC 4.7.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> def callsomething(x):
...     if x in {3,4,5,6}: pass
... 
>>> import dis
>>> dis.dis(callsomething)
  2           0 LOAD_FAST                0 (x) 
              3 LOAD_CONST               5 (frozenset({3, 4, 5, 6})) 
              6 COMPARE_OP               6 (in) 
              9 POP_JUMP_IF_FALSE       15 
             12 JUMP_FORWARD             0 (to 15) 
        >>   15 LOAD_CONST               0 (None) 
             18 RETURN_VALUE         
>>> 
Run Code Online (Sandbox Code Playgroud)

  • @Patashu,没有.如果你看一下反汇编,你会注意到`冷冻集'的`LOAD_GLOBAL`,`set`仍然被构造,然后传递给`frozenset`. (2认同)