Python中的OOP – Part2

编辑:光环大数据 来源: 互联网 时间: 2017-10-31 14:44 阅读:

  Python中的OOP–Part2,在Part1中我介绍了面向对象编程的三大支柱:封装、继承和多态。并且已经讲解了Python中封装的相关知识,接下来我们谈谈继承。

什么是继承?

继承作为面向对象编程中的一个概念,它可以帮助程序员实现:

1.建立模型-一种关系树(不是所有的编程语言都这样)

2.重用代码-帮助开发者遵守DRY原则和重用现有的实现和逻辑代码

3.扩展功能-有些时候不能改变现行类的源代码(别人都在用它,或者它不是public或干脆它就是不允许修改);要延伸的类的功能,就可以通过继承来实现。

Python支持单一和多重继承。在Python2.x和3.x中,继承的原理和实现存在很大的差异。我给出的的例子都是基于Python3.x的。

Python中的单一继承

在Python中,继承可以通过这的语法实现:classMySubClass(MyBaseClass)

先声明新的子类,然后括号中指明继承的基类(或称为父类、超类)。

举个常用的例子:Animal作为一个基类,Panda,Pig等各种动物就可以作为它的子类。

来看一段代码:

classAnimal:

__name=None

__age=0

__is_hungry=False

__nr_of_legs=0

def__init__(self,name,age,is_hungry,nr_of_legs):

self.name=name

self.age=age

self.is_hungry=is_hungry

self.nr_of_legs=nr_of_legs

#

#METHODS

#

defeat(self,food):

print("{}iseating{}.".format(self.name,food))

#

#PROPERTIES

#

@property

defname(self):

returnself.__name

@name.setter

defname(self,new_name):

self.__name=new_name

@property

defage(self):

returnself.__age

@age.setter

defage(self,new_age):

self.__age=new_age

@property

defis_hungry(self):

returnself.__is_hungry

@is_hungry.setter

defis_hungry(self,new_is_hungry):

self.__is_hungry=new_is_hungry

@property

defnr_of_legs(self):

returnself.__nr_of_legs

@nr_of_legs.setter

defnr_of_legs(self,new_nr_of_legs):

self.__nr_of_legs=new_nr_of_legs

在Animal类中,定义了四个私有成员(__name,__age,__is_hungry,__nr_of_legs)。然后分别使用@property定义每个成员的属性(这个在Part1的内容中有提到)。然后我创建了一个构造函数,带有4个参数(不包含self),使用@property设定私有成员的值。基于这4个property,我创建了一个方法叫eat(self,food),它会打印出XiseatingY,其中X是动物,Y是入参。接下来,我们把Animal作为一个基类来使用,用继承创建一条Snake。

classSnake(Animal):

__temperature=28

def__init__(self,name,temperature):

super().__init__(name,2,True,0)

self.temperature=temperature

#

#METHODS

#

defeat(self,food):

iffood=="meat":

super().eat(food)

else:

raiseValueError

#

#PROPERTIES

#

@property

deftemperature(self):

returnself.__temperature

@temperature.setter

deftemperature(self,new_temperature):

ifnew_temperature<10ornew_temperature>40:

raiseValueError

self.__temperature=new_temperature

在Snake类中存在两个参数:name和temperature,对于__temperature这个私有成员,我创建一个property来接受入参。在构造函数里,我首先使用super()调用基类的构造函数(还有其他的方法来调用,但在Python3.x中,这是推荐的方式)。当调用基类的构造函数时,我会传入默认值,例如nr_of_legs默认值zero,因为蛇没有腿,is_hungry默认值为True,因为蛇通常比其他动物要饿

跟其他编程语言一样,在Python中也可以重写方法。我已经重写了eat方法,并且我加了额外的逻辑:如果给出的食物不是肉,那么我会抛出一个ValueError;如果是,我就会调用基类Animal中定义的eat方法。

Python中的多重继承

Python为我们提供了从多个基类继承的可能性,叫做多重继承。如果有一些不同功能的类,而且这些不同的功能需要被组合在一起使用,那么多重继承将会非常有用。

在Python中,多重继承的语法非常简单,只要在新子类后的括号内填写所有的基类即可,例如:classMySubClass(MyBaseClass1,MyBaseClass2,MyBaseClass3)。

classPhone:

def__init__(self):

print("Phoneconstructorinvoked.")

defcall_number(self,phone_number):

print("Callingnumber{}".format(phone_number))

classComputer:

def__init__(self):

print("Computerconstructorinvoked.")

definstall_software(self,software):

print("Computerinstallingthe{}software".format(software))

classSmartPhone(Phone,Computer):

def__init__(self):

super().__init__()

我定义了3个类:Phone,Computer,SmartPhone

其中2个是基类:Phone,Computer;1个是继承类:SmartPhone

从逻辑上讲,这样做是正确的:一部智能手机可以打电话也可以安装软件,SmartPhone应该具有call_number方法(从Phone继承)和install_software方法(从Computer继承)

#

#willbediscussedlaterwhyonlytheconstructorofPhoneclasswasinvoked

#

>>>my_iphone=SmartPhone()

Phoneconstructorinvoked.

>>>my_iphone.call_number("123456789")

Callingnumber123456789

>>>my_iphone.install_software("python")

Computerinstallingthepythonsoftware

我们来看SmartPhone这个类的构造函数,挺简单,它包含了基类的构造函数,看上去没错,它通过继承获得的。但问题是从哪个基类继承的。如果仔细代码,会发现它仅仅从Phone继承的构造函数,这是为什么?

这个问题不是很好解释,它与Python的MRO(MethodResolutionOrder)有关系。

Python中的MRO

MRO是一套规则,用于定义和确定类的线性化(linearization)。线性化(也称为优先级列表)是一个由近及远的基类的列表。MRO对于支持多重继承的编程语言十分重要,它有助于编程语言处理DiamondProblem。

在Python2.3,为了更好的定义多重继承时具体的MRO,发生了一些根本性的变化(这个版本采用C3线性化)。MicheleSimionato写过一篇很棒的帖子,说明了相关的方法和算法,帖子相当长,包含了大量的例子和算法的详细说明。GuidovanRossum也写过一篇关于PythonMRO的详细文章。Perl语言同样是使用C3线性化算法来定义MRO的。

为了给回答我前面提出的问题:为什么super().__init__()只调用Phone的构造函数?出现这种情况,是因为基类的解析顺序。当super().__init__()调用Phone(MRO中的第一个基类),其他基类的__init__()没有被调用。MRO影响基类的结构函数如何被调用,我作为一个程序猿,当我使用多重继承时,必须确保我的基类全部被正确的初始化。我更新SmartPhone的代码以确保Computer和Phone都被初始化。(如果使用Python2.x,请确保你获得了相同的MRO)

classPhone(object):

def__init__(self):

print("Phoneconstructorinvoked.")

defcall_number(self,phone_number):

print("Callingnumber{}".format(phone_number))

classComputer(object):

def__init__(self):

print("Computerconstructorinvoked.")

definstall_software(self,software):

print("Computerinstallingthe{}software".format(software))

classSmartPhone(Phone,Computer):

def__init__(self):

Phone.__init__(self)

Computer.__init__(self)

现在创建了一个新的SmartPhone,这两个基类的构造函数都被调用了。

Python3.2.3(default,Feb272014,21:31:18)[GCC4.6.3]onlinux2

Type"help","copyright","credits"or"license"formoreinformation.

>>>fromoop_multiimportSmartPhone

>>>s=SmartPhone()

Phoneconstructorinvoked.

Computerconstructorinvoked.

>>>

在Python中,对一个类使用mro()或者__mro__能够显示出类的MRO。

例如:

>>>SmartPhone.mro()[<class'SmartPhone'>,<class'Phone'>,<class'Computer'>,<class'object'>]>>>SmartPhone.__mro__(<class'SmartPhone'>,<class'Phone'>,<class'Computer'>,<class'object'>)

MRO中的第一个元素,是我们使用mro()这个命令的类SmartPhone,接着是Phone,最后是Computer,这三个基类是如此设定的。

在一些拥有复杂层次结构的大型类中定义MRO将会十分困难,甚至在一些特定情况下MRO是无法定义的。Python将会抛出TypeError以防基类间出现交叉引用,例如:

classPhone(object):

def__init__(self):

print("Phoneconstructorinvoked.")

defcall_number(self,phone_number):

print("Callingnumber{}".format(phone_number))

classComputer(object):

def__init__(self):

print("Computerconstructorinvoked.")

definstall_software(self,software):

print("Computerinstallingthe{}software".format(software))

classSmartPhone(Phone,Computer):

def__init__(self):

Phone.__init__(self)

Computer.__init__(self)

classTablet(Computer,Phone):

def__init__(self):

Computer.__init__(self)

Phone.__init__(self)

classPhablet(SmartPhone,Tablet):

def__init__(self):

SmartPhone.__init__(self)

Tablet.__init__(self)

如代码中所示,我创建了两个新类,一个是Tablet(多重继承自Computer和Phone,注意跟SmartPhone的不同),另个是Phablet(多重继承自SmartPhone和Tablet)。SmartPhone和Tablet对于基类Phone和Computer差生了交叉引用,Python解释器于是抛出了TypeError,因为C3线性化规则不能给出确切的基类的调用顺序。

 

  Python培训Python培训班Python培训机构,就选光环大数据!

  还不够过瘾?想学习更多?点击 http://hadoop.aura.cn/python/ 进行Python学习!


大数据培训、人工智能培训、Python培训、大数据培训机构、大数据培训班、数据分析培训、大数据可视化培训,就选光环大数据!光环大数据,聘请专业的大数据领域知名讲师,确保教学的整体质量与教学水准。讲师团及时掌握时代潮流技术,将前沿技能融入教学中,确保学生所学知识顺应时代所需。通过深入浅出、通俗易懂的教学方式,指导学生更快的掌握技能知识,成就上万个高薪就业学子。 更多问题咨询,欢迎点击------>>>>在线客服

你可能也喜欢这些

在线客服咨询

领取资料

X
立即免费领取

请准确填写您的信息

点击领取
#第三方统计代码(模版变量) '); })();
'); })();