面向对象-继承和多态
Posted guyanzhi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象-继承和多态相关的知识,希望对你有一定的参考价值。
在这一节中,你将体会到面向对象的诸多特色.
1、单继承
class Person(Object): def __init__(self, name, age): self.name = name self.age = age def walk(self): print("%s is walking..." % self.name) def talk(self): print("%s is talking..." % self.name) # 定义子类1 py23都支持 class Teacher(Person): def __init__(self, name, age, level): super(Teacher, self).__init__(name, age) # python提供了这个函数,创建一个父类的对象,用来调用父类的__init__() # 避免了再次定义这些属性 self.level = level def walk(self): # 继承父类的方法并 拓展 实践中,继承的这种用途意义并不很大,甚至常常是有害的。因为它使得子类与基类出现强耦合。 super().walk() # 避免再写一遍父类中的功能代码 print("加速...") def teach(self): print("%s is teaching..." % self.name) # 定义子类2 class Student(Person): def __init__(self, name, age, grade): Person.__init__(self, name, age) # 这样写避免了自己再次定义这些属性 self.grade = grade def fight(self): print("%s is fighting..." % self.name) t1 = Teacher("mr z", 30, "一级") s1 = Student("xiao ming", 15, "高中一年级")
所谓继承,就像上述代码中,定义Person 类时,class Person(Object) 表示Person 类拥有Object 类的属性和方法(一些内置方法和属性),class Teacher(Person),Teacher 类拥有Person 类的属性和方法...
(walk和talk). Person 是Teacher 的父类(基类、父类或超类(Base class、Super class)),Teacher 是Person 的子类..父类上还可以有父类,子类下也可以还有子类,这就是继承关系.
Python 有两个判断继承的函数:isinstance() 用于检查实例类型;issubclass() 用于检查类继承。参见下方示例:
class Person(object): pass class Child(Person): # Child 继承 Person pass May = Child() Peter = Person() print(isinstance(May,Child)) # True print(isinstance(May,Person)) # True print(isinstance(Peter,Child)) # False print(isinstance(Peter,Person)) # True print(issubclass(Child,Person)) # True
2、多继承
多继承是指一个类有多个父类的情况.多继承使用的比较少,但是你需要知道,多继承时,是怎样的继承顺序:首先提出两个概念:新式类和经典类.
新式类:python3中默认所有的类都是新式类:以Object为最终的父类(我喜欢叫它 祖先类) 创建对象时需要申请名称空间 将对象属性放进去 这些事情在新式类里 都是objeck类自动执行
经典类:python2中,继承于哪个类都需要在()里说明 ,没有显式的继承object类的类,以及该类的子类,都是经典类
有的地方会这样定义新式类和经典类:
Python 与其他语言不同点在于,当我们定义一个 class 的时候,我们实际上就定义了一种数据类型。我们定义的数据类型和Python自带的数据类型,比如str、list、dict没什么两样。
由任意内置类型派生出的类(只要一个内置类型位于类树的某个位置),都属于“新式类”,都会获得所有“新式类”的特性.反之,即不由任意内置类型派生出的类,则称之为“经典类”。
“新式类”和“经典类”的区分在Python 3之后就已经不存在,在Python 3.x之后的版本,因为所有的类都派生自内置类型objec.(即使没有显示的继承object类型),即所有的类都是“新式类”。
大抵上是一致的.
经典列和新式类在继承顺序(继承的查找)方式山有区别:
新式类的继承顺序是按照C3算法来的
经典类则是按照“从左至右,深度优先”的方式去查找属性。当有菱形继承时,祖先类最后查找.
了解 C3算法
merge操作是C3算法的核心。
遍历执行merge操作的序列,如果一个序列的第一个元素,是其他序列中的第一个元素,或不在其他序列出现,则从所有执行merge操作序列中删除这个元素,合并到当前的mro中。
举例:
# 简易的定义几个类 class A(object): pass class B(object): pass class C(object): pass class E(A, B): pass class F(B, C): pass class G(E, F): pass ‘‘‘ O表示object类 A、B、C都继承至一个基类,所以mro序列依次为[A,O]、[B,O]、[C,O] mro(E) = [E] + merge(mro(A), mro(B), [A,B]) = [E] + merge([A,O], [B,O], [A,B]) 执行merge操作的序列为[A,O]、[B,O]、[A,B] A是序列[A,O]中的第一个元素,在序列[B,O]中不出现,在序列[A,B]中也是第一个元素,所以从执行merge操作的序列([A,O]、[B,O]、[A,B])中删除A,合并到当前mro,[E]中。 mro(E) = [E,A] + merge([O], [B,O], [B]) 再执行merge操作,O是序列[O]中的第一个元素,但O在序列[B,O]中出现并且不是其中第一个元素。继续查看[B,O]的第一个元素B,B满足条件,所以从执行merge操作的序列中删除B,合并到[E, A]中。 mro(E) = [E,A,B] + merge([O], [O]) = [E,A,B,O] ‘‘‘
查看和判断继承有如下方法:
Python 有两个判断继承的函数:isinstance() 用于检查实例类型;issubclass() 用于检查类继承。参见下方示例:
class Person(object): pass class Child(Person): # Child 继承 Person pass May = Child() Peter = Person() print(isinstance(May,Child)) # True print(isinstance(May,Person)) # True print(isinstance(Peter,Child)) # False print(isinstance(Peter,Person)) # True print(issubclass(Child,Person)) # True
类名.__bases__方法 返回该类继承于哪些类(多继承时的从左到右的类都将被返回)
类名.__base__方法 只返回从左到右继承的第一个类.
类名.__mro__或 类名.mro() 可以返回该类的查找顺序列表 在最上面的实例中 : print(Teacher.mro()) 打印[<class ‘__main__.Teacher‘>, <class ‘__main__.Person‘>, <class ‘object‘>]
在python3中,使用类和对象来编程,要求你能把握好类和对象的定义,比如一个学生管理系统中,有老师,学生,,这两个类应该有一个父类 Person,而不能将Teacher设置成Student的父类,即便Teacher
的 name age 等属性在Student中也有. 把握好这一"先抽象,后继承"的原则,在安排各种类和父类时就不易出错.
使用python3的新式类时,Object为默认的父类,所有的类都会继承它的一些属性和方法,它们的名称是以双下划线__开头,同时又以双下划线__结尾。
这些属性和方法不再是私有属性和私有方法,它们是可以在类的外部通过实例对象去直接访问的,且它们都有着各自特殊的意义,我们可以通过这些特殊属性和特殊方法来获取一些重要的信息,
或执行一些有用的操作。
属性:
属性名称 |
说明 |
__doc__ | 类的描述性信息 类似函数的‘‘‘ ‘‘‘ 注释 |
__module__ | 当前操作对象的类的定义所在模块名 |
__class__ | 当前操作的对象的类名 |
__dict__ | 一个字典,保存类的所有成员(属性和方法)或实例对象的成员属性 |
实例应用:
class Dog(object): """这是一个Dog类""" # print(‘Hello, This is a dog.‘) color = ‘白色‘ def __init__(self, name): self.name = name self.__id = 1234 def func1(self): pass def __func1(self): pass @classmethod def func2(cls): pass @staticmethod def func3(): pass
from dog import Dog dog1 = Dog(‘泰迪‘) print(dog1.__doc__) print(dog1.__module__) print(dog1.__class__) print(dog1.__dict__) print(Dog.__dict__)
打印结果:
这是一个Dog类 dog <class ‘dog.Dog‘> {‘name‘: ‘泰迪‘, ‘_Dog__id‘: 1234} {‘__dict__‘: <attribute ‘__dict__‘ of ‘Dog‘ objects>, ‘__module__‘: ‘dog‘, ‘func2‘: <classmethod object at 0x000001DF0C658F98>, ‘color‘: ‘白色‘, ‘func3‘: <staticmethod object at 0x000001DF0C658FD0>, ‘_Dog__func1‘: <function Dog.__func1 at 0x000001DF0C63E400>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘Dog‘ objects>, ‘__doc__‘: ‘这是一个Dog类‘, ‘__init__‘: <function Dog.__init__ at 0x000001DF0C63E2F0>, ‘func1‘: <function Dog.func1 at 0x000001DF0C63E378>}
方法:
方法 | 说明 |
__init__ | 初始化构造方法,创建类时自动执行 |
__del__ | 析构方法,当对象在内存中被释放(回收)前,会自动执行 |
__str__ | 如果类中定义了__str__方法,并有返回值,在打印对象时会自动输出_-str__的返回值 |
__xxxitem__ |
是指__getitem__、__setitem__、__delitem这3个方法,它们用于索引操作,比如对字典的操作,分别表示 获取、设置、删除某个条目。 数据。可以通过这些方法来定义一个类对字典进行封装, 从而可以对字典中key的操作进行控制,尤其是删除操作。 |
__new__ | 该方法会在__init__方法之前被执行,该方法会创建被返回一个新的实例对象,然后传递给__init__。另外需要说明的是,这不是一个成员方法,而是一个静态方法。 |
__call__ | 源码中的注释是"Call self as a function." 意思是把自己(实例对象)作为一个函数去调用,而函数的调用方式是函数名() 。也就是说,当我们执行实例对象() 或者 类名()() 这样的操作时会触发执行该方法。 |
示例:
https://www.cnblogs.com/yyds/p/7591804.html
以上是关于面向对象-继承和多态的主要内容,如果未能解决你的问题,请参考以下文章