python代码太长_我很长时间以来一直困惑的Python代码,那些,让,疑惑,许久

疑惑代码1

a, b = a[b] = {}, 5

print(a) # {5: ({...}, 5)}

print(b) # 5

疑惑点

a, b = a[b] = {}, 5的执行流程是怎样的?

为什么会出现{…}

结果是怎么来的

解决疑惑点

a, b = a[b] = {}, 5的执行流程是怎样的?

官方文档中关于赋值语句的形式:

(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]是从右往左开始赋值的

003128483d238adb4108357890bcfffe.png

但是真实输出的答案为:

7c97910af89fda39e81ea7fad15d9aa3.png

所以我们在进行另一个假设:lst=lst[len(lst):] = lst[len(lst):] = [x]是从左往右开始赋值的

16ecc50d5d5438b7f0c8149ec7579d9d.png

???为什么是[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)

5c0d87a945d1f2673bd59f136cd2b48b.png

通过上面的分析我们可以得到"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)

疑惑代码2

a=[1,2,3]

a+=[4,5,6]

a=a+[7,8,9]

print(a) //[1, 2, 3, 4, 5, 6, 7, 8, 9]

疑惑点

+和+=有什么区别

二者的效率一样吗

解决疑惑点

+和+=有什么区别

在python的内存机制中,当不可变对象改变了原有的值,其别名绑定到了新值上面,id肯定会改变

+和+=的区别可以从可变对象和不可变对象说起

对于+号操作,可变对象和不可变对象调用的都是__add__操作

对于+=号操作,可变对象调用__add__,不可变对象调用的是__iadd__(不可变对象没有__iadd__) __iadd__是原地修改

在列表中+号则是一个特例

因为python中列表使用+的时候,等价于list.extend(list2),所以列表的另一个操作数必须是列表

二者的效率一样吗

import timeit

print(timeit.timeit("a = a + b + c", setup="a='a'*10000;b='b'*10000;c='c'*10000", number=100))

print(timeit.timeit("a += b + c", setup="a='a'*10000;b='b'*10000;c='c'*10000", number=100))

6cce24dec3273b5947f70978b9a2e73e.png

可以看出+=的效率明显高于+,但是二者效率的比较还是存在质疑

我们先从其机械指令来看为什么?

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

741fe843bb2896f4068c4e66dfc782d8.png

二者唯一区别在于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内存分配开销

而且作者在莫论坛看到

37406e059bab0f12c5c4e54f41585748.png

所以a+=b和a=a+b在效率方面可能还是存在可变因素

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值