文章目录
简述
练手的过程中时常会遇到些语法死角,都是小问题,翻一下手册立马就明白,不翻又不确定对不对。每遇到一个问题都要重新翻一次,其实经常会重复的查阅同一个语法点,查过用过之后就忘了,不回头看就丢了,下次遇到还要重新学一遍,影响效率。既然如此,那我每次查阅后记下来好了,再写一点自己扩展的心得,便于回顾复习。
本文用于记录编程过程中遇到、查阅过、明确过的语法死角,不定期增删改,纯属个人笔记本。
基础语法
@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
的作用是用来检查对象的标示符是否一致,也就是比较两个对象在内存中的地址是否一样,而 ==
是用来检查两个对象是否相等。
我们在检查 ais
b 的时候,其实相当于检查 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'