关于传统除 / 和地板除 //
python2
在python2中,传统除会根据操作数来判断:
- 若操作数都为整数,则商舍去小数后的部分,返回整数
- 若操作数中有浮点数,则商为正确的值,返回浮点数
>>> 1 / 2
0
>>> 1 / 2.0
0.5
若用地板除,则无论如何都舍去小数点后的部分,并根据操作数判断返回类型:
>>> 1 // 2
0
>>> 1 // 2.0
0.0
python3
在python3中,传统除不再根据操作数判断,而是直接执行精确除法:
>>> 1 / 2
0.5
>>> 1 / 2.0
0.5
地板除还是和python2一样
>>> 1 // 2
0
>>> 1 // 2.0
0.0
循环语句中的else子句
若循环后跟了else子句,则else子句中的部分在循环没有被break(即正常运行完)时执行:
test1.py
for i in range(3):
print(i)
else:
print("else")
λ python test1.py
0
1
2
else
test2.py
for i in range(3):
print(i)
if i == 2:
break
else:
print("else")
λ python test2.py
0
1
2
赋值/浅复制/深复制
python中的赋值相当于引用,变量更像是指针。如,a=1,创建了一个整数对象1,并且让a指向它;再赋值a=2,则另创建了一个整数对象2,让a指向它;再赋值b=a,则将b指向2这个对象:
>>> a = 1
>>> id(a)
1599559952
>>> a = 2
>>> id(a)
1599559968
>>> b = a
>>> id(b)
1599559968
此时赋值a=3,则b=2不变,因为a指向了另一个对象3,而b还是指向2:
>>> a = 3
>>> id(a)
1599559984
>>> b
2
>>> id(b)
1599559968
然而如果赋予的值是可变对象如列表时,情况又会有所不同:
>>> aa = [1, 2]
>>> bb = aa
>>> id(aa), id(bb)
(49214288, 49214288)
>>> aa.append(3)
>>> aa, bb, id(aa), id(bb)
([1, 2, 3], [1, 2, 3], 49214288, 49214288)
可以看到,当bb=aa时,若aa改变了,bb也跟着一起变了。这是因为aa.append(3)语句并没有创建一个新的列表对象让aa指向它,而是再原来的对象上添加元素,而此时bb也指向这个对象,因此bb的值也跟着变了。而之前a=2和b=2由于2是整数即不可变对象,另外赋值时会新创建对象。
如果要让bb不跟随aa变化,就不能使用aa.append(3)的方式,而应该采用aa = aa[:]或aa = aa.copy()的方式,这样会复制aa指向的内容创建一个新的对象再让aa指向它,再执行aa.append(3)将不会影响bb:
>>> aa, bb, id(aa), id(bb)
([1, 2, 3], [1, 2, 3], 49214288, 49214288)
>>> aa = aa.copy()
>>> aa, bb, id(aa), id(bb)
([1, 2, 3], [1, 2, 3], 49213688, 49214288)
>>> aa.append(3)
>>> aa, bb, id(aa), id(bb)
([1, 2, 3, 3], [1, 2, 3], 49213688, 49214288)
这种复制对象的方式叫做浅复制,因为它只能复制最外层的内容创建新的对象,而对于嵌套内的内容依然是指向关系:
>>> aaa = [1, [1, 2], 3]
>>> bbb = aaa.copy()
>>> aaa, bbb
([1, [1, 2], 3], [1, [1, 2], 3])
>>> aaa[0] = 4
>>> aaa[1][0] = 5
>>> aaa, bbb
([4, [5, 2], 3], [1, [5, 2], 3])
由上可知bbb的外层元素因为是copy的缘故不受aaa影响,可是bbb[1]还是与aaa[1]指向同一个列表对象。如果需要将嵌套内的元素全部复制则需要用到copy标准库的deepcopy方法:
>>> aaa = [1, [1, 2], 3]
>>> import copy
>>> bbb = copy.deepcopy(aaa)
>>> aaa, bbb
([1, [1, 2], 3], [1, [1, 2], 3])
>>> aaa[0] = 4
>>> aaa[1][0] = 5
>>> aaa, bbb
([4, [5, 2], 3], [1, [1, 2], 3])
这种将嵌套内元素全部复制的方法叫深复制
参数中的 * 和 ** 前缀
经常能看到这样的函数定义:func(*args, **kwargs)
其中*前缀表示遍历args的元素作为参数依次传递给函数:
>>> a = "123"
>>> b = (1, 2, 3)
>>> c = [1, 2, 3]
>>> d = {1: "11", 2: "22", 3: "33"}
>>> print(*a, *b, *c, *d)
1 2 3 1 2 3 1 2 3 1 2 3
而**前缀只跟字典类型,将字典中的key和value拿出来传递给函数:
>>> aa = {"a": "aa", "b": "bb"}
>>> def f(b, a):
... print("b: {}, a: {}".format(b, a))
...
>>> f(**aa)
b: bb, a: aa
其中的f(**aa)就相当于f(a=”aa”, b=”bb”)
迭代器
我们知道,像字符串,列表,字典等对象是可以用for来循环遍历的,然而我们自己建立一个普通的对象却不能用for遍历:
test.py
class A:
def __init__(self, data):
self.data = data
a = A("test")
for c in a:
print(a)
λ python test.py
Traceback (most recent call last):
File "test.py", line 15, in <module>
for c in a:
TypeError: 'A' object is not iterable
这是因为使用for时会默认调用iter()返回一个迭代器,迭代器包含next()函数来返回下一个元素。当迭代器中元素用尽后返回一个StopIteration异常告诉for循环该结束了:
>>> a = iter("123")
>>> next(a)
'1'
>>> next(a)
'2'
>>> next(a)
'3'
>>> next(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
所以如果要让我们自己的对象含有迭代器特性,可以通过定义__iter__()方法使对象可迭代,通过定义__next__()方法定义每次迭代返回的元素:
test.py
class A:
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index == len(self.data):
raise StopIteration
self.index += 1
return self.data[self.index-1]
a = A("test")
for c in a:
print(c)
λ python test.py
t
e
s
t
使用str.format()方法格式化字符串
虽然python支持使用C语言风格的格式化方式,如:
>>> print("%d is a integer" % 2)
2 is a integer
但是使用str.format()方法更强大便捷
普通情况下不用再指定需要代入的是什么类型,统一用 {} 就能搞定
>>> print("{}, {} and {}".format(1, '2', [3, 4, 5]))
1, 2 and [3, 4, 5]
如果想得到repr()的内容使用{!r}:
>>> print("{!r}".format("Wow!!"))
'Wow!!'
如果需要指定代入的参数,可以加上下标或者使用参数名:
>>> print("{2}, {0} and {1}".format(1, '2', {"w": 2}))
{'w': 2}, 1 and 2
>>> print("{a}, {c} and {b}".format(a=1, b='2', c={"w": 2}))
1, {'w': 2} and 2
>>>
可以获取参数的元素或属性:
>>> a = [1, 2, 3]
>>> b = {"aa": 11, "bb": 22}
>>> class C:
... value = 333
...
>>> c = C()
>>> print("{0[2]}, {1[aa]}, {2.value}".format(a, b, c))
3, 11, 333
对齐及填充:
>>> print("{:<10}o".format("left"))
left o
>>> print("o{:>10}".format("right"))
o right
>>> print("o{:^10}o".format("center"))
o center o
>>> print("o{:*^10}o".format("center"))
o**center**o
>>> print("o{:>^10}o".format("center"))
o>>center>>o
>>> print("o{:A^10}o".format("center"))
oAAcenterAAo
控制小数位数等:
>>> print("{:.3f}".format(1234.44444))
1234.444