【python】语法死角

本文记录了Python编程中常见的语法难点,包括dis模块、is与==的区别、二维列表生成、str.format()的使用、list.sort()排序、lambda匿名函数、装饰器的应用、reduce函数、while循环break与else的关系,以及面向对象编程的细节。通过实例解析,帮助开发者理解和避免这些语法陷阱,提升编程效率。
摘要由CSDN通过智能技术生成


简述

练手的过程中时常会遇到些语法死角,都是小问题,翻一下手册立马就明白,不翻又不确定对不对。每遇到一个问题都要重新翻一次,其实经常会重复的查阅同一个语法点,查过用过之后就忘了,不回头看就丢了,下次遇到还要重新学一遍,影响效率。既然如此,那我每次查阅后记下来好了,再写一点自己扩展的心得,便于回顾复习。
本文用于记录编程过程中遇到、查阅过、明确过的语法死角,不定期增删改,纯属个人笔记本。


基础语法


@dis——反汇编工具

dis是个反汇编工具,将Python代码翻译成字节码指令。

import dis
def swep1():
    x = 5
    y = 6
    x, y = y, x

def swep2():
    x = 5
    y = 6
    temp = x
    x = y
    y = temp
    
if __name__ == "__main__":
    print("============swap1==============")
    print(dis.dis(swep1))
    print("============swap2==============")
    print(dis.dis(swep2))

输出如下

============swap1==============
  6           0 LOAD_CONST               1 (5)
              3 STORE_FAST               0 (x)

  7           6 LOAD_CONST               2 (6)
              9 STORE_FAST               1 (y)

  8          12 LOAD_FAST                1 (y)
             15 LOAD_FAST                0 (x)
             18 ROT_TWO
             19 STORE_FAST               0 (x)
             22 STORE_FAST               1 (y)
             25 LOAD_CONST               0 (None)
             28 RETURN_VALUE
None
============swap2==============
 12           0 LOAD_CONST               1 (5)
              3 STORE_FAST               0 (x)

 13           6 LOAD_CONST               2 (6)
              9 STORE_FAST               1 (y)

 14          12 LOAD_FAST                0 (x)
             15 STORE_FAST               2 (temp)

 15          18 LOAD_FAST                1 (y)
             21 STORE_FAST               0 (x)

 16          24 LOAD_FAST                2 (temp)
             27 STORE_FAST               1 (y)
             30 LOAD_CONST               0 (None)
             33 RETURN_VALUE
None

通过字节码可以看到,swap1和swap2最大的区别在于,swap1中通过ROT_TWO交换栈顶的两个元素实现x和y值的互换,swap2中引入了tmp变量,多了一次LOAD_FAST, STORE_FAST的操作。执行一个ROT_TWO指令比执行一个LOAD_FAST+STORE_FAST的指令快,这也是为什么swap1比swap2性能更好的原因。

通过使用dis.dis()可较便捷的看出汇编指令,便于衡量和评估程序执行的效率。注意使用前需要先import dis


@is & ==

is==的区别:
官方文档中说is表示的是对象标示符(object identity),而 == 表示的是相等(equality)。
is 的作用是用来检查对象的标示符是否一致,也就是比较两个对象在内存中的地址是否一样,而 ==是用来检查两个对象是否相等。

我们在检查 aisb 的时候,其实相当于检查 id(a) == id(b)。而检查 a==b 的时候,实际是调用了对象 a 的 eq() 方法,a ==b 相当于 a.eq(b)。

一般情况下,如果 ais b 返回True的话,即 a 和 b 指向同一块内存地址的话,a ==b 也返回True,即 a 和 b 的值也相等。

a = "hello"
b = "hello"
print( a == b )	#output: True
print( a is b )	#output: True

a = "hello world"
b = "hello world"
print( a == b )	#output: True
print( a is b )	#output: False

a = [ 1, 2, 3 ]
b = [ 1, 2, 3 ]
print( a == b )	#output: True
print( a is b )	#output: False

a = [ 1, 2, 3 ]
b = a
print( a == b )	#output: True
print( a is b )	#output: True

打印出 id(a) 和 id(b) 后就很清楚了。只要 a 和 b 的值(value)相等,a == b 就会返回True,而只有 id(a) 和 id(b) 相等时,a is b 才返回 True。
这里还有一个问题,为什么 a 和 b 都是 “hello” 的时候,a is b 返回True,而 a 和 b都是 “hello world” 的时候,a is b 返回False呢?
这是因为前一种情况下Python的字符串驻留机制起了作用。对于较小的字符串,为了提高系统性能Python会保留其值的一个副本,当创建新的字符串的时候直接指向该副本即可。所以 “hello” 在内存中只有一个副本,a 和 b 的 id 值相同,而 “hello world” 是长字符串,不驻留内存,Python中各自创建了对象来表示 a 和 b,所以他们的值相同但 id 值不同。
is 是检查两个对象是否指向同一块内存空间,而 == 是检查他们的值是否相等.


@生成二维列表

创建N行0列的列表有多种方式:
1.首先想到的是for循环,比较无脑:

N = 4
li = []
for i in range(N):
    li.append([])

2.for循环不易读,改成列表生成式:

N = 4
li=[[] for i in range(N)]

3.上面两种都要用到for,还是感觉怪麻烦的,试试乘号,于是遇到了坑!如下:

#先生成一个值全为0的2x3的二维列表
N = 4
li = [[]] * N
print("list =", li)
#再给第一行的元素append一个数233
li[1].append(233)
print("list =", li)

运行以上代码将输出:

list = [[], [], [], []]
list = [[233], [233], [233], [233]]

官方文档中给出的说明如下:

Note also that the copies are shallow; nested structures are not copied. This often haunts new Python programmers; consider:

>>> lists = [[]] * 3
>>> lists
[[], [], []]
>>> lists[0].append(3)
>>> lists
[[3], [3], [3]]

What has happened is that [[]] is a one-element list containing an empty list, so all three elements of [[]] * 3 are (pointers to) this single empty list. Modifying any of the elements of lists modifies this single list. You can create a list of different lists this way:

>>>
>>> lists = [[] for i in range(3)]
>>> lists[0].append(3)
>>> lists[1].append(5)
>>> lists[2].append(7)
>>> lists
[[3], [5], [7]]

也就是说*matrix=[array]3操作中,只是创建3个指向array的引用,所以一旦array改变,matrix中3个list也会随之改变,因此使用简单的*来实现生成多行列表是不现实的,官方文档还是让用列表生成式实现。

由此引发了对深拷贝和浅拷贝的思考。


总结生成二维列表的办法:
1.直接生成
----简单粗暴,元素较多的场合不适用,不易读,一般不用。
test = [0, 0, 0], [0, 0, 0], [0, 0, 0]]
2.列表生成器
----每行、每列元素的值需有一定规律。

#创建一个0*0的二维列表:
list = [ [0 for col in range(0)] for row in range(0)]

#创建一个5*5,每个数都初始化为0的二维列表:
list = [ [0 for col in range(5)] for row in range(5)]

3.用for循环依次遍历
----遍历列表中的每一个元素赋值,各元素值之间可以没有规律。效率低。

#生成列表:[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
inner_list = []
outer_list = []
for i in range(1,10):
    inner_list.append(i)
    if i % 3 == 0:
        outer_list.append(inner_list)
        inner_list = []

@str.format()----格式化字符串

通过{}和:替代C的%。

  • format()函数可接受不限个数个参数:
    {}中为空时,按顺序依次映射format的参数;
    {}中可填序号(从0开始),按序号在format参数中映射;
    {}中可对format参数精确访问,包括列表内的元素等;
    {0[2]['a']}表示找到format第一个参数,此参数是一个列表,找到列表的第3个元素,此元素是个字典,在字典中访问label为’a’的项的值,该键值替换{};

  • 格式限定
    {}中用分隔开,前面指明位置,用来索引format中的参数值,后面表示格式,有两种格式:1️⃣填充与对齐2️⃣进制与精度。

[1].填充与对齐
格式如下:
{【参数索引】:【填充物】【^居中 <左对齐 >右对齐】【字符串长度】}
举个栗子?
'{0:*^12}'.format(3.14,23333,'feawr4esr')表示字符串总长度为12,把3.14居中的填入该字符串中,其他位置用星号*填充,所以打出来就是****3.14****

[2].进制与精度与千分位

{:b}二进制
{:d}十进制
{:o}八进制
{:x}十六进制

float数的精度:

{x:.nf}表示小数点后保留n位显示。

{:,}表示千分位分隔符,每三位数加一个逗号,举个栗子?
{:,}.format(1234567890)打出来就是1,234,567,890

PS:填充对齐和进制、千分位不能同时用,精度可以加在字符串长度后面。

>>> s='{0:*^12.3f}'.format(3.1423333,'sdfdgfdf')
>>> print(s)
***3.142****

@list.sort()----列表排序

描述
sort() 函数用于对原列表进行排序,如果指定参数,则使用比较函数指定的比较函数。

语法
sort()方法语法:
list.sort(cmp=None, key=None, reverse=False)

参数

  • cmp – 可选参数, 如果指定了该参数会使用该参数的方法进行排序。

  • key – 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。常与lambda函数配合使用。li.sort(key=lambda x:x[1])

  • reverse – 排序规则,reverse = True 降序, reverse = False 升序(默认)。

实例

li=[3,9,-25,17,0,-7]
#由小到大排序
li.sort()
print(li)
#output:[-25, -7, 0, 3, 9, 17]
#由大到小排序
li.sort(reverse=True)
print(li)
#output:[17, 9, 3, 0, -7, -25]

#按元素的绝对值有小到大排序
>>> li.sort(key=lambda x:abs(x))
>>> print(li)
#output:[0, 3, -7, 9, 17, -25]

>>> li=[['asd',12,'1234qwer'],['abc',18,79],[23,9,'hehehehe']]
#按元素的第二个子元素排序
>>> li.sort(key=lambda x:x[1])
>>> print(li)
#output:[[23, 9, 'hehehehe'], ['asd', 12, '1234qwer'], ['abc', 18, 79]]

>>> li=[{'name':'Tom','age':18,'class':3},{'name':'Tom','age':22,'class':1},
{'name':'Tom','age'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值