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    #又都变了,所以可变对象就不是拷贝完了自己搞,是大伙一起搞的

 

 

 

posted on 2013-09-04 22:01  李皮筋  阅读(651)  评论(0编辑  收藏  举报

导航