【python】-- 类的继承(新式类/经典类)、多态

继承

之前我们说到了类的公有属性和类的私有属性,其实就是类的封装,现在准备随笔的 是继承,是面向对象的第二大特性。

  面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

  通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”,继承的过程,就是从一般到特殊的过程。在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。

  继承概念的实现方式主要有2类:实现继承、接口继承。

  1. 实现继承是指使用基类的属性和方法而无需额外编码的能力。
  2. 接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力(子类重构爹类方法)。

  在考虑使用继承时,有一点需要注意,那就是两个类之间的关系应该是“属于”关系。例如,Employee 是一个人,Manager 也是一个人,因此这两个类都可以继承 Person 类。但是 Leg 类却不能继承 Person 类,因为腿并不是一个人。

  抽象类仅定义将由子类创建的一般属性和方法,OO开发范式大致为:划分对象→抽象类→将类组织成为层次化结构(继承和合成) →用类与实例进行设计和实现几个阶段

二、类的继承

1、继承的定义

在类名的括号中写入需要继承的类名即可

class Person(object):

    def talk(self):
        print("person is talking...")

class BlackPerson(Person):  #继承Person这个类

    def walk(self):  #定义子类自身的walk方法
        print("BlackPerson is walking.....")

b = BlackPerson()
b.talk()   #由于继承了父类的talk()方法,所以可以被调用
b.walk()  #调用子类自身的walk方法

#输出
person is talking...
BlackPerson is walking.....

2、构造方法的继承

 说明:因为子类有自己的属性,但是又想继承父类的属性,所以需要先继承,再重构

继承类的构造方法2种写法:

  1. 经典类写法:父类.__init(self,name,age)
  2. 新式类写法:super(子类,self).__init__(name,age)

更多经典类和新式类知识补充:点击

注:建议使用新式类的写法,因为使用经典类的写法,在多继承的情况下,会出现重复调用参数的可能

class Person(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age
        self.sex = "noraml"

    def talk(self):
        print("person is talking...")

class BlackPerson(Person):
    def __init__(self,name,age,strength):  #定义时需要传入父类的属性名
        Person.__init__(self,name,age)  #继承父类的构造方法,也可以写成:super(BlackPerson,self).__init__(name,age)
        self.strength = strength   #定义子类本身的属性
        print(self.name,self.age,self.sex)

    def walk(self):
        print("BlackPerson is walking.....")

b = BlackPerson("xiaogao",18,"strong")

#输出
xiaogao 18 noraml

这边不禁的有一个疑问?我不能重新写一遍,我为啥要继承父类中的方法呢?因为你重新写一遍的话,只能继承self.name和self.age,那self.sex怎么办,它也需要重写吗?所以啊,只有把父类中的构造函数全部继承过来,只能用上面这种办法?那它是怎么实现的呢?我们来画一个图:

3、子类对父类方法的重写

说明:如果我对父类中的方法不满意,我可以重写父类中的方法,当然还可以继承父类中的方法

class Person(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age
        self.sex = "noraml"

    def talk(self):
        print("person is talking...")

class BlackPerson(Person):

    def talk(self):  #重写父类的方法
        Person.talk(self)  #调用父类的方法
        print("BlackPerson is talking ...")

    def walk(self):
        print("BlackPerson is walking.....")

b = BlackPerson("xiaogao",18)  #子类不写,则继承父类的构造方法
b.talk()
b.walk()

#输出
person is talking...
BlackPerson is talking ...
BlackPerson is walking.....

其实重写不是上面说的那么简单,只需要子类的方法名和父类的中的方法名一样就算重写了,其实不然,那怎么样才算重写呢?

重写的条件:

  1. 重写方法的方法名必须和父类中被重写的方法名一模一样
  2. 重写方法的传入的参数名和参数的个数必须和父类中被重写的方法一样

我们再来看看下面的例子:

class Person(object):

    def talk(self,food):
        print("person is talking...{0}".format(food))

class BlackPerson(Person):

    def talk(self):  #方法名和父类的方法名一样,但是少了一个food参数
        print("BlackPerson is talking ...")

b = BlackPerson("xiaogao",18,"strong")
b.talk()

#输出
BlackPerson is talking ...

看着像重写了呀!其实不是重写,根据重写的条件明显两个方法的传入参数名和参数的个数都不一样,其实上面这种只是子类自己写了一个talk方法,只是名字一样,但是传入的参数和参数的个数不一样,并不是重写了父类中的方法。下面这个才是真正的重写:

class Person(object):

    def talk(self,food):
        print("person is talking...{0}".format(food))

class BlackPerson(Person):

    def talk(self,food):  #重写父类的方法(方法名和传入的参数名以及参数的个数与父类的方法一样)
        print("BlackPerson is talking ...{0}".format(food))

b = BlackPerson("xiaogao",18,"strong")
b.talk("hotdog")

#输出
BlackPerson is talking ...hotdog

类继承练习的小例子:

class SchoolMember(object):
    ‘‘‘学校成员基类‘‘‘

    member = 0  #设置类属性
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex =sex
        self.enroll()  #每次生成一个对象注册一次
    def enroll(self):
        "注册"
        print("just enroll a new school member [{0}]".format(self.name))
        SchoolMember.member += 1

    def tell(self):
        print("------info:{0}-----".format(self.name))
        for k,v in self.__dict__.items():  #__dict__()函数是获取对象的属性,以字典的形式返回
            print("\t",k,v)
        print("------end--------")

    def __del__(self):
        print("开除了[{0}]...".format(self.name))
        SchoolMember.member -= 1

class Teacher(SchoolMember):
    "讲师类"

    def __init__(self,name,age,sex,salary,course):
        SchoolMember.__init__(self,name,age,sex)
        self.salary = salary
        self.course = course

    def teaching(self):
        "讲课方法"
        print("Teacher [{0}] is teaching [{1}]".format(self.name,self.course))

class Student(SchoolMember):
    "学生类"
    def __init__(self,name,age,sex,couser,tuition):
        SchoolMember.__init__(self,name,age,sex)
        self.couser = couser
        self.tuition = tuition
        self.amount = 0

    def pay_tuition(self,amount):
        print("student [{0}] has just paied [{1}]".format(self.name,amount))
        self.amount += amount

t1 = Teacher("xiaogao",18,"F*M",3000,"Python")
s1 = Student("shuaigao",19,"M","PYS15",300000)
s2 = Student("gaogao",12,"M","PYS15",11000)

print(SchoolMember.member)
del s1  #删除一个变量
t1.tell()
s2.tell()
print(SchoolMember.member) #会执行__del__函数

#输出
just enroll a new school member [xiaogao]
just enroll a new school member [shuaigao]
just enroll a new school member [gaogao]
3
开除了[shuaigao]...
------info:xiaogao-----
     salary 3000
     sex F*M
     course Python
     name xiaogao
     age 18
------end--------
------info:gaogao-----
     couser PYS15
     sex M
     name gaogao
     amount 0
     tuition 11000
     age 12
------end--------
2
开除了[gaogao]...
开除了[xiaogao]...

多态

多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。

  那么,多态的作用是什么呢?我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用!多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。

  很遗憾,在python不能直接的支持多态,所以我们只能间接的去执行

class Animal:

    def __init__(self,name):
        self.name = name

    def talk(self):
        print("animal {0} is talk".format(self.name))

class Cat(Animal):
    def talk(self):
        return "Meow!"

class Dog(Animal):
    def talk(self):
        return "Woof!Woof!"

def animal_talk(obj):    #定义一个调用类的talk方法
    print(obj.talk())

all_animal = [Dog("d1"),Cat("c1")]  #把对象存入列表中

for animal in all_animal:  #循环传入对象
    animal_talk(animal)  # 实现类似于Animal.talk(Dog("d1"))这种效果

#输出
Woof!Woof!
Meow!

小结:

  1. 多态在python中是不支持的
  2. 想要在python实现类似于Animal.talk(Dog("d1")),可以定义一个可以类方法的一个方法,调用时需要往这个方法传入类的实例
时间: 08-04

【python】-- 类的继承(新式类/经典类)、多态的相关文章

python基础学习日志day6-类的经典类vs新式类

经典类VS新式类区别 1)写法新式类class Person(object):#new style 经典类class Persion: #classical style 2)调用父类 新式写法用super 经典类直接写父类类名 3)多继承时继承顺序python3使用的是广度查询,所以两个都一样. 经典类python2是深度查询.所以经典类python2多继承是有BUG class D(B,C) D-->B-->A--C # -*- coding:utf-8 -*- __author__ = '

类的继承定义一个computer类在此基础上派生出两个子类(继承与多态绑定)

题目如下 定义一个计算机类(Computer),并在它的基础上派生出两个子类:台上机(Desktop)和便携机类(Notebook),在Computer中定义几个方法,并在子类Desktop和Notebook中覆盖这些方法.在main方法中利用对象类型转换将类Desktop和Notebook的对象分别赋值给Computer对象,并应用多态调用这些方法. 实验目的 (1)       理解继承的概念,掌握继承的语法. (2)       学习定义和使用子类. (3)       掌握继承过程中的方

python基础之继承派生、组合、接口和抽象类

类的继承与派生 经典类和新式类 在python3中,所有类默认继承object,但凡是继承了object类的子类,以及该子类的子类,都称为新式类(在python3中所有的类都是新式类) 没有继承object类的子类成为经典类(在python2中,没有继承object的类,以及它的子类,都是经典类) 1 class People: 2 pass 3 class Animal: 4 pass 5 class Student(People,Animal): #People.Animal称为基类或父类,

【python】-- 类的多继承、经典类、新式类

继承知识点补充 在python还支持多继承,但是一般我们很少用,有些语言干脆就不支持多继承,有多继承,就会带来两个概念,经典类和新式类. 一.多继承 之前我们都是讲的单继承,那么什么是多继承呢?说白了,就是:子类可以继承多个父类,就叫多继承. class SchoolMember(object): #SchoolMember类 '''学校成员基类''' def tell(self): print("the schoolmeber is tell...") class School(ob

python之继承、抽象类、新式类和经典类

一.上节补充1.静态属性静态属性 : 类的属性,所有的对象共享这个变量 如果用对象名去修改类的静态属性:在对象的空间中又创建了一个属性,而不能修改类中属性的值 操作静态属性应该用类名来操作 例1:请你写一个类,能够统计一共实例化了多少个对象? class Foo: count = 0 def __init__(self): Foo.count += 1 f1 = Foo() print(f1.count) # 1 f2 = Foo() f3 = Foo() f4 = Foo() f5 = Foo

Python新式类与经典类的区别

1.新式类与经典类 在Python 2及以前的版本中,由任意内置类型派生出的类(只要一个内置类型位于类树的某个位置),都属于“新式类”,都会获得所有“新式类”的特性:反之,即不由任意内置类型派生出的类,则称之为“经典类”. “新式类”和“经典类”的区分在Python 3之后就已经不存在,在Python 3.x之后的版本,因为所有的类都派生自内置类型object(即使没有显示的继承object类型),即所有的类都是“新式类”. 官方文档 https://www.python.org/doc/new

python中新式类和经典类

python中的类分为新式类和经典类,具体有什么区别呢?简单的说, 1.新式类都从object继承,经典类不需要. Python 2.x中默认都是经典类,只有显式继承了object才是新式类 Python 3.x中默认都是新式类,不必显式的继承object 2.经典类继承深度优先,新式类继承广度优先. 在多重继承关系下,子类的实例对象想要调用父类的方法,向上寻找时的顺序. 3.新式类相同父类只执行一次构造函数,经典类重复执行多次. class A: def __init__(self): pri

Python自学之乐-python 2、python 3中经典类、新式类的深度和广度优先小结

#Author:clarkclass Original(object):#在python 3 中写上object的新式类和不写的经典类遵循的都是广度优先原则 def __init__(self): print("in Original")class Second(Original): pass # def __init__(self): # print("in the second")class Third(Original): def __init__(self)

面向对象【day07】:类的属性-继承-经典类

本节内容 类的公有属性 析构函数 类的继承 新式类和经典类 一.类的公有属性 一.概述 前面我们讲了类的私有属性,现在我们来说说类的公有属性,这边很容易被人弄混淆,有人觉的,在__init__()构造方法中,除了私有属性,其他的都是公有属性了,其实这是一个错误的结论,并不是定义在__init__()初始化方法中的属性是公有属性(除私有属性),那什么是公有属性呢?揭起了大家的好奇心. 定义:指的是所属这个类的所有对象,都可以访问的属性,叫做公有属性. 二.公有属性 2.1 定义 说明:在类中直接定

新式类 VS 经典类

一.概述 Python中支持多继承,也就是一个子类可以继承多个父类/基类.当一个调用一个自身没有定义的属性时,它是按照何种顺序去父类中寻找的呢?尤其是当众多父类中都包含有同名的属性,这就涉及到新式类 和 经典类的区别. 二.多继承 1 class Food(object): 2 3 def __init__(self, name, color): 4 self.name = name 5 self.color = color 6 7 def eatable(self): 8 print("%s