python 零散记录(七)(下) 新式类 旧式类 多继承 mro 类属性 对象属性
python新式类 旧式类:
python2.2之前的类称为旧式类,之后的为新式类。在各自版本中默认声明的类就是各自的新式类或旧式类,但在2.2中声明新式类要手动标明:
这是旧式类为了声明为新式类的方式
class A: #手写把元类 metaclass 给 type __metaclass__ = type pass #或者这样写,效果是一样的 class B(object): #手动指定继承自object类,object类是最初的类,一切类都是object的子类,是祖宗 pass
对于class A的写法,我的理解是:所谓一切皆对象,类也是对象!类的实例是对象,元类的实例是类...只能这么理解了。类的上头就是元类__metaclass__,然后给元类手动给type。
python多继承,mro:
我并不喜欢这种乱伦式的继承...而且有难写,更难调试。说说自己的理解吧:
1. 当父类们来自不同祖先,并且有同名方法时,顺序在前的父亲会覆盖后面父亲的方法,这个对于新式类旧式类都适用。
2. 当父亲们继承自同一个祖先,新式类的处理是按照宽度优先搜索,旧式类按照深度优先搜索
对于第 1 种,父亲们来自不同祖先,这个新式旧式都适用:
class A: def f(self): print 'A' class B: def f(self): print 'B' class AB(A,B): pass ab = AB() ab.f() #这里调用ab.f()打印的结果跟AB类的父类继承顺序有关,顺序在前的父类方法会覆盖后面的父类方法 #这里打印出的是 :A
对于第2种,继承自相同的祖先时:
class A(object): #声明新式类 def f(self): print 'A' class B: __metaclass__ = type #另一种新式类声明 def f(self): print 'B' class BB(B): #BB继承自B,B已经是新式类了,那么BB不用再声明就自然是新式类 #BB重写了B的f方法 def f(self): print 'BB' class BBB(B): #BBB没有重写B的f方法,所以用的还是B的f方法 pass class BBBB(B): #BBBB也重写B的f方法: def f(self): print 'BBBB'
class Test1(BB,BBB): pass t1 = Test1() t1.f() #这里会打印BB class Test2(BB,BBBB): #BB,BBBB都是直接继承自B的,也都重写了B的f方法 pass t2 = Test2() t2.f() #这里会打印BB,因为BB在前,说说咋回事:
#首先这里面的都是新式类,Test继承的父亲BB,BBB都来自同一个祖先B,那么开始了: """ 1 新式类按照宽度优先搜索,所以继承的先后顺序无关结果 2 新式类有一个mro(method resolution order 方法判定次序)的东西,可以类名.__mro__或类名.mro()查看。旧式类是没有的,写的话会报错。 3 具体继承哪个方法:看哪个方法是最新(英文的lasted)重写父类的,就用哪个。如果是统一级别的,也就是同一层级重写的,那就按照先后次序选择 比如Test1:
BB继承B后马上就重写了f方法,而BBB继承B后没有重写f方法而是完全继承自B。这时BB和BBB是同一级别的,都是B的儿子们。 相比较的话,自然可以看出是BB最新重写了f,那f方法就继承BB的。
在比如第二个例子Test2:
BB和BBBB都继承自B,也都重写了B的f方法,有都处于同一级别,这时就看谁在前了,会继承前面的类。
这一条也说明了,继承自不同祖先的情况下,父亲之间都是同辈,没有长幼之分,都是统一级别,所以按照次序选择前面的。 """
getattr setattr hasattr:
hasattr(a, '属性名/方法名') 返回True or False
setattr(a, '属性名/方法名', 属性/方法的返回值)
getattr(a, '属性名/方法名', 缺省值)
类属性 对象属性:
class C: #这里的是类属性 a = 0 def __init__(self): #这里的是对象的属性,对象自己用自己的 pass
当对象中没有指定a的时候,在实例中访问a实际上是访问类属性a
而一旦该实例访问了该属性,那么就会自己保留一份a的拷贝作为自己的对象属性,从此这个对象属性就与类属性无关了,虽然都叫a。也就是说在此之后类和实例两方对各自的a操作互不影响。
但是如果这个属性是可变的,比如list或dict,那么上面一条互不影响就不成立了。是会影响的
class A: i = 0 #不可变的整数 l = [] #可变的列表 a1 = A() a2 = A() #先看看有什么 print A.i, a1.i, a2.i #都是 0 #类直接搞i A.i = 10 print A.i, a1.i, a2.i #三个都变成了10,因为这时都用的是类属性 #这时用对象 a1 搞一下类属性 i a1.i = 1 print A.i, a1.i, a2.i #只用a1的i属性变了,其他的没变还是10 #再用类直接搞 A.i += 1 print A.i, a1.i, a2.i #只有A和a2的i属性变了,说明a1经过上面独立搞i属性之后,已经把i拷贝到自己那,以后操作都与其他人无关了。 #现在看看搞一搞可变对象 列表 a1.l.append('a1') print A.l, a1.l, a2.l #都变了 a2.l.append('a2') print A.l, a1.l, a2.l #又都变了,所以可变对象就不是拷贝完了自己搞,是大伙一起搞的