1.一个关于+=的谜题
#增量赋值:a+=b会调用__iadd_方法(就地加法),a=a+b会调用__add__方法
>>> t=(1,2,[2,3])
>>> t[2]+=[4,5]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t
(1, 2, [2, 3, 4, 5])
'''增量赋值不是原子操作
将t[2]+=[4,5]分解为2步:
1⃣️temp=[2,3],temp+=[4,5],可变对象可以执行此操作
2⃣️t[2]=temp,由于t为元组,不可变对象所以会报错。
'''解决办法
>>> t[2].extend([4,5])
>>> t
(1, 2, [2, 3, 4, 5])
>>> t=(1,2,[2,3])
>>> t[2].append([4,5])
>>> t
(1, 2, [2, 3, [4, 5]])
增量赋值运算符+=、*=。对于增量加法会先去调用__iadd__,若没有该方法则调用__add__。str不可变对象是例外,因为对字符串做+=太普遍,所以Cpython对它做了优化,为str初始化内存的时候,程序会为它留出额外的可扩展空间,因此进行增量操作的时候,并不会涉及复制原有字符 串到新位置这类操作。
2.变量作用域
>>> b=6
>>> def f1(a):
... print a
... print b
... b=9
...
>>> f1(3)
3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in f1
UnboundLocalError: local variable 'b' referenced before assignment
-------------------------------------------
为什么会报错,而不是正常输出3 6
python在编译函数定义体时,由于在函数体中b被赋值,所以被判断为局部变量。在赋值之前引用变量b,所以会报错。如果在函数体内没有给b赋值,则b被视为全局变量。
3.避免可变对象作为参数默认值
# -*- coding: utf-8 -*-
def ad(nam,abs=[]):
if abs==None:
abs=[]
abs.append(nam)
return abs
print ad('xxx')
print ad('cx')
-----------------------out
['xxx']
['xxx', 'cx'] #期待输出['cx']
第一个输出会和第二个输出共享同一个列表。要想得到期望的结果,将参数abs默认为None
4.推导式
def demo():
for i in range(4):
yield i
g=demo()
g1=(i for i in g)
g2=(i for i in g1)
print(list(g1))
print(list(g2))
------------------out----why
[0, 1, 2, 3]
[]
----------------分割线
def add(n,i):
return n+i
def test():
for i in range(2):
yield i
g=test()
for n in [1,2]:
g=(add(n,i) for i in g)
print(list(g))
----------out------why
[4,5]
-----------------------------分割线 (延迟绑定)
def create_multipliers():
return [lambda x : i * x for i in range(5)]
for multiplier in create_multipliers():
print(multiplier(2))
---------------------out
实际:8 8 8 8 8
期望:0 2 4 6 8
--------------------解决
def create_multipliers():
return [lambda x,i=i: i * x for i in range(5)]
for multiplier in create_multipliers():
print(multiplier(2))
5. 数据叠加
>>> lists = [[]] * 3
>>> lists
[[], [], []]
>>> lists[0].append(3)
>>> lists
[[3], [3], [3]]
这样叠加出来的数据其实是对数据的多次引用,并不是拷贝
>>> lists = [[] for i in range(3)]
>>> lists[0].append(3)
>>> lists[1].append(5)
>>> lists[2].append(7)
>>> lists
[[3], [5], [7]]