Python局部变量初始化

Python local variable initialization

我对Python比较陌生,我想知道局部变量是如何工作的。让我们从一个简单方法的例子开始:

1
2
3
def do_sth():
    local_dict = { 'a': 1, 'b': 2, 'c': 3, ... }
    ...

让我们假设局部变量像常量变量一样使用。问题是:每次调用doesh()或只创建一次,它都会被创建,并保存在doesh()内部的某个地方?


您可以查看解释器使用dis模块执行的操作:

1
2
3
4
5
6
7
def do_sth():
    d = {'a':2, 'b':3}
    print(id(d))


import dis
dis.dis(do_sth)

将打印

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  2           0 BUILD_MAP                2
              3 LOAD_CONST               1 (2)
              6 LOAD_CONST               2 ('a')
              9 STORE_MAP          
             10 LOAD_CONST               3 (3)
             13 LOAD_CONST               4 ('b')
             16 STORE_MAP          
             17 STORE_FAST               0 (d)

  3          20 LOAD_GLOBAL              0 (id)
             23 LOAD_FAST                0 (d)
             26 CALL_FUNCTION            1
             29 PRINT_ITEM          
             30 PRINT_NEWLINE      
             31 LOAD_CONST               0 (None)
             34 RETURN_VALUE

这表明每次调用函数时,解释器都在重建值。


每次调用do_sth()时。这很重要,因为它允许您在函数内部修改local_dict,并且不会对其他调用产生任何影响。解释器不够聪明,看你是否不会改变它,特别是因为python非常动态,所以有一些非常迂回的方法可以让它改变。

以下是您如何向自己证明字典不断被重新创建的方法:

1
2
3
4
5
6
7
8
9
def print_3():
    print(3)

def do_sth():
    local_dict = {'a': print_3()}

do_sth()
do_sth()
do_sth()

这张照片3…3次。

我认为全局变量对于优化这一点是可以的,但是如果你真的想要,这一点如何:

1
2
3
4
def do_sth():
    return do_sth.local_dict

do_sth.local_dict = {'a': print_3()}

从技术上讲,这仍然可以被每个人访问,但它更清楚它属于什么。


很容易与is操作员联系:

1
2
3
4
5
def test():
    return {'a': 1, 'b': 2, 'c': 3}

>>> test() is test() #did both produce the same object in memory space?
False

这对于可变对象很有意义,或者可变的默认参数陷阱会无处不在。

但是,存在存储为常量的值,可以使用dis看到这些值,因为常量是用LOAD_CONST字节代码加载的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> dis.dis(lambda:1)
  1           0 LOAD_CONST               1 (1)
              3 RETURN_VALUE
>>> dis.dis(lambda:(1,True, 10*1000,"a"))
  1           0 LOAD_CONST               7 ((1, True, 10000, 'a'))
              3 RETURN_VALUE
>>> dis.dis(lambda:[1,2,3]) #list is mutable
  1           0 LOAD_CONST               1 (1)
              3 LOAD_CONST               2 (2)
              6 LOAD_CONST               3 (3)
              9 BUILD_LIST               3
             12 RETURN_VALUE
>>> dis.dis(lambda:{"a":1}) #dict is also mutable
  1           0 LOAD_CONST               1 ('a')
              3 LOAD_CONST               2 (1)
              6 BUILD_MAP                1
              9 RETURN_VALUE

局部变量总是在函数范围内创建。一旦程序计数器退出函数(局部变量的作用域),垃圾收集器就会收集这些数据。

1
2
3
4
5
6
7
8
9
10
global_dict = []

def do_sth():
    local_dict = { 'a': 1, 'b': 2, 'c': 3, ... }
    ...

def do_other_task():
   #local_dict not visible. It's outside of scope.
   global global_dict # fetch memory address of previously declared global_dict
   global_dict = { 'a': 1, 'b': 2, 'c': 3, ... }

其他答案都是正确的,我只想补充一下。

在这种情况下,我宁愿这样做:

1
2
3
4
5
constant_dict = { 'a': 1, 'b': 2, 'c': 3, ... }
def do_sth():
    # do something reading constant_dict

do_sth()

或者更不可取:

1
2
3
4
def do_sth(local_dict = { 'a': 1, 'b': 2, 'c': 3, ... }):
    # do something reading local_dict

do_sth()

在这两种情况下,python都不必为变量重新分配内存,因为它是在解释器读取python文件时声明和分配的。

如果我错了就纠正我。