标签:打包 属性 第一个 类别 error method 父类 执行 key
# 看一个继承的例子
class Person:
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age
class Cat:
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age
class Dog:
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age
# 是不是很麻烦,我们来看一下继承
class Animal:
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age
class Person(Animal):
pass
class Cat(Animal):
pass
class Dog(Animal):
pass
# Aminal叫做父类,基类,超类
# Person Cat Dog: 子类,派生类
class Animal(object):
type_name = '动物类'
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age
def eat(self):
print(self)
print('吃东西')
class Person(Animal):
pass
class Cat(Animal):
pass
class Dog(Animal):
pass
# 类名:
print(Person.type_name) # 可以调用父类的属性,方法
Person.eat(1)
------------------------------------------------
# 对象:
# 实例化对象
p1 = Person('元始天尊', '男', 18)
print(p1.__dict__)
# 对象执行类的父类的属性,方法
print(p1.type_name)
p1.type_name = '666'
print(p1.type_name)
p1.eat()
# 执行顺序
class Animal(object):
type_name = '动物类'
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age
def eat(self):
print(self)
print('吃东西')
class Person(Animal):
def eat(self):
print(f'{self.name}吃饭')
class Cat(Animal):
pass
class Dog(Animal):
pass
p1 = Person('太上老君', '男', 18)
# 实例化对象时必须执行__init__方法,类中没有,父类没有,从object类中找
p1.eat()
# 先要执行自己类中的eat方法,自己类没有才能执行父类中的方法
# 方法一:
# 如果想执行父类的func方法,这个方法并且子类中也有,那么就在子类的方法中写上: 父类.func(对象,其他参数)
class Animal(object):
type_name = '动物类'
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age
def eat(self):
print(self)
print('吃东西')
class Person(Animal):
def __init__(self, name, sex, age, mind):
Animal.__init__(self, name, sex, age) # 方法一
self.mind = mind
def eat(self):
print(f'{self.name}吃饭')
class Cat(Animal):
pass
class Dog(Animal):
pass
p1 = Person('孙悟空', '男', 18, '有思想')
print(p1.__dict__)
-------------------------------------------------
# 方法二: 利用super,super().func(参数)
class Animal(object):
type_name = '动物类'
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age
def eat(self):
print(self)
print('吃东西')
class Person(Animal):
def __init__(self, name, sex, age, mind):
# super(Person, self).__init__(name, sex, age) # 方法二
super().__init__(name, sex, age) # 方法二
self.mind = mind
def eat(self):
print(f'{self.name}吃饭')
class Cat(Animal):
pass
class Dog(Animal):
pass
p1 = Person('嫦娥', '女', 18, '有思想')
print(p1.__dict__)
super的作用:在子类中调用父类的方法,可以避免直接使用父类的名字
# 例
class God:
def __init__(self, name):
self.name = name
def fly(self):
print('会飞')
def climb(self):
print('神仙也会爬树')
class Monkey:
def __init__(self, sex):
self.sex = sex
def climb(self):
print('会爬树')
class MonkeySun(God, Monkey): # 多继承
pass
sun = MonkeySun('孙悟空')
sun.climb()
sun.fly()
# 虽然在python3中已经不存在经典类了,但是经典类的MRO最好还是学一下,这是树形结构遍历的一个最直接的案例,在python的继承体系中,我们可以把类与类继承关系画成一个树形结构的图
class A:
pass
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
class E:
pass
class F(D, E):
pass
class G(F, D):
pass
class H:
pass
class Foo(H, G):
pass
print(Foo.mro())
# 查找原则: 在经典类中采用的时深度优先遍历方案,就是一条路走到头,然后再回来,继续找下一个
# MRO是一个有序列表L,在类被创建时就计算出来,计算公式为:
mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
# (其中Child继承自Base1, Base2)
--------------------------------------------------------------
# 如果继承至一个基类: class B(A)
# 这时B的mro序列为
mro(B) = mro( B (A) )
= [B] + merge( mro(A) + [A] )
= [B] + merge( [A] + [A] )
= [B,A]
--------------------------------------------------------------
# 如果继承至多个基类: class B(A1,A2,A3...)
# 这时B的mro序列
mro(B) = mro( B(A1,A2,A3...))
= [B] + merge( mro(A1),mro(A2),mro(A3)...,[A1,A2,A3] )
= ...
# 计算结果为列表,列表中至少有一个元素,即类自己,如上述示例[A1,A2,A3],merge操作是C3算法的核心
--------------------------------------------------------------
# 表头和表尾
# 表头: 列表的第一个元素
# 表位: 列表中表头以外的元素集合(可以为空)
# 示例: 列表[A,B,C] 表头是A,表尾是B和C
# 列表之间的+操作: [A] + [B] = [A,B]
--------------------------------------------------------------
# 示例: 计算merge( [E,O], [C,E,F,O], [C] )
# 1. merge不为空,取出第一个列表[E,O]的表头E,进行判断,各个列表的表尾分别是[O],[E,F,O]
# 因为E在这些表尾的集合中,因而跳过当前列表
# 2. 取出第二个列表[C,E,F,O]的表头C,进行判断,各个列表的表尾分别是[O],[E,F,O]
# 因为C不在这些表尾的集合中,因而将C拿出到merge外,并将所有表头为C的删除
# merge( [E,O], [C,E,F,O], [C] ) = [C] + merge( [E,O], [E,F,O])
# 3. 进行下一次新的merge操作...
? 把很多数据封装到?个对象中. 把固定功能的代码封装到?个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情况具体分析.对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容。
# 封装: 顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容
# 第一步: 将内容封装到某个地方
class Foo:
def __init__(self, name, age):
self.name = name
self.age = age
def detail(self):
print(self.name)
print(self.age)
obj1 = Foo('小红', 18)
obj2 = Foo('小花', 18)
# 内容被封装到了对象obj1和obj2中,每个对象中都有name和age属性
---------------------------------------------------------
# 第二步: 从某处调用被封装的内容
# 通过对象直接调用
print(obj1.name)
print(obj2.name)
# 通过self间接调用被封装的内容
obj1.detail()
class A:
def f1(self):
print('in A f1')
def f2(self):
print('in A f2')
class B:
def f1(self):
print('in A f1')
def f2(self):
print('in A f2')
# A和B两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准
# 对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互称为鸭子类型
# 公司让小明给他们的网站完善一个支付功能,小明写了两个类,如下:
# 版本一
class QQpay:
def pay(self, money):
print(f'使用qq支付{money}元')
class Alipay:
def pay(self, money):
print(f'使用阿里支付{money}元')
a = Alipay()
a.pay(100)
b = QQpay()
b.pay(200)
--------------------------------------------------------
# 但是这样不统一,整改如下:
# 版本二
class QQpay:
def pay(self, money):
print(f'使用qq支付{money}元')
class Alipay:
def pay(self, money):
print(f'使用阿里支付{money}元')
def pay(obj, money): # 这个函数就是统一支付规则: 归一化设计
obj.pay(money)
a = Alipay()
b = QQpay()
pay(a, 100)
pay(b, 200)
-------------------------------------------------------
# 过了一段时间,换成了新人小周,新加一个微信支付功能
# 版本三
class QQpay:
def pay(self, money):
print(f'使用qq支付{money}元')
class Alipay:
def pay(self, money):
print(f'使用阿里支付{money}元')
class Wechatpay:
def fuqian(self, money):
print(f'使用微信支付{money}元')
def pay(obj, money):
obj.pay(money)
a = Alipay()
b = QQpay()
c = Wechatpay() # 改变了支付方式,又不统一了
pay(a, 100)
pay(b, 200)
c.fuqian(300)
------------------------------------------------------
# 小周受惩罚,改代码:
# 版本四
class QQpay(Payment):
def pay(self, money):
print(f'使用qq支付{money}元')
class Alipay(Payment):
def pay(self, money):
print(f'使用阿里支付{money}元')
class Wechatpay(Payment):
def pay(self, money):
print(f'使用微信支付{money}元')
def pay(obj, money):
obj.pay(money)
a = Alipay()
b = QQpay()
c = Wechatpay()
pay(a, 100)
pay(b, 100)
pay(c, 100)
# 但是以后再换人还可能出现同样的问题
-------------------------------------------------------
# 在一些重要的逻辑,与用户数据相关等核心部分,我们要建立一种约束,避免此种错误
# 所以此时我们要用到对类的约束,对类的约束有两种:
# 1. 提取父类,然后在父类中定义好方法,在这个方法中什么都不用干,就抛出一个异常就可以了这样所有的子类必须重写这个方法,否则访问的时候就会报错
# 2. 使用元类来描述父类,在元类中给出一个抽象方法,这样子类就不得不给出抽象方法的具体实现,也可以起到约束的效果(硬性约束)
-------------------------------------------------------
# 先用第一种方式解决:
class Payment:
def pay(self, money): # 约定俗成定义一种规范,子类要定义pay方法
raise Exception('你没有实现pay方法')
class QQpay(Payment):
def pay(self, money):
print(f'使用QQ支付{money}元')
class Alipay(Payment):
def pay(self, money):
print(f'使用阿里支付{money}元')
class Wechatpay(Payment):
def fuqian(self, money):
print(f'使用微信支付{money}元')
def pay(obj, money):
obj.pay(money)
a = Alipay()
b = QQpay()
c = Wechatpay()
pay(a, 100)
pay(b, 200)
pay(c, 300) # 报错: Exception: 你没有实现pay方法
# 但是可以绕过
c.fuqian(300)
-------------------------------------------------------
# 第二种方式: 引入抽象类的概念处理
from abc import ABCMeta
from abc import abstractmethod
class Payment(metaclass=ABCMeta): # 抽象类,接口类,规范和约束,metaclass指定的是一个元类
@abstractmethod
def pay(self, money): # 抽象方法
pass
class QQpay(Payment):
def pay(self, money):
print(f'使用QQ支付{money}元')
class Alipay(Payment):
def pay(self, money):
print(f'使用阿里支付{money}元')
class Wechatpay(Payment):
def fuqian(self, money):
print(f'使用微信支付{money}元')
def pay(obj, money):
obj.pay(money)
a = Alipay()
b = QQpay()
c = Wechatpay()
# 报错: TypeError: Can't instantiate abstract class Wechatpay with abstract methods pay
# 基类如上设置,子类如果没有定义pay方法,在实例化对象时就报错
pay(a, 100)
pay(b, 200)
-------------------------------------------------------
# 总结: 约束,其实就是父类对子类进行约束,子类必须要写XXX方法,在python中约束的方式和方法有两种
# 1. 使用抽象类和抽象方法,由于该方案来源是java和C#,所以使用频率还是很少的
# 2. 使用人为抛出异常的方案,并且尽量抛出的是NotImplementError.这样错误比较明确
class A:
def f1(self):
print('in A f1')
def f2(self):
print('in A f2')
class Foo(A):
def f1(self):
super().f2()
print('in A Foo')
obj = Foo()
obj.f1()
# in A f2
# in A Foo
-----------------------------------------------------
class A:
def f1(self):
print('in A')
class Foo(A):
def f1(self):
super().f1()
print('in Foo')
class Bar(A):
def f1(self):
print('in Bar')
class Info(Foo, Bar):
def f1(self):
super().f1()
print('in Info')
print(Info.mro()) # Info Foo Bar A object
obj = Info()
obj.f1()
# in Bar
# in Foo
# in Info
----------------------------------------------------
class A:
def f1(self):
print('in A')
class Foo(A):
def f1(self):
super().f1()
print('in Foo')
class Bar(A):
def f1(self):
print('in Bar')
class Info(Foo, Bar):
def f1(self):
super(Foo, self).f1() # Foo的下个类
print('in Info')
obj = Info()
obj.f1()
# in Bar
# in Info
标签:打包 属性 第一个 类别 error method 父类 执行 key
原文地址:https://www.cnblogs.com/douzi-m/p/11941131.html