Python面向对象(超类和抽象的概念是什么)
Python面向对象,超类和抽象的概念是什么
本文小编为大家详细介绍“Python面向对象,超类和抽象的概念是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“Python面向对象,超类和抽象的概念是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。
对象魔法
在面向对象编程中,术语对象大致意味着一系列数据 (属性) 以及一套访问和操作这些数据的方法。
封装
封装讲究结构复用,逻辑内敛,以固定接口对外提供服务。其遵循单一职责,规定每个类型仅有一个引发变化的原因。单一封装的核心是解耦和内聚,这让设计更简单,清晰,代码更易测试和冻结,避免了不确定性。
继承
继承在遵循原有设计和不改变既有代码的前提下,添加新功能,或改进算法。其对应开闭原则,对修改封闭,对扩展开放。
多态
多态特性遵循里氏替换原则,所有继承子类应该能直接用于引用父类的场合。
我们习惯于将复杂类型的公用部分剥离出来,形成稳固的抽象类。其他引发变化的相似因素则被分离成多个子类,以确保单一职责得到遵守,并能相互替换。
我们习惯于将复杂类型的公用部分剥离出来,形成稳固的抽象类。其他引发变化的相似因素则被分离成多个子类,以确保单一职责得到遵守,并能相互替换。
场景:先将整体框架抽象成基类,然后每个子类仅保留单一分支逻辑。
继承和多态
定义一个名为 Animal 的 class,有一个 run() 方法可以直接打印:
class Animal(object):
def run(self):
print("Animal is running...")
当我们需要编写 Dog 和 Cat 类时,就可以直接从 Animal 类继承:
class Dog(Animal):
pass
class Cat(Animal):
pass
对于 Dog 来说,Animal 就是它的父类,对于 Animal 来说,Dog 就是它的子类。Cat 和 Dog 类似。
继承的好处一:子类获得了父类的全部功能,扩展子类自己的功能
上例中 Animial 实现了 run() 方法,因此,Dog 和 Cat 作为它的子类也拥有 run() 方法:
dog = Dog()
dog.run()
cat = Cat()
cat.run()
'''
Animal is running...
Animal is running...
'''
我们也可以扩展子类的方法,比如 Dog 类:
class Dog(Animal):
def run(self):
print("Dog is running...")
def dog_eat(self):
print("Eating bones...")
继承的好处二:重写父类的功能。
无论是 Dog 还是 Cat,它们 run() 的时候,显示的都是 Animal is running...,而对于 Dog 和 Cat 本身,应该具有自己的 run() 特性,即: Dog is running.. 和 Cat is running...,因此,对 Dog 和 Cat 类改进如下:
class Dog(Animal):
def run(self):
print("Dog is running...")
def dog_eat(self):
print("Eating bone...")
class Cat(Animal):
def run(self):
print("Cat is running...")
def cat_eat(self):
print("Eating fish...")
if __name__ == "__main__":
dog = Dog()
dog.run()
cat = Cat()
cat.run()
'''
Dog is running...
Eating bone...
Cat is running...
Eating fish...
'''
当子类的 run() 覆盖了父类的 run() 时候,运行时总是会调用子类的 run() 。这样,我们就获得了继承的另一个好处:多态。
判断一个变量是否是某个类型可以用 isinstance() 判断:
>>> isinstance(dog,Animal)
>>> isinstance(cat,Animal)
'''
True
True
'''
>>> isinstance(dog,Dog)
>>> isinstance(cat,Dog)
'''
True
False
'''
上面示例可以看到,dog 的数据类型既是 Animal,也是 Dog。因为 Dog 是从 Animal 继承下来的,当我们创建 Dog 实例时,我们认为 dog 的数据类型是 Dog,但同时 dog 也是 animal 的数据类型,因为 Dog 本来就是 Animal 的一种。而 cat 的数据类型是 Animal 没错,但是 cat 不是 Dog 数据类型。
所以,在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。但是,反过来就不行:
>>> b = Animal()
>>> isinstance(b, Dog)
'''
False
'''
Dog 可以看成 Animal,但 Animal 不可以看成Dog。
超类
要指定超类,可在 class 语句中的类名后加上超类名,并将其用圆括号括起。
Filter 是一个过滤序列的通用类。实际上,它不会过滤掉任何东西。
class Filter:
def init(self):
self.blocked = []
def filter(self, sequence):
return [x for x in sequence if x not in self.blocked]
class SPAMFilter(Filter):
# SPAMFilter是Filter的子类 def init(self): # 重写超类Filter的方法init
def init(self): # 重写超类Filter的方法init
self.blocked = ['SPAM']
if __name__=="__main__":
f = Filter()
f.init()
print(f.filter([1, 2, 3]))
'''
1, 2, 3
'''
Filter 类的用途在于可用作其他类 (如将 'SPAM' 从序列中过滤掉的 SPAMFilter 类) 的基类 (超类)。
if __name__=="__main__":
s = SPAMFilter()
s.init()
a = s.filter(['SPAM', 'SPAM', 'SPAM', 'SPAM', 'eggs', 'bacon', 'SPAM'])
print(a)
'''
['eggs', 'bacon']
'''
请注意 SPAMFilter 类的定义中有两个要点。
以提供新定义的方式重写了 Filter 类中方法 init 的定义。
直接从 Filter 类继承了方法 filter 的定义,因此无需重新编写其定义。
第二点说明了继承很有用的原因:可以创建大量不同的过滤器类,它们都从 Filter 类派生而来,并且都使用已编写好的方法 filter。
你可以用复数形式的 __ bases __ 来获悉类的基类,而基类可能有多个。为说明如何继承多个类,下面来创建几个类。
class Calculator:
def calculate(self, expression):
self.value = eval(expression)
class Talker:
def talk(self):
print('Hi, my value is',self.value)
class TalkingCalculator(Calculator, Talker): pass
if __name__=="__main__":
tc = TalkingCalculator()
tc.calculate('1 + 2 * 3')
tc.talk()
'''
Hi, my value is 7
'''
这被称为多重继承,是一个功能强大的工具。然而,除非万不得已,否则应避免使用多重继承,因为在有些情况下,它可能带来意外的 “并发症”。
使用多重继承时,有一点务必注意:如果多个超类以不同的方式实现了同一个方法 (即有多个同名方法),必须在class 语句中小心排列这些超类,因为位于前面的类的方法将覆盖位于后面的类的方法。
因此,在前面的示例中,如果 Calculator 类包含方法 talk,那么这个方法将覆盖 Talker 类的方法 talk (导致它不可访问)。
如果像下面这样反转超类的排列顺序:
class TalkingCalculator(Talker, Calculator): pass
将导致 Talker 的方法 talk 是可以访问的。多个超类的超类相同时,查找特定方法或属性时访问超类的顺序称为方法解析顺序 (MRO),它使用的算法非常复杂。
抽象基类
一般而言,抽象类是不能实例化的类,其职责是定义子类应实 现的一组抽象方法。
下面是一个简单的示例:
from abc import ABC, abstractmethod
class Talker(ABC):
@abstractmethod
def talk(self):
pass
这里的要点是你使用 @abstractmethod 来将方法标记为抽象的 —— 在子类中必须实现的方法。
如果你使用的是较旧的 Python 版本,将无法在模块 abc 中找到 ABC 类。在这种情况下,需要导入ABCMeta,并在类定义开头包含代码行 __ metaclass __ = ABCMeta (紧跟在 class 语句后面并缩进)。如果你使用的是 3.4 之前的 Python 3 版本,也可使用 Talker(metaclass=ABCMeta) 代替 Talker(ABC)。
抽象类(即包含抽象方法的类)最重要的特征是不能实例化。
>>> Talker()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Talker with abstract methods talk
假设像下面这样从它派生出一个子类:
class Knigget(Talker):
pass
由于没有重写方法 talk,因此这个类也是抽象的,不能实例化。如果你试图这样做,将出现类似于前面的错误消息。然而,你可重新编写这个类,使其实现要求的方法。
class Knigget(Talker):
def talk(self):
print("Ni!")
现在实例化它没有任何问题。这是抽象基类的主要用途,而且只有在这种情形下使用 isinstance 才是妥当的:如果先检查给定的实例确实是 Talker 对象,就能相信这个实例在需要的情况下有方法 talk。
>>> k = Knigget()
>>> isinstance(k, Talker) True
>>> k.talk()
Ni!
读到这里,这篇“Python面向对象,超类和抽象的概念是什么”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注恰卡编程网行业资讯频道。
推荐阅读
-
python(中无效的十进制怎么解决 python怎么转换进制)
python怎么转换进制?Python执行二进制转换:1.十进制到二进制(bin)首先,让让我们看看如何将十进制转换成二进制。我...
-
python怎么清除完全相同的行(python splte如何分隔有多个相同符号的str)
pythonsplte如何分隔有多个相同符号的str?str你的string内容str_(相同的符号)执行完了以后再在相同符号的...
-
python(编程控制电脑关机 如何控制电脑关机)
如何控制电脑关机?可以在电脑的运行窗口中输入输入公式,给电脑可以设置自动关机。1.按开快捷键winr然后打开运行窗口。2.在运行窗...
-
python中的特殊标识符(python 中 标识符中可以有逗号吗)
python中标识符中可以有逗号吗?在python语言中合法的标识符是字母、数字以及_,所以我合法的标识符中肯定不能有逗号if...
-
python(excel 提取数据写入新表 python导入excel数据找不到工作簿)
python导入excel数据找不到工作簿?我可以导入数据后找不到工作,不是因为他的工作没有被转移。什么软件可提取并合并Exce...
-
python中字典定义的四种方法(python global关键字的用法详解)
pythonglobal关键字的用法详解?global标志实际上是目的是提示python讲解器,说被其修饰的变量是全局变量。这样...
-
python(array用法 python如何对两个数组做差处理)
python如何对两个数组做差处理?Python中的列表中的元素肯定不能真接相加,减。t最佳的位置的是将列表装换成Python中的...
-
python多行注释符号怎么表示
python多行注释符号怎么表示这篇文章主要介绍“python多行...
-
python支持的操作系统是什么
python支持的操作系统是什么这篇文章主要介绍“python支持...
-
python如何判断列表为空
python如何判断列表为空这篇文章主要介绍“python如何判断...