python函数中的硬编码变量

Art*_*r.V 5 python constants python-internals

有时,某些值/字符串在函数中是硬编码的.例如,在以下函数中,我定义了一个"常量"比较字符串并检查它.

def foo(s):
    c_string = "hello"
    if s == c_string:
        return True
    return False
Run Code Online (Sandbox Code Playgroud)

没有讨论太多关于为什么它的坏做到这一点,以及应如何在外部范围进行定义,我想知道幕后发生了什么时,它这样定义的.
是否每次调用都会创建字符串?
如果不是字符串,"hello"那么它就是列表:( [1,2,3]或者如果重要的话,列表中包含可变内容的列表)会发生同样的情况吗?

Mar*_*ers 11

因为字符串是不可变的(和元组一样),所以它与函数的字节码对象一起存储.它由一个非常简单和快速的索引查找加载.这实际上比全局查找更快.

您可以使用以下dis.dis()函数在字节码的反汇编中看到这一点:

>>> import dis
>>> def foo(s):
...     c_string = "hello"
...     if s == c_string:
...         return True
...     return False
... 
>>> dis.dis(foo)
  2           0 LOAD_CONST               1 ('hello')
              3 STORE_FAST               1 (c_string)

  3           6 LOAD_FAST                0 (s)
              9 LOAD_FAST                1 (c_string)
             12 COMPARE_OP               2 (==)
             15 POP_JUMP_IF_FALSE       22

  4          18 LOAD_GLOBAL              0 (True)
             21 RETURN_VALUE        

  5     >>   22 LOAD_GLOBAL              1 (False)
             25 RETURN_VALUE        
>>> foo.__code__.co_consts
(None, 'hello')
Run Code Online (Sandbox Code Playgroud)

LOAD_CONST操作码装入从字符串对象co_costs即该函数的代码对象的一部分阵列; 引用被推到堆栈的顶部.所述STORE_FAST操作码取从堆栈的顶部的参考,并将其存储当地人阵列,再次以非常简单和快速的操作英寸

对于可变文字({..},[..]),特殊操作码构建对象,内容仍然尽可能地被视为常量(更复杂的结构只遵循相同的构建块):

>>> def bar(): return ['spam', 'eggs']
... 
>>> dis.dis(bar)
  1           0 LOAD_CONST               1 ('spam')
              3 LOAD_CONST               2 ('eggs')
              6 BUILD_LIST               2
              9 RETURN_VALUE        
Run Code Online (Sandbox Code Playgroud)

BUILD_LIST调用使用两个常量字符串对象创建新的列表对象.

有趣的事实:如果你使用列表对象进行成员资格测试(something in ['option1', 'option2', 'option3']Python知道列表对象永远不会被改变,并且会在编译时将它转换为元组(所谓的窥孔优化).这同样适用于集合literal,它被转换为一个frozenset()对象,但仅限于Python 3.2及更新版本.在'if'子句中使用'in'时,请参阅元组或列表?

请注意,您的示例函数使用的是非常冗长的布尔值; 你可以使用:

def foo(s):
    c_string = "hello"
    return s == c_string
Run Code Online (Sandbox Code Playgroud)

为了完全相同的结果,避免LOAD_GLOBALPython 2中的调用(Python 3 TrueFalse关键字,所以值也可以存储为常量).