第十章 初识面向对象

第十章 初识面向对象

1.面向对象思想的引入                                              

例:公司需要开发一款人狗大战的游戏
需要两个角色:人 狗
  人的属性:昵称、性别、生命值、战斗力、背包
  狗的属性:昵称、品种、生命值、战斗力
再尚未学习面向对象知识的时候,我们只是知道需要两个字典描述这两个角色

例1:初步思想

# 例1:初步思想
#
person = {'name':'alex', 'sex':'不详', 'hp':250, 'dps':5, 'bag':[]}
#
dog = {'name':'2哈', 'kind':'哈士奇', 'hp':15000, 'dps':200}
# 说明: 这样虽然已经能够描述这两个角色,但是如果增加角色,就需要重新创建字典,很是繁琐

例2:使用函数创建两个模子

# 例2:使用函数创建两个模子
def Person(name, sex, hp, dps): # 人模子
    dic = {'name': name, 'sex': sex, 'hp':hp, 'dps': dps, 'bag': []}
    return dic
def Dog(name, kind, hp, dps): # 人模子
    dic = {'name': name, 'kind': kind, 'hp':hp, 'dps': dps, 'bag': []}
    return dic

alex = Person('alex', 'N/F', 250, 5)
ha2 = Dog('2哈', '哈士奇', 15000, 200)

print(alex)
# {'name': 'alex', 'sex': 'N/F', 'hp': 250, 'dps': 5, 'bag': []}
print(ha2)
# {'name': '2哈', 'kind': '哈士奇', 'hp': 15000, 'dps': 200, 'bag': []}
# 说明:这样创建人物已经很方便了,接下来就要进行人狗大战了

例3:人狗大战 -- 使用函数

# 例3:人狗大战
def Person(name, sex, hp, dps): # 人模子
    dic = {'name': name, 'sex': sex, 'hp':hp, 'dps': dps, 'bag': []}
    return dic
def Dog(name, kind, hp, dps): # 人模子
    dic = {'name': name, 'kind': kind, 'hp':hp, 'dps': dps, 'bag': []}
    return dic

alex = Person('alex', 'N/F', 250, 5)
ha2 = Dog('2哈', '哈士奇', 15000, 200)

# 人打狗
def attack(person_name, dog_name, person_dps, dog_hp):
    print('%s打了%s,%s掉了%s点血,剩余%s点血' % (person_name, dog_name, dog_name, person_dps, dog_hp-person_dps))

attack(alex['name'], ha2['name'], alex['dps'], ha2['hp'])
# alex打了2哈,2哈掉了5点血,剩余14995点血
# 说明人狗大战的时候,需要输入的参数过多,不好调用

例4:简化人狗大战函数

# 例4:简化人狗大战函数
def Person(name, sex, hp, dps): # 人模子
    dic = {'name': name, 'sex': sex, 'hp':hp, 'dps': dps, 'bag': []}
    return dic
def Dog(name, kind, hp, dps): # 人模子
    dic = {'name': name, 'kind': kind, 'hp':hp, 'dps': dps, 'bag': []}
    return dic

alex = Person('alex', 'N/F', 250, 5)
ha2 = Dog('2哈', '哈士奇', 15000, 200)

# 人打狗
def attack(person, dog):
    dog['hp'] -= person['dps']
    print('%s打了%s,%s掉了%s点血,剩余%s点血' % (person['name'], dog['name'], dog['name'], person['dps'], dog['hp']-person['dps']))

# 狗咬人
def bite(dog, person):
    person['hp'] -= dog['dps']
    print('%s咬了%s,%s掉了%s点血,剩余%s点血' % (dog['name'], person['name'], person['name'], dog['dps'], person['hp']-person['dps']))

attack(alex, ha2)
# alex打了2哈,2哈掉了5点血,剩余14990点血
attack(alex, ha2)
# alex打了2哈,2哈掉了5点血,剩余14985点血

bite(ha2, alex)
# 2哈咬了alex,alex掉了200点血,剩余45点血

# 异常展示
attack(ha2, alex)
# 2哈打了alex,alex掉了200点血,剩余-350点血
# 说明:虽然这已经满足了我们的需求,但是还是出现 狗打人 人咬狗的错误

例5:升级:将打狗变为人的特有功能,将咬人变为狗的特有功能

# 例5:--升级,将打狗变为人的特有功能,将咬人变为狗的特有功能
def Person(name, sex, hp, dps):
    dic = {'name': name, 'sex': sex, 'hp': hp, 'dps': dps, 'bag': []}
    def attack(dog):
        dog['hp'] -= dic['dps']
        print('%s打了%s,%s掉了%s点血,剩余%s点血' % (dic['name'], dog['name'], dog['name'], dic['dps'], dog['hp']))
    dic['attack'] = attack
    return dic


def Dog(name, kind, hp, dps):
    dic = {'name': name, 'kind': kind, 'hp': hp, 'dps': dps}
    def bite(person):
        person['hp'] -= dic['dps']
        print('%s咬了%s,%s掉了%s点血,剩余%s点血' % (dic['name'], person['name'], person['name'], dic['dps'], person['hp']))
    dic['bite'] = bite
    return dic

# 创建人物alex,狗ha2
alex = Person('alex', 'N/F', 250, 5)
ha2 = Dog('2哈', '哈士奇', 15000, 200)

# 人打狗
alex['attack'](ha2)
# alex打了2哈,2哈掉了5点血,剩余14995点血
# 狗咬人
ha2['bite'](alex)
# 2哈咬了alex,alex掉了200点血,剩余50点血

思路总结:

1. 面向过程思想
  创建一个人
  创建一个狗
  人打狗 -- 函数
  狗咬人 -- 函数
2.面向对象思想
  造模子 -- 面向对象
  规范了一类角色的属性项目、属性的名字、技能的名字
  权限 有一些函数 只能是这个角色才能拥有 才能使用

2.初识类的语法                                                      

类 :具有相同属性和相同方法(技能、动作)的一类事物 组成一个类

对象 :具体的某一个具有实际属性和具体动作的一个实体

类是抽象的

对象是具体的

类被创造出来 就是模子 是用来描述对象的

类的编写格式

class 类名:
    静态属性 = 123
    # def 动态属性(self): pass # 就是函数
    def 动态属性(self):
        # 在类中的方法的一个默认的参数,但也只是一个形式参数
        # 约定必须叫self
        print(self)
# 说明
#  类中的变量 -- 静态属性
#  类中的函数 -- 动态属性
# 只要是类中的名字 不管是变量还是函数名 都不能在类的外部直接调用
# 只能通过类名来使用它

类的第一个功能:查看属性

# 只要是类中的名字 不管是变量还是函数名 都不能在类的外部直接调用
# 只能通过类名来使用它
# 1- 查看类的属性
print(类名.__dict__) # 类中必要的默认值之外 还记录了程序员在类中定义的所有名字
# {'__module__': '__main__', '静态属性': 123, '动态属性': <function 类名.动态属性 at 0x0000023F9EB91158>, '__dict__': <attribute '__dict__' of '类名' objects>, '__weakref__': <attribute '__weakref__' of '类名' objects>, '__doc__': None}
# 查看静态属性
print(类名.静态属性)
# 123

# 2- 修改静态属性
类名.静态属性 = 123345
print(类名.静态属性)
# 123345

# 3- 增加静态属性
类名.静态属性2 = 2345
print(类名.静态属性2)
# 2345

# 4- 删除静态属性
del 类名.静态属性2
print(类名.静态属性2)
# AttributeError: type object '类名' has no attribute '静态属性2'
# 查看动态属性
# 类名可以查看某个方法,但是一般情况下 我们不直接使用类名来调用方法
print(类名.动态属性)
# <function 类名.动态属性 at 0x00000206B5E61158>
类名.动态属性(1)
# 1

类的第二个功能:实例化(创造对象)

# 函数名的第一个字母一定是要小写的
# 类名的第一个字母一定要大写的
class Person:pass

alex = Person()
# 对象 = 类名() # 实例化的过程
print(alex)
# <__main__.Person object at 0x0000023BCFE70B00>
# __main__ -- 当前文件
print(Person)
# <class '__main__.Person'>

给对象添加属性

# 查看alex的属性
print(alex.__dict__)
# {}
# 给alex添加属性
alex.__dict__['name'] = 'alex'
alex.__dict__['sex'] = '不详'
alex.__dict__['hp'] = 250
alex.__dict__['dps'] = 5
alex.__dict__['bag'] = []
print(alex.__dict__)
# {'name': 'alex', 'sex': '不详', 'hp': 250, 'dps': 5, 'bag': []}

# 简化方法
alex.name = 'alex' # 给alex对象添加属性
alex.hp = 250
alex.dps = 5
alex.sex = '不详'
alex.bag = []
print(alex.__dict__)
# {'name': 'alex', 'hp': 250, 'dps': 5, 'sex': '不详', 'bag': []}

实例化的过程

# 类名()就是实例化
# 在实例化的过程中 发生了很多事情是外部看不到的
# 1.创建了一个对象
# 2.自动调用__init__方法,进行初始化
# 3.这个被创造的对象会被当作实际参数 传到__init__方法中,并且传给第一个参数self
# 执行init方法中的内容

初始化和在外部使用对象来调用属性

# 初识化和在外部使用对象来调用属性
class Person:
    def __init__(self):
        self.name = 'alex'
        self.hp = 250
        self.dps = 5
        self.sex = '不详'
        self.bag = []
升级
class Person:
    def __init__(self,name,hp,dps,sex):
        self.name = name
        self.hp = hp
        self.dps = dps
        self.sex = sex
        self.bag = []

alex = Person('alex',250,5,'N/A') # 参数个数必须与__init__参数相对应
print(alex.__dict__)
# {'name': 'alex', 'hp': 250, 'dps': 5, 'sex': 'N/A', 'bag': []}
print(alex.name)
# alex

使用面向对象的方式编写人狗大战代码

class Person:
    def __init__(self, name, hp, dps, sex):
        self.name = name
        self.hp = hp
        self.dps = dps
        self.sex = sex
        self.bag = []
    def attack(self,dog):
        dog.hp -= self.dps
        print('%s打了%s,%s掉了%s点血,剩余%s点血' % (self.name, dog.name, dog.name, self.dps, dog.hp))

class Dog:
    def __init__(self,name,kind,hp,dps):
        self.name = name
        self.hp = hp
        self.kind = kind
        self.dps = dps
    def bite(self, person):
        person.hp -= self.dps
        print('%s咬了%s,%s掉了%s点血,剩余%s点血' % (self.name, person.name, person.name, self.dps, person.hp))

alex = Person('alex', 250, 5, 'N/A')
ha2 = Dog('2哈', '哈士奇', 15000, 200)
# Person.attack(alex)
# 简化的方式
# alex.attack(ha2) #Person.attack(alex)
alex.attack(ha2)
alex.attack(ha2)
alex.attack(ha2)
# alex打了2哈,2哈掉了5点血,剩余14995点血
# alex打了2哈,2哈掉了5点血,剩余14990点血
# alex打了2哈,2哈掉了5点血,剩余14985点血
ha2.bite(alex)
ha2.bite(alex)
ha2.bite(alex)
# 2哈咬了alex,alex掉了200点血,剩余50点血
# 2哈咬了alex,alex掉了200点血,剩余-150点血
# 2哈咬了alex,alex掉了200点血,剩余-350点血
# 说明:对象名.方法名 相当于调用一个函数,这个函数默认把对象名作为第一个参数传入函数
# 剩余的其他参数根据我的需求可以随意传

例:使用面向对象的思想编写已知半径,计算圆的面积和周长

from cmath import pi
class Circle:
    def __init__(self, radius):
        self.radius = radius
    def area(self):
        return pi * self.radius ** 2
    def perimeter(self):
        return 2 * pi * self.radius

a = Circle(5)
print(a.area())
# 78.53981633974483
print(a.perimeter())
# 31.41592653589793
# 程序运行过程:自上至下一次执行
from cmath import pi # 1- 导入模块
class Circle:  # 2- 创建类Circle,在内存中开辟一块内存空间,记录类中的名字__init__,area,perimet
    # 3- 加载__init__
    def __init__(self, radius): # 7- 创建对象,在内存中开辟一块内存空间(self) radius=5
        self.radius = radius
    # 4- 加载area
    def area(self):
        return pi * self.radius ** 2
    # 5- 加载perimeter
    def perimeter(self):
        return 2 * pi * self.radius
# 6- 实例化
c1 = Circle(5)  # 8- 赋值
# c1.area() ==> Circle.area(c1)
print(c1.area())
# 78.53981633974483
# c1.perimeter() ==> Circle.perimeter(c1)
print(c1.perimeter())
# 31.41592653589793

面向对象的好处:

  每一个角色都有属于自己的属性和方法

  高可扩展性: 可以方便添加属性和方法

  可读性/规范性

不好的:

  结局不可控性

3.类的命名空间                                                      

类有自己的命名空间

对象也有自己的命名空间

对象能不能访问类的命名空间?  --- 可以

类能不能访问对象的命名空间?  --- 不可以

# 运行过程分析
class Person: # 1- 定义类Person
    COUNTRY = '中国人' # 2- 定义变量
    def __init__(self, name): # 3- 定义__init__
        self.name = name # 5-  8- 执行__init__
# 4- 实例化alex ==> Person('alex')
# 6- 赋值
alex = Person('alex')
# 7- 实例化egon ==> Person('egon')
# 9- 赋值
egon = Person('egon')

print(alex.name)
# alex
print(egon.name)
# egon

class Person:
    COUNTRY = '中国人'
    def __init__(self, name):
        self.name = name
    def eat(self):
        print('%s在吃面包' % self.name)

alex = Person('alex')
egon = Person('egon')
alex.eat() # Person.eat(alex)
# alex在吃面包
print(Person.name)
# AttributeError: type object 'Person' has no attribute 'name'
# 当一个类在创建一个实例的时候 就产生了一个这个实例和类之间的联系
# 可以通过实例 对象找到实例化它的类
# 但是 类不能找到它的实例化     

测试:

# 例1: 类的命名空间分析
class Person:
    COUNTRY = '中国人'
    def __init__(self, name):
        self.name = name
    def eat(self):
        print('%s在吃面包' % self.name)

alex = Person('alex')
egon = Person('egon')
print(alex.COUNTRY)
# 中国人
alex.COUNTRY == '印度人'
print(alex.COUNTRY)
print(egon.COUNTRY)
print(Person.COUNTRY)
# 中国人
# 中国人
# 中国人

# 例2: 类的命名空间分析
class Person:
    COUNTRY = ['中国人']
    def __init__(self, name):
        self.name = name
    def eat(self):
        print('%s在吃面包' % self.name)

alex = Person('alex')
egon = Person('egon')
print(alex.COUNTRY)
# ['中国人']
alex.COUNTRY[0] = '印度人'
print(alex.COUNTRY)
print(egon.COUNTRY)
print(Person.COUNTRY)
# ['印度人']
# ['印度人']
# ['印度人']

# 说明
# 在访问变量的时候,都显示用自己命名空间中的,如果自己的空间中没有,再到类的空间中去找
# 在使用对象修改该静态变量的过程中,相当于在自己的空间中创建了一个新的变量
# 在类的静态变量(大家都需要的变量)的操作中 应该使用类名来直接进行操作(不应该用对象名修改) 就不会出现乌龙问题

4.组合                                                             

组合 一个类的对象作为另一个类对象的属性

# 例1: 添加武器类
class Person:
    def __init__(self, name, hp, dps, sex):
        self.name = name
        self.hp = hp
        self.dps = dps
        self.sex = sex
        self.bag = []
    def attack(self,dog):
        dog.hp -= self.dps
        print('%s打了%s,%s掉了%s点血,剩余%s点血' % (self.name, dog.name, dog.name, self.dps, dog.hp))

class Dog:
    def __init__(self,name,kind,hp,dps):
        self.name = name
        self.hp = hp
        self.kind = kind
        self.dps = dps
    def bite(self, person):
        person.hp -= self.dps
        print('%s咬了%s,%s掉了%s点血,剩余%s点血' % (self.name, person.name, person.name, self.dps, person.hp))

class Weapon:
    def __init__(self, name, price, dps):
        self.name = name
        self.price = price
        self.dps = dps
    def kill(self, dog):
        dog.hp -= self.dps

# 给alex装备一个武器
# 肉包子打狗
alex = Person('alex', 250, 5, 'N/A')
ha2 = Dog('2哈', '哈士奇', 15000, 200)
roubaozi = Weapon('肉包子', 600000, 10000)
alex.money = 1000000
if alex.money >= roubaozi.price:
    alex.weapon = roubaozi
    alex.weapon.kill(ha2)
    print(ha2.__dict__)
# {'name': '2哈', 'hp': 5000, 'kind': '哈士奇', 'dps': 200}
# 例2: 常见使用实例
# 基础数据类型 都是类
# 'alex' : str的对象
print(alex.name) # => 'alex'
# 组合
print(alex.name.startswith('a'))
# True
# 例3: 圆形类 -- 圆环类
# 组合 求圆环的面积和周长

from cmath import pi
class Circle:
    def __init__(self,r):
        self.r = r
    def area(self):
        return pi * self.r ** 2
    def primeter(self):
        return 2 * pi * self.r

class Annulus:
    def __init__(self, outr, inr):
        self.outr = outr
        self.inr = inr
    def area(self):
        return Circle(self.outr).area() - Circle(self.inr).area()
    def primeter(self):
        return Circle(self.outr).primeter() + Circle(self.inr).primeter()

a = Annulus(5, 3)
print(a.area())
print(a.primeter())

总结 : 组合是描述了一种什么有什么的关系 圆环有圆 人有武器

5.继承                                                            

为什么会出现继承?

class Person:
    def __init__(self, name, hp, dps, sex):
        self.name = name
        self.hp = hp
        self.dps = dps
        self.sex = sex
        self.bag = []
    def attack(self,dog):
        dog.hp -= self.dps
        print('%s打了%s,%s掉了%s点血,剩余%s点血' % (self.name, dog.name, dog.name, self.dps, dog.hp))

class Dog:
    def __init__(self,name,kind,hp,dps):
        self.name = name
        self.hp = hp
        self.kind = kind
        self.dps = dps
    def bite(self, person):
        person.hp -= self.dps
        print('%s咬了%s,%s掉了%s点血,剩余%s点血' % (self.name, person.name, person.name, self.dps, person.hp))

仔细观察上面的代码,你会发现在定义Person/Dog类的时候都创建了name/hp/dps属性,这样就出现了多个类的冗余,所以就引入了继承

继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可以成为基类或超类,新建的类成为派生类或子类

继承的分类

# 单继承
class Parent:pass
class Son(Parent):pass
print(Son.__bases__) # 查看父类
# (<class '__main__.Parent'>,)

# Son类 继承 Parent类
# 父类 基类 超类 -- Parent类
# 子类 派生类 -- Son类

# 多继承
class Parent1:pass
class Parent2:pass

class Son(Parent1,Parent2):
    pass
print(Son.__bases__) # 查看父类
# (<class '__main__.Parent1'>, <class '__main__.Parent2'>)

含有继承关系的类的实例化过程

class Animal:
    def __init__(self, name, hp, dps):
        print('---->')
        self.name = name
        self.hp = hp
        self.dps = dps

class Person(Animal):pass
class Dog(Animal):pass

alex = Person('alex', 250, 5)
# ---->
ha2 = Dog('哈士奇', 15000, 200)
# ---->
print(alex.__dict__)
# {'name': 'alex', 'hp': 250, 'dps': 5}
print(ha2.__dict__)
# {'name': '哈士奇', 'hp': 15000, 'dps': 200}
# 每当实例化发生的时候发生
# 1. 创建了一个对象 ---> 该对象由子类创建
# 2. 把我创建的对象传给__init__
# 3. 把子类创建的对象传给父类__init__的self
# 4. 执行__init__
# 5. 把self返回给alex

类的内存空间的查找顺序

先找对象的内存空间 -> 再找创建这个对象的类的内存空间 -> 父类的

class Animal:
    def __init__(self, name, hp, dps):
        print('---->')
        self.name = name
        self.hp = hp
        self.dps = dps

class Person(Animal):
    def __init__(self, name, hp, dps):
        print('*****')

alex = Person('alex', 250, 5)
# *****
# 说明: 对象在使用名字的时候,先在子类Person中已经找,如果找到就不到父类Animal中找了

派生属性: 子类添加自己的新的属性或者在自己这里重新定义这些属性(不会影响到父类), 但是需要注意,一旦重新定义了自己的属性且父类重名,那么调用新增的属性时,就以自己为准了

# 派生属性
class Animal:
    def __init__(self, name, hp, dps):
        print('---->')
        self.name = name
        self.hp = hp
        self.dps = dps

class Person(Animal):
    def __init__(self, name, hp, dps, sex):
        # Animal.__init__(self, name, hp, dps)
        super().__init__(name, hp ,dps)  #super(Person, self).__init__(name, hp ,dps)
        self.sex = sex     # 派生属性
class Dog(Animal):
    def __init__(self, name, hp, dps, kind):
        Animal.__init__(self, name, hp, dps)
        super().__init__(name, hp ,dps)
        self.kind = kind   # 派生属性

alex = Person('alex', 250, 5, 'N/A')
ha2 = Dog('2哈', 15000, 200, '哈士奇')
print(alex.__dict__)
# {'name': 'alex', 'hp': 250, 'dps': 5, 'sex': 'N/A'}
print(ha2.__dict__)
# {'name': '哈士奇', 'hp': 15000, 'dps': 200}

子类重复的方法 重复的属性都放到父类中,子类特有的方法放到子类中

#
class Animal:
    def __init__(self, name, hp, dps):
        print('---->')
        self.name = name
        self.hp = hp
        self.dps = dps
    def eat(self):
        print('%s吃药回血了' % self.name)
class Person(Animal):
    def __init__(self, name, hp, dps, sex):
        # Animal.__init__(self, name, hp, dps)
        super().__init__(name, hp ,dps)  #super(Person, self).__init__(name, hp ,dps)
        self.sex = sex     # 派生属性
    def attack(self,dog):
        dog.hp -= self.dps
        print('%s打了%s,%s掉了%s点血,剩余%s点血' % (self.name, dog.name, dog.name, self.dps, dog.hp))

class Dog(Animal):
    def __init__(self, name, hp, dps, kind):
        Animal.__init__(self, name, hp, dps)
        self.kind = kind   # 派生属性
    def bite(self, person):
        person.hp -= self.dps
        print('%s咬了%s,%s掉了%s点血,剩余%s点血' % (self.name, person.name, person.name, self.dps, person.hp))

alex = Person('alex', 250, 5, 'N/A')
ha2 = Dog('哈士奇', 15000, 200, 'zangao')
print(alex.__dict__)
# {'name': 'alex', 'hp': 250, 'dps': 5, 'sex': 'N/A'}
print(ha2.__dict__)
# {'name': '哈士奇', 'hp': 15000, 'dps': 200}
alex.eat()
# alex吃药回血了
ha2.eat()
# 哈士奇吃药回血了
alex.attack(ha2)
# alex打了哈士奇,哈士奇掉了5点血,剩余14995点血
ha2.bite(alex)
# 哈士奇咬了alex,alex掉了200点血,剩余50点血

测试题

class Foo:
    def __init__(self):
        self.func()
    def func(self):
        print('in Foo')

class Son(Foo):
    def func(self):
        print('in Son')

Son() 
# in Son
# Son() 实例化,创建对象self
# 执行父类Foo的init
# 调用self.func方法,按照--'先找对象的内存空间 -> 创建这个对象的类的内存空间 -> 父类的'的原则
# 所以,先找Son中的func,输出 in Son

6.多继承                                                           

python中有两种类

  经典类 py3已经灭绝了, 在py2里还存在,在py2中只要程序员不主动继承object,这个类就是经典类 -- 深度优先算法

  新式类 py3所有的类都是新式类,所有的新式类都继承自object -- 在多继承中遵循广度优先算法

python3
class A:
    def f(self):
        print('in A')

class B(A):
    def f(self):
        print('in B')

class C(A):
    def f(self):
        print('in C')

class D(B):
    def f(self):
        print('in D')

class E(C):
    def f(self):
        print('in E')

class F(D,E):
    def f(self):
        print('in F')

print(F.mro()) # 查看继承顺序,遵循广度优先原则, 如图
# [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

super和找父类这件事是两回事

在单继承中  super就是找父类

在多继承中  super的轨迹是根据整个模型的起始点而展开的一个广度优先顺序 遵循mro规则

# 例:
class A:
    def f(self):
        print('in A')

class B(A):
    def f(self):
        print('in B')
        super().f()

class C(A):
    def f(self):
        print('in C')
        super().f()

class D(B,C):
    def f(self):
        print('in D')
        super().f()

d = D()
d.f()
# in D
# in B
# in C
# in A

继承的总结:

继承的作用

  减少代码的重用

  提高代码的可读性

  规范编码模式

名词说明

  抽象: 抽象即抽取类似或者说比较像的部分, 是一个从具体到抽象的过程

  继承: 子类继承了父类的方法和属性

  派生: 子类在父类方法和属性的基础上产生了新的方法和属性

钻石继承

  新式类: 广度优先

  经典类: 深度优先

7.多态                                                                        

在python中处处都是多态

在java(强数据类型语言)定义函数/执行函数参数都要表明参数的数据类型

# java 强数据类型语言
# def func(int a, str b, dic c):pass
# func(1, 'x', {'a':'b'})

在python(弱数据类型语言)中,定义函数/执行函数是参数不要求数据类型就可以执行

class Person():pass

alex = Person()
# 每个对象对应的数据类型,就是对象对应的类
print(type(alex)) # 类型是Person
# <class '__main__.Person'>
print(type('123'))
# <class 'str'>
print(type(123))
# <class 'int'>

猜你喜欢

转载自www.cnblogs.com/gnaix/p/9041220.html
今日推荐