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)3Traceback (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 absprint 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+idef 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]]复制代码