ckdk's blog

python learning

2018/03/13

知乎上看到几个题,发现自己掌握的不好,记录一下警示下自己。

Python函数参数默认值的陷阱

1
2
3
4
5
6
# 以下程序输出什么
def f(x=[]):
x.append(3)
print(len(x))
f()
f()
1
2
3
//结果
1
2

解释:
如果参数的默认值是一个不可变(Imuttable)数值,那么在函数体内如果修改了该参数,那么参数就会重新指向另一个新的不可变值。而如果参数默认值是与上述方法一样,是一个可变对象(Muttable),那么情况就比较糟糕了。所有函数体内对于该参数的修改,实际上都是对compile阶段就已经确定的那个对象的修改。

可变类型(Muttable):列表,字典
不可变类型(Imuttable):数字,字符串,元组

全局变量的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
x = 2
def f():
print(x)

def g():
print(x)
x = 3

def j():
global x
x = 3
print(x)

def h():
exec('x = 4')
print(x)



try:
f()
except:
print('Oops')
try:
g()
except:
print('Oops')
try:
j()
except:
print('Oops')
try:
h()
except:
print('Oops')
1
2
3
4
2
Oops
3
4

解释:
第一个try:函数内部可以访问全局变量。
第二个try:函数内部不能直接为全局变量赋值。
第三个try:使用global关键词,可以在函数内部访问并修改全局变量的值。
第四个try:可以看出exec的作用域是全局的,具体细节也不是很清楚。

python多继承顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class M(type):
def __init__(cls, name, bases, attrs, **kwargs):
super().__init__(name, bases, attrs, **kwargs)
def f(self):
try:
super(cls, self).f()
except AttributeError:
pass
print(name)
cls.f = f


class A(metaclass=M):
pass

class AA(A):
pass

class AAA(AA):
pass

class B(metaclass=M):
pass

class C(AAA, B, metaclass=M):
pass

C().f()
print(C.__mro__)
1
2
3
4
5
6
B 
A
AA
AAA
C
(<class '__main__.C'>, <class '__main__.AAA'>, <class '__main__.AA'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)

解释:
在python多继承中,如果每个类下有同名方法,那个调用的顺序是按照python的mro算法顺序来执行的,这里我们打印了C()的mro顺序 发现是 B, A, AA, AAA, C(对MRO算法有兴趣的可以自己去查阅相关资料). 在f方法里,会调用父类的f方法,因此会层层调用每个类的f方法,在递归里,输出语句在递归调用之后,则最先运行的最后输出。因为不难得出结果就是mro的反顺序。

python类变量和实例变量

1
2
3
4
5
6
7
8
class A:
x = 2
def f(self, y):
print(A.x, self.x)
self.x = self.x + y
print(A.x, self.x)

A().f(3)
1
2
(2, 2)
(2, 5)

解释:
在python里,不管是实例还是类本身,都有一个自己的__dict__属性,它的值为一个字典, key为属性名,value为属性值。在访问一个实例的属性时,查找顺序为优先查找自己的__dict__属性,然后是类,然后是父类。
第一个print,此时实例本身并没有x属性,所以A.x和self.x都读到了类属性中的x,所以都是2
第二个print,在这之前,self.x即实例的x属性已经被创建且赋值,存在了自身的__dict__属性中。

CATALOG
  1. 1. Python函数参数默认值的陷阱
  2. 2. 全局变量的使用
  3. 3. python多继承顺序
  4. 4. python类变量和实例变量