面向对象

class 关键字

类方法

 class MyClass:
     def __init__(self):
         pass
     
     @classmethod
     def foo(cls):
         return cls.__name__
     # 通过@classmethod装饰函数, 函数此时叫类方法(第一个cls参数是固定的)
     # 类方法的第一个参数是类的本身,在执行该函数的时候解析器会帮我们吧类传递进入函数

静态方法

 class MyClass:
     def __init__(self):
         pass
     
     @staticmethod
     def foo():
         pass
     # 通过staticmethod装饰函数, 该函数为静态方法; 参数自定义
     # 静态方法特性
     # 无需创建实例即可调用
     # 在类中可以用 self.foo() 进行调用

属性装饰器

 class MyClass:
     def __init__(self):
         self.name = 'LiHua'
         self.age = 12
         
     @property
     def foo(self):
         return '{}-{}'.format(self.name, self.age)
     # 属性
 instance = MyClass()
 print(instance.foo)
 # 返回 "LiHua-12"
 # 像调用属性一样调用他
 """
     class C(object):
         @property
         def x(self):
             "I am the 'x' property."
             return self._x
         @x.setter
         def x(self, value):
             self._x = value
         @x.deleter
         def x(self):
             del self._x
 """
 # 要想操作内容需要按照以上示例
 # 

内置方法

 class Test:
     def __new__(cls, *args, **kwargs):
         # 执行init之前执行的方法
         pass
 
     def __init__(self):
         # 初始化函数
         pass
 
     def __exit__(self, exc_type, exc_val, exc_tb):
         # 退出函数 一般用于 with
         pass
 
     def __enter__(self):
         # 进入函数 一般用于 with
         return self

访问控制

私有属性

 # 双下划线为私有属性
 class MyClass:
     def __init__(self):
         self._desc = 'This is Desc' 
         # 单下划线也是私有属性,但是这只是程序员的一种约定,python不会对其进行限制
         # 一般情况下对于私有的变量,我们不会想办法去修改,因为破坏了封装的思想
         self.name = 'tom'
         self.__age = 10
     
     def set_age(self, val):
         if val > 0 and val < 150:
            self.__age = 30
     def get_age(self):
         return self.__age
     
 instance = MyClass()
 # 双下划线可以实现私有的属性
 # 但是还是可以通过实例的__dict__修改值
 # 私有变量的本质: 类定义的时候,如果声明一个实例变量的时候, 使用双下划线, Python解释器会将其 改名 ,转换为'_类名__变量名', 所有用当初定义的私有变量名就访问不到了
 # 单下划线意味不要随意修改

私有成员总结

在python中使用_单下划线或__双下划线来标识一个成员被保护或者被私有化隐藏起来

但是不管什么样的访问控制,你总是能够找到他,因为python的特性.所有对于私有成员,只能起一个警告的作用,这个警告同时也被大家所遵守

删除方法

 class Test:
     def __init__(self):
         pass
     # 删除是时候做的操作
     def __del__(self):
         pass

方法重载

Python中没有方法重载,只有覆盖

运算符重载

 class MyClass:
     def __init__(self):
         pass
     def __str__(self):
         # 强制类型转换
         pass
     def __int__(self):
         # 强制类型转换
         pass
     def __add__(self):
         # 加法运算符重载
         pass
     def __lt__(self):
         pass
     def __gt__(self):
         pass
     # ...

单例类

 # 

继承

父类,子类,派生

父类: 可以叫做 基类, 超类

子类: 可以叫做 子类, 继承类

派生就是继承的意思,从某类中派生出一个类

 class 子类名(基类,[基类1, 基类2, ...]):
     """语句块"""
 # 支持多继承, 但是多继承是一个比较麻烦的东西,使用的时候需要格外的注意
 

一些特殊的属性和方法

名称含义示例
__base__类的基类
__bases__类的基类元组
__mro__显示方法查找顺序,基类的元组
mro()同上int.mro()
__subclasses__类的子类列表int.__subclasses`

在继承的时候关于__init__中为什么要执行super函数?

如果在子类没有写出__init__初始化函数, 解释器会调用父类的__init__方法,如果在子类定义了__init__方法,那么需要调用super函数执行父类的__init__方法,如果不执行父类的初始化方法, 父类的属性将不会绑定到当前实例.

 class Person:
     def __init__(self, name, age, height):
         self.name = name
         self.age = age
         self.height = height
 
     def eat(self):
         raise NotImplemented
 
 
 class Man(Person):
     def __init__(self, *args, **kwargs):
         self.run = True
         pass
         # super(Man, self).__init__(*args, **kwargs)
 
     def test(self):
         print('------')
         print(self.__dict__)
         print('-------')
 man = Man('Tom', 18, 180)
 man.test() # ==> self.__dict__ = {'run': True} 
 # 可以看到上面的例子,字典中只有一个数据,父类的name,arg,heigth都不没有
 # 原因就是没有执行父类的初始化方法
 # 取消注释 super(Man, self).__init__(*args, **kwargs) 即可正常绑定属性
 # 其实这个过程就是吧父类的一些属性绑定到当前的实例 self
 # 等价式
 # super(Man, self).__init__(*args, **kwargs) <==> Person.__init__(self, *args, **kwargs)

覆盖/重写

子类如果定义了和父类一个同名的方法或属性,就会被直接覆盖.调用的时候是直接调用子类的方法或属性

如果一个方法在子类中被覆盖了,那么如何调用父类的方法呢?

 class Animal:
     def __init__(self, name):
         self.name = name
     def shout(self):
         print('animal-----')
    
 class Cat(Animal):
     def shout(self):
         print('cat--------')
         # 如果在本方法中想要调用父类的方法
         super(Cat, self).shout()
         # 

一套方法有多种不同的调用方法就是多态, 多态是通过继承和覆盖实现的

用类实现装饰器

 class Wraps:
     def __init__(slef, function):
         self.target = function
     def __call__(self, *args, **kwargs):
         return self.target(*args. **kwargs)
 # 带参装饰器
 class Wraps:
     def __init__(self, name, age):
         self.name = anem
         self.arg = age
        
     def call(self, *args, **kwargs):
         print(self.name)
         print(self.arg)
         return self.target(*args, **kwargs)
     
     def __call__(self, function):
         self.target = function
         return self.call

多继承

  1. OCP原则: 多继承,少修改
  2. 继承的用途: 增强基类, 实现多态

多继承的弊端

多继承很好的模拟了世界, 因为事物很少是单一继承的,但是舍弃简单, 必然引入复杂性, 带来了冲突.

如同一个孩子继承自父亲和母亲,那么该孩子的眼睛到底是像父亲还是母亲,以及像母亲多一点还是像父亲多一点呢?

多继承的实现会导致编译器设计的复杂度增加,所以很多语言也舍弃了类的多继承

解决方案: 实现多继承的语言,要解决二义性, 深度优先或广度优先 (继承树)

python使用MRO(method resolution order)解决基类搜索顺序问题

MRO搜索算法

  1. 经典算法,按照定义从左到右, 深度优先策略. 2.2版本之前
  2. 新式类算法, 经典算法的升级, 重复的只保留最后一个. 2.2版本
  3. C3算法,在类被创建出来的时候,就计算一个MRO有序列表, 2.3之后,python3唯一支持的算法; C3算法解决多继承的二义性

关于继承

不建议使用多继承

Mixin

功能增强

 class Mixin:
     def show(self):
         print('Show')
         
 class Print:
     def __init__(self, content):
         self.content = content
     
     def show(self):
         print(self)
         
  # 增强的对象, 增强class往左边放
  class MyPrint(Mixin, Print):
     pass
 
 # 对于类的增强
 # 1. 修改类
 # 2. 继承类
 # 3. 装饰器绑定方法, 属性
 # 3. Mixin多继承方式
 
 # UML 设计模式 书籍

Mixin类的使用原则

  • Mixin类中不应该显式的出现__init__初始化方法
  • Mixin类通常不能独立工作, 因为它是准备混入别的类中的部分功能实现
  • Mixin类的祖先类也应该是Mixin类

使用时, Mixin类通常在继承列表的第一位置, 例如classPrintWord(PrintMinix, Word): pass

最后修改:2021 年 06 月 04 日 04 : 56 PM
如果觉得我的文章对你有用,请随意赞赏