python渐进-类3

13.6 实例化以及__init__函数

类在进行实例化的时候,python会自动生成一个实例对象,然后调用实例的__init__()方法进行本实例的初始化工作。

在定义类的时候,可以自行创建一个__init__()函数,接收初始化的参数,进行不同实例的数据初始化。

下面的例子中,__init__方法接收一个步长参数。类实例化时,也需要传入一个步长实参。

class IncClass: def __init__(self,n): self.n=n print('init step '+str(self.n)) def Incn(self,x): return x+self.nic9=IncClass(9)print(ic9.Incn(5))ic3=IncClass(3)print(ic3.Incn(3))

以上代码中有两个实例,一个是ic9,步长为9,每次相加会+9;另外一个ic3,步长为3,每次相加会+3。运行结果为:

init step 914init step 36

13.7 类的继承

使用class derivedclass(baseclass):可以声明一个继承类。其中derivedclass是继承的类,而baseclass是基类。

derivedclass会继承baseclass的所有类变量和所有的类函数;如果觉得baseclass的某个类函数不符合要求,derivedclass可以重写它;同时derivedclass可以定义自己独有的类变量和类函数。

以下的代码就演示了继承,重写,个性化的过程:

class human(): def __init__(self,name): self.name=name def Washhand(self): print(self.name+' wash hand')class boy(human): def Washhand(self): print(self.name+' pretent to wash hand') def Play(self): self.Washhand() print(self.name+' play car')class girl(human): def Play(self): self.Washhand() print(self.name+' play doll')

以上的代码中human类为基类。而boy和girl类都继承了human类。boy和girl默认就拥有了__init__的初始化方法,和Washhand()方法,还有name这个实例变量。即使boy类里面没有定义__init__,而girl类连washhand方法都没有。

继承的类可以重写基类的方法,boy中的Washhand方法就经过了重写。此时boy的实例调用的就是重写的Washhand方法。

而boy和girl又分别拥有自己的Play()方法。继承类的方法里面可以调用基类的方法。girl类的Play方法就调用了基类的Washhand()方法。

此时分别实例化boy和girl类,并且调用它们的play方法。

b=boy('riko')b.Play()g=girl('rebecca')g.Play()

运行的结果是

riko pretent to wash handriko play carrebecca wash handrebecca play doll

python的类也支持多继承。在代码中加入两个类。

class student(): def __init__(self,school): self.school=school def study(self): print('study at '+self.school)class teenage(human,student): def __init__(self,name,school): human.__init__(self,name) student.__init__(self,school)

其中teenage类继承了human类,和student类。这个时候teenage类需要处理__init__方法。因为teenage接收到的参数需要分给human和student类各自的__init__方法。

使用human.__init__(self,name)和student.__init__(self,school)调用各自父类的初始化方法。

此时编写代码调用一下

tee=teenage('kitty','high shool')tee.Washhand()tee.study()

其中Washhand()是从human类继承的方法,而study是从student类继承的方法。运行结果为:

kitty wash handstudy at high shool

在继承当中,一个很重要的问题是实例变量和实例方法的查询。当一个实例变量或者实例方法在当前类没有定义的时候,会追溯到所有的父类进行查询,看看是在哪个父类定义的。只要在某个父类找到了,就会使用那个父类变量或者方法。此时会涉及到查询顺序的问题。同时,在新式类当中,会存在一个菱形问题。一个类A,继承了AA和AB,同时AA和AB又继承了OO。按照旧式类的查询方式,是深度优先,从左到右的顺序进行。也就是先AA,再OO,接着AB,再OO。这里的问题是OO被查了两遍。所以在新式类当中,会动态生成一个查询的序列。这个序列可以保证每个父类仅被查询一次,并且和A距离近的父类会被优先查询。这个序列可以用A.__mro__变量查询到。这个序列是动态生成的,如果继承链有了变化,整个查询顺序也会改变。

下面的代码演示了如果获取一个类的attribute查询顺序。并且演示一下父类存在同名的attribute时,是选择继承哪个父类的:

class OO(object): def oo(self): print('in oo')class AA(OO): def aa(self): print('in aa')class AB(OO): def oo(self): print('in ab')class A(AA,AB): passprint(A.__mro__)a=A()a.oo()

这段代码的运行结果为:

(, , , , )in ab

可以看到,A的attribute查询顺序为A,AA,AB,OO,object。如果这些类都有同名的attribute,那么会优先使用A,然后是AA,AB,OO,object类的同名attribute。

从上面的代码可以看到,使用a实例来访问oo()方法的时候,会先在A找,接着是AA,以及AB。当它在AB查询到了有oo()方法的定义,就决定继承AB类的这个方法。

之前在访问父类方法的时候,都是使用 类.方法 的形式来进行调用了。这样在菱形问题的时候,同一个父类方法会被调用两次。

class OO(object): def oo(self): print('in oo')class AA(OO): def oo(self): OO.oo(self) print('in aa')class AB(OO): def oo(self): OO.oo(self) print('in ab')class A(AA,AB): def oo(self): AA.oo(self) AB.oo(self) print('in a')a=A()a.oo()

这段代码的运行结果为

in ooin aain ooin abin a

可以看到OO类的方法被调用了两次。

如果只想要调用一次的话,那么就要使用super()。super()是根据__mro__工作的,super()会返回搜索链中的下一个类。super的第一个参数是类,第二个参数是类或者实例。super根据第二个参数的类的__mro__列表,返回第一个参数之后的那个类。比如super(A,a)根据a实例所在类的__mro__列表,返回A之后的那个类。

把前面的代码修改一下:

class OO(object): def oo(self): print('in oo')class AA(OO): def oo(self): super(AA,self).oo() print('in aa')class AB(OO): def oo(self): super(AB,self).oo() print('in ab')class A(AA,AB): def oo(self): super(A,self).oo() print('in a')a=A()a.oo()

这段代码的每个类都调用了父类的方法,使用super(当前类,某个类实例)的方式来返回一个类函数。其中a作为一个实例,被当作第二个参数在每个super函数中传递。而a的__mro__我们刚才已经看过,是A,AA,AB,OO的顺序。所以A的super返回A的下一个是AA,而AA的super返回AA的下一个是AB,而AB的super返回AB的下一个是OO。所以OO类的oo方法被最先执行了,接着AB、AA、A的oo方法的剩余语句也被执行了。这段代码返回的结果是:

in ooin abin aain a

这样OO的代码就仅执行了一遍了。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180627G1YPDK00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券