# 商家类
class Merchants():
platform = 'python外卖平台'
def __init__(self, name, addr, tel):
self.name = name # 商家名字
self.addr = addr # 商家地址
self.tel = tel # 商家联系电话
def reveive_order(self):
print(f'{self.name}已经接单')
# 外卖小哥类
class Rider():
platform = 'python外卖平台'
def __init__(self, name, addr, tel):
self.name = name # 外卖小哥姓名
self.addr = addr # 外卖小哥配送地址
self.tel = tel # 外卖小哥电话
def distribution(self):
print(f'{self.name}正在配送')
# 顾客类
class Customer():
platform = 'python外卖平台'
def __init__(self, name, addr, tel):
self.name = name # 顾客姓名
self.addr = addr # 收货地址
self.tel = tel # 顾客电话
def accept_delivery(self):
print(f'{self.name}已经收到外卖')
以上三个类之间存在重复的代码,都属于python外卖平台,都需要独有的name、addr、tel,因此可以得出以下继承关系,实现代码重用:
class Personnel_information():
platform = 'python外卖平台'
def __init__(self, name, addr, tel):
self.name = name
self.addr = addr
self.tel = tel
# 商家类
class Merchants(Personnel_information):
def reveive_order(self):
print(f'{self.name}已经接单')
# 外卖小哥类
class Rider(Personnel_information):
def distribution(self):
print(f'{self.name}正在配送')
# 顾客类
class Customer(Personnel_information):
def accept_delivery(self):
print(f'{self.name}已经收到外卖')
商家类、外卖小哥类和顾客类中并没有定义__init__方法,但是会从它们的父类中找到__init__方法,因为子类会继承父类所有的属性和方法,因此仍然可以正常实例化:
mer = Merchants('川菜', '山清水秀区', '11111')
rider = Rider('小庄', '依山傍水区', '2222')
customer = Customer('xu', '养生区', '33333')
class Test():
def t1(self):
print('from Test t1')
class Foo(Test):
def f1(self):
print('Foo f1')
f = Foo()
f.t1
# 运行结果
from Test t1
父类如果不想让子类覆盖自己的方法,可以采用双下划线开头的方式将方法设置为私有的。
class Test():
def __t1(self):
print('from Test t1')
def t2(self):
self.__t1()
print('from Test t2')
class Foo(Test):
def __t1(self):
print('Foo t1')
f = Foo()
f.t2()
# 运行结果
from Test t1
from Test t2
多继承属性查找
Python面向对象支持多继承,好处是子类可以同时继承多个父类的属性,最大限度的重用代码,但是多继承也有很多缺点,多继承违背了继承表达的什么是什么的关系,而且如果一个类同时继承多个父类,代码的可读性就会变得很差,可能会出现菱形继承的问题。菱形继承是不同子类拥有同一个非object的父类,而不同的子类又是另一个子类的父类,如果A类中有一个方法,B类或者C类对这个方法进行了重写,D类继承的是哪个版本的方法?
>>> D.mro() # 新式类内置了mro方法可以查看线性列表的内容,经典类没有该内置该方法
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
有菱形继承问题,就会有非菱形继承,如下所示:
不管是菱形继承还是非菱形继承,只需要记住:
如果是类实例化得到的对象发起的属性查找,会从对象自身的属性里检索,没有则会按照对象的类.mro()规定的顺序依次找下去;
如果是由类发起的属性查找,会按照当前类.mro()规定的顺序依次找下去。
Mixins机制
多继承实际上提高了程序的耦合程度,但是面向对象的编程思想就是解耦合,解耦合的目的就是提高代码的可读性和可扩展性,那么到底要不要用多继承呢?
# 定义父类---交通工具类
class Vechicle:
print('我是交通工具')
# 定义飞的功能---Mixin表示该类只是作为一个功能
class FlyableMixin():
def __init__(self,fly):
self.fly = fly
class CivilAircraft(FlyableMixin, Vechicle): # 民航飞机
pass
class Helicopter(FlyableMixin, Vechicle): # 直升飞机
pass
class Bus(Vechicle):
pass
# 民航飞机对象
c = CivilAircraft('我会飞')
print(c.__dict__)
# 直升飞机对象
h = Helicopter('fly')
print(h.__dict__)
# 汽车对象
b = Bus()
print(b.__dict__)
车 、船 、直升机、民航飞机都是交通工具,但是只有飞机具有飞的功能,如果将飞的功能添加到交通工具这个父类中是不合理的,所以可以将“飞”这个功能另外定义,采用统一的命名规范(例如Mixin后缀),这个后缀会明确的告诉读代码的人,这个类是作为一个功能添加到子类中,而不是作为父类,当bus这个类混合 飞的功能,bus就是会飞的一个交通工具。
但是在使用mixins机制的时候需要注意以下几点:
1.必须表示某一种功能,而不是某类物品
2.python 对于mixin类的命名方式一般以 Mixin, able, ible 为后缀
3.如果有多个功能,那就写多个Mixin类
4.定义的Minx类越多,子类的代码可读性就会越差
class Personnel_information():
platform = 'python外卖平台'
def __init__(self, name, addr, tel):
self.name = name
self.addr = addr
self.tel = tel
# 商家类
class Merchants(Personnel_information):
def reveive_order(self):
print(f'{self.name}已经接单')
# 外卖小哥类
class Rider(Personnel_information):
def distribution(self):
print(f'{self.name}正在配送')
# 顾客类
class Customer(Personnel_information):
def accept_delivery(self):
print(f'{self.name}已经收到外卖')
print(f'{self.name}已经收到外卖')
直接继承父类属性
如上述代码,子类直接继承了父类的所有方法和属性。
class Personnel_information():
platform = 'python外卖平台'
def __init__(self, name, addr, tel):
self.name = name
self.addr = addr
self.tel = tel
# 商家类
class Merchants(Personnel_information):
def __init__(self, name, addr, tel, food_info):
self.name = name
self.addr = addr
self.tel = tel
self.food_info = food_info
def reveive_order(self):
print(f'{self.name}已经接单')
向父类索要方法
class Personnel_information():
platform = 'python外卖平台'
def __init__(self, name, addr, tel):
self.name = name
self.addr = addr
self.tel = tel
# 商家类
class Merchants(Personnel_information):
def __init__(self, name, addr, tel, food_info):
Personnel_information.__init__(self, name, addr, tel) # 向类索要方法
self.food_info = food_info # 定制自己独有的属性
def reveive_order(self):
print(f'{self.name}已经接单')
super调用父类中的属性
class Personnel_information():
platform = 'python外卖平台'
def __init__(self, name, addr, tel):
self.name = name
self.addr = addr
self.tel = tel
# 商家类
class Merchants(Personnel_information):
def __init__(self, name, addr, tel, food_info):
super().__init__(name, addr, tel) # 调用的是绑定方法,自动传入self
# super(Merchants, self).__init__(name, addr, tel) # 与上一行代码等价,但是在python2中必须这么写,python3可以简写
self.food_info = food_info
def reveive_order(self):
print(f'{self.name}已经接单')
转载请注明:XAMPP中文组官网 » python面向对象三大特性详解2-封装&继承