Loading... ## 面向对象 > 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 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 0 如果觉得我的文章对你有用,请随意赞赏