Skip to main content
 首页 » 编程设计

python之程序真的每次都创建了内部对象吗

2025年05月04日11三少

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

def callsomething(x): 
    if x in (3,4,5,6): 
        #do something 

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

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

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

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

还是比这慢

def callsomething(x): 
    for t in (3+x,4+x,5+x,6+x): 
        #do something 

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

我知道 python 中的全局 var 访问会减慢程序速度,但它与创建结构相比如何?

请您参考如下方法:

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

>>> 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         

在 set 中查找 x 应该更快,对吧?但是呃哦...

>>> 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       

set 是可变的,所以 Python 直到最近才进行这种优化。 Python3.3 认为把它做成 frozenset 是安全的

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          
>>>