官方文档中关于赋值语句的形式:
(target_list "=")+ (expression_list | yield_expression)个人翻译等式应该是这样: 目标列表=多个计算表达式列表 按照列表赋值的方式,则应该是表达式运算完后依次从左到右赋值给目标列表 现在知道了列表赋值从左到右,但是却不知道{},5是先赋值给a,b还是a[b] 我们可以通过下面这个案例来说明{},5到底先赋值给谁
lst=[] x=1 lst=lst[len(lst):] = lst[len(lst):] = [x] print(lst)我们这里可以先假设lst=lst[len(lst):] = lst[len(lst):] = [x]是从右往左开始赋值的 但是真实输出的答案为: 所以我们在进行另一个假设:lst=lst[len(lst):] = lst[len(lst):] = [x]是从左往右开始赋值的 ???为什么是[1,1,1],那[1,1,1,1]到底怎么来的,反复看上面的图,和赋值表达式,唯一能证实的就是
S=[x] S1=S S2=S这样运算才能获取[1,1,1,1],从而证实了python中如果存在多个目标时,会先将运算表达式赋值给最左边的目标,然后得到的结果分别赋值给其他目标
a,b=c=d=1,2 print(a,b) print(c) print(d)通过上面的分析我们可以得到 "a, b = a[b] = {}, 5的执行流程是怎样的?"的答案了
1.a={},b=5 2.a[b]=a,b**现在我们已经知道a[b]=a,b 那为什么会出现{…},{…}这个又是什么东西? 可以简单看个小案例
lst=lst[0]=[0] print(lst) //[[...]]其实[[…]]指的是与 lst 引用了相同的对象。**及lst[0] is lst,当引用的相同的对象时,Python就会打印出[…] 由与a[b]=a,b,a[b]中的a和a,b中的a是相同的对象,所以则会导致出现{…},这种现象
解决上面二个问题这个问题就很容易解决了
1.a,b={},5 2.a={},b=5 3.a[b]={},5 4.a[5]=({....},5)在python的内存机制中,当不可变对象改变了原有的值,其别名绑定到了新值上面,id肯定会改变 +和+=的区别可以从可变对象和不可变对象说起 对于+号操作,可变对象和不可变对象调用的都是__add__操作 对于+=号操作,可变对象调用__add__,不可变对象调用的是__iadd__(不可变对象没有__iadd__) __iadd__是原地修改 在列表中+号则是一个特例 因为python中列表使用+的时候,等价于list.extend(list2),所以列表的另一个操作数必须是列表
可以看出+=的效率明显高于+,但是二者效率的比较还是存在质疑 我们先从其机械指令来看为什么?
import dis def fun(): a = 1 b = 2 a = a + b a += b dis.dis(fun)结果:
3 0 LOAD_CONST 1 (1) 2 STORE_FAST 0 (a) 4 4 LOAD_CONST 2 (2) 6 STORE_FAST 1 (b) 5 8 LOAD_FAST 0 (a) 10 LOAD_FAST 1 (b) 12 BINARY_ADD 14 STORE_FAST 0 (a) 6 16 LOAD_FAST 0 (a) 18 LOAD_FAST 1 (b) 20 INPLACE_ADD 22 STORE_FAST 0 (a) 24 LOAD_CONST 0 (None) 26 RETURN_VALUE二者唯一区别在于BINARY_ADD与INPLACE_ADD,从现在看出+=的效率高一些只能说明INPLACE_ADD效率总是不低于BINARY_ADD,但是未必a+=b 比 a=a+b快 1.JIT影响,很可能二者最终是相同的机器指令,就是一模一样 2.例子中int是immutable, INPLACE_ADD未必真正意义的inplace,否则就破坏了int immutable原则,至少能确定不论哪种方式加,每加一次a的内存地址变一次,a新分配地址是整个过程最大的开销(加逻辑计算可以忽略),在大量执行的情况下,二者应该开销基本一致,都是a内存分配开销 而且作者在莫论坛看到 所以a+=b和a=a+b在效率方面可能还是存在可变因素