变量与对象
- 变量不是盒子,变量是便利贴:把变量s分配给对象xxx
==比较两个对象的值(存储的数据),is比较对象的标识(identity)is判断是否是同一个对象,不能重载;==可以调用类型定义的相等性比较。选择哪一个取决于语义,不应只看速度。- 判断
None用is None。== None可能触发自定义__eq__,因此并不保证同样的结果。
- 浅拷贝创建最外层容器,但其中的项仍然引用原对象。如果有可变项,修改可能影响两边;需要独立的嵌套对象时,可以考虑深拷贝,并留意它是否复制了本来希望共享的数据。
- Python唯一支持的参数传递模式是共享传参(call by sharing),由此函数可能会修改作为参数传入的可变对象,而不改变其标识(it cannot altogether replace an object with another)
默认参数与共享传参
"""
>>> bus1 = HauntedBus(['Alice', 'Bill'])
>>> bus1.passengers
['Alice', 'Bill']
>>> bus1.pick('Charlie')
>>> bus1.drop('Alice')
>>> bus1.passengers
['Bill', 'Charlie']
>>> bus2 = HauntedBus()
>>> bus2.pick('Carrie')
>>> bus2.passengers
['Carrie']
>>> bus3 = HauntedBus()
>>> bus3.passengers
['Carrie']
>>> bus3.pick('Dave')
>>> bus2.passengers
['Carrie', 'Dave']
>>> bus2.passengers is bus3.passengers
True
>>> bus1.passengers
['Bill', 'Charlie']
>>> dir(HauntedBus.__init__) # doctest: +ELLIPSIS
['__annotations__', '__call__', ..., '__defaults__', ...]
>>> HauntedBus.__init__.__defaults__
(['Carrie', 'Dave'],)
>>> HauntedBus.__init__.__defaults__[0] is bus2.passengers
True
"""
class HauntedBus:
"""A bus model haunted by ghost passengers"""
def __init__(self, passengers=[]):
self.passengers = passengers
def pick(self, name):
self.passengers.append(name)
def drop(self, name):
self.passengers.remove(name)
- 创建对象时没有传入passengers,导致对象去引用函数定义时求值一次的默认列表,变量成为参数默认值的别名
del 与垃圾回收
del删除的是绑定或容器中的引用,不等同于直接销毁对象。CPython 使用引用计数,并配合循环垃圾回收;Python 语言不保证不可达对象立即被销毁,其他实现也可能使用不同策略。- 可以通过
weakref.finalize注册回调函数,在销毁对象时调用- finalizer 对目标对象使用弱引用;回调及其参数不要直接或间接持有该对象,否则会阻止回收
- 可以通过
>>> import weakref
>>> s1 = {1, 2, 3}
>>> s2 = s1
>>> def bye():
... print('...like tears in the rain.')
...
>>> ender = weakref.finalize(s1, bye)
>>> ender.alive
True
>>> del s1
>>> ender.alive
True
>>> s2 = 'spam'
...like tears in the rain.
>>> ender.alive
False
变量作用域
- 变量作用域
- Python does not require you to declare variables, but assumes that a variable assigned in the body of a function is local. This is much better than the behavior of JavaScript, which does not require variable declarations either, but if you do forget to declare that a variable is local (with var), you may clobber a global variable without knowing.
- local, global, nonlocal
- When a function is defined, the Python bytecode compiler determines how to fetch a variable x that appears in it, based on these rules:
- If there is a global x declaration, x comes from and is assigned to the x global variable module
- If there is a nonlocal x declaration, x comes from and is assigned to the x local variable of the nearest surrounding function where x is defined.
- If x is a parameter or is assigned a value in the function body, then x is the local variable.
- If x is referenced but is not assigned and is not a parameter:
- x will be looked up in the local scopes of the surrounding function bodies (nonlocal scopes).
- If not found in surrounding scopes, it will be read from the module global scope.
- If not found in the global scope, it will be read from
__builtins__.__dict__.
以下反汇编保留旧版 CPython 的输出,指令名称与偏移会随版本变化。
>>> def f1(a):
... print(a)
... print(b)
...
>>> f1(3)
3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in f1
NameError: name 'b' is not defined
>>> b = 6
>>> f1(3)
3
6
>>> def f2(a):
... print(a)
... print(b)
... b = 9
...
>>> f2(3)
3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in f2
UnboundLocalError: local variable 'b' referenced before assignment
>>> from dis import dis
>>> dis(f1)
2 0 LOAD_GLOBAL 0 (print) <1>
3 LOAD_FAST 0 (a) <2>
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
9 POP_TOP
3 10 LOAD_GLOBAL 0 (print)
13 LOAD_GLOBAL 1 (b) <3>
16 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
19 POP_TOP
20 LOAD_CONST 0 (None)
23 RETURN_VALUE
>>> dis(f2)
2 0 LOAD_GLOBAL 0 (print)
3 LOAD_FAST 0 (a)
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
9 POP_TOP
3 10 LOAD_GLOBAL 0 (print)
13 LOAD_FAST 1 (b) <1>
16 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
19 POP_TOP
4 20 LOAD_CONST 1 (9)
23 STORE_FAST 1 (b)
26 LOAD_CONST 0 (None)
29 RETURN_VALUE
