OOP Object Oriented Programing
面向对象是认识世界的一种方法论, 一切皆对象
类class: 抽象的概念,一类具有共同特征的事物的集合;用计算机语言来描述,就是属性和方法的集合
实例instance: 类的一个实现
属性,是对象状态的抽象
方法,是对象行为的抽象
面向对象3要素:
命名上的一些约定
类名用大驼峰,类变量用全大写
变量名加下划线后缀, 避免与保留关键字冲突
变量名加下划线前缀, 表示变量非公有,
私有属性: 双下划线开头的属性名,对象属性字典中被改名_CLASS__ATTRIBUTE
私有方法: 双下划线开头的方法名,被解释器改名_CLASS_METHOD
单下划线前缀不带保护
前后双下滑线, 系统定义的变量, 避免定义
当使用__定义属性时,保存到属性字典中的key,变成_class__attr,class为定义属性语句所处的类
当使用.__attr
访问属性时,访问的其实是._class__attr
,class为访问语句所处的类
类中的方法分类
0、也没有装饰, 没有参数的方法,实例不可调用(因为默认实例会作为参数会隐式传入),禁止使用
1、没有装饰器,至少有一个参数:self
,即此方法被实例通过属性方式调用时,隐式传入实例本身,类对象调用时,就是普通函数,self占用一个参数位置
2、@classmethod 至少一个参数:cls
,表示不管是类对象调用,还是实例调用,都隐式传入一个类对象本身,cls占用一个传参位,
常作为工厂函数,代替constructor,实例化一个需要不同参数的实例,例如rectangle 类实例化一个 square,只要一个参数 side_length
3、@staticmethod 可以没有参数,随意传参,不隐式传参
补丁:Monkey Pathch
运行时,对类的属性、方法进行动态替换,慎用,测试
把实例的属性保护起来,不让外部直接访问,外部使用getter方法访问,setter方法设置属性
属性装饰器 :property 常用来使属性read_only
@property;@method.setter;@method.deleter
Class Person:
def __init__(self, name, age=18):
self.name = name
self.__age = age
@property
def age(self):
return self.__age
@age.setter
def age(self, age):
self.__age = age
@age.deleter
def age(self):
del self.__age
tom = Person('Tom')
print(tom.age) # getter
tom.age = 20 # setter
del tom.age # deleter
Class Person:
def __init__(self, name, age=18):
self.name = name
self.__age = age
def getage(self):
return self.__age
def setage(self, age):
self.__age = age
def delage(slef):
del self.__age
age = property(getage, setage, delage, 'age property')
Class Person:
def __init__(self, name, age=18):
self.name = name
self.__age = age
age = property(lambda self: self.__age) # getter
对象的销毁
def __del__(self): print('del')
类中可以定义__del__
方法,称为析构函数(方法), 执行del
命令时调用
当对象引用计数为0时, 自动调用
类的一些特殊属性和方法
__base__
类的基类
__bases__
类的基类元组
__mro__
显示属性方法查找顺序 method resolution order,类的元组, mro() 调用
__subclasses__()
:子类的列表
对象的属性和方法都可以使用.
访问, 表示属性和对象发生了绑定
属性的访问顺序:实例自己的字典,实例所属类的字典,实例所属类的父类的字典
类中定义的属性(变量和方法)在外部看都变成了cls.attr或instance.attr,这里的外部包括类方法的内部,而在类的内部看还是attr
类的执行顺序,为从上到下,每一句都执行,语句块结束后才生成类
函数只做声明,调用时才执行
初始化函数init中,再实例化类,就会产生递归
类是语句块的最外层,只要类生成了,在当前modul中都可以访问到
继承和多态
继承加覆盖形成多态
override 覆盖
overload 重载, 例: type
函数
super类,
def __init__(self, type1=None, type2=None)
super() -> same as super(__class__owner, self)
super(type1) -> unbound super object
super(type1, obj) -> bound super object; requires isinstance(obj, type1)
super(type1, type2) -> bound super object; requires issubclass(type2, type1)
Typical use to call a cooperative superclass method:
class C(B):
def meth(self, arg):
super().meth(arg)
This works for class methods too:
class C(B):
@classmethod
def cmeth(cls, arg):
super().cmeth(arg)
用super调用type1
(第一个参数)的父类的方法(绑定或非绑定, 第二个参数),
用法: 子类的同名方法中调用父类的方法,达到增强方法的目的,类似装饰器
作为一个好的习惯,如果父类中定义了__init__
方法,你就应该在子类的__init__
中调用它
class A(B):
def __init__(self,arg):
super().__init__(arg)
Python2.2 之后引入共同祖先类object,为了兼容分为古典类(旧式类)和新式类
Python3 中全部都是新式类,新式类都继承自object,新式类可以使用super,使用超类方法
多继承
java中舍弃了多继承,java中一个类可以实现多个接口,一个接口可以继承多个接口,接口只有方法的声明
多继承可能带来二义性,解决二义性,要看深度优先还是广度优先
python3 解决多继承二义性使用C3算法,计算出一个MRO有序列表
尽量避免多继承
Mixin
定义Mixin类,只有特定方法的实现,其他类需要这些方法是,就继承Mixin类
多使用
Mixin体现的是一种组合的设计模式,多组合,把功能类独立出来复用
Mixin类的祖先类也应该是Mixin类
上下文管理
with object as foo:
进入调用__enter__(self),return值赋给foo
执行语句
退出调用__exit__(exc_type, exc_value, exc_traceback),return 等效True 就压制异常
__dir__
: dir()
函数调用,如果没有提供,尽量收集对象的属性,对象 -> 类 -> 基类属性名全部收集, list实例没有__dict__
属性,但用dir()可以找到它所有的的属性和方法__init__
, __del__
: __hash__
: hash()
调用,返回int,定义了这个方法,类的实例才可hash. __eq__
方法,来判断是否相同 __bool__
:
bool类实例化时调用,bool(),返回True or False,没有定义就找__len()__
,长度非0即为True,len方法也没实现,默认是True,只有bool() -> False
对象的特殊属性
__name__
标识符,字符串, 模块的name为A.B.C, 类名为C
__module__
所属module
__class__
实例的类,type()
__bases__
, __base__
基类tuple, 基类
__doc__
文档
__mro__
method resolution order, mro()调用
__dict__
属性字典
__qualname__
类的限定名, A.B.C
可视化
* __repr__
:
repr()
调用,返回对象的字符串表达,就按照object的定义,返回内存信息
* __str__
:
str()
,format()
,print()
调用,返回对象的字符串表达,没有定义,就去调用__repr__
* __int__
: coverting object to built-in types
* __bytes__
:
bytes(object)
调用,返回对象的bytes表达,没有定义抛TypeError
运算符重载
operator_method(self, other)
__lt__
,__le__
,__eq__
,__gt__
,__ge__
,__ne__
<, <=, ==, >, >=, !=
__add__
,__sub__
,__mul__
,__truediv__
,__mod__
,__floordiv__
,__pow__
,__divmod__
,&__and__
,|__or__
,^__xor__
__iadd__
,__isub__
,__imul__
,__itruediv__
,__imod__
,__ifloordiv__
,__ipow__
: +=, -=, *=, /=, %=,/ /=, **=
<,<=,==
,另外三种调用实现容器相关方法
* __len__
:
len()
调用,返回对象长度(>=0的整数),没有定义报TypeError
* iter
:
迭代对象时调用(for语句),返回一个新的迭代器对象,不能next()
* __contains__
:
使用in
成员运算符时调用,没有实现,就调用__iter__
方法遍历,直到迭代找到为止
* __getitem__
:
使用self[key]
访问对象时调用
* __setitem__
:
使用self[key] = value
设置对象属性是调用
* __missing__
:
字典或其子类使用self[key]
访问时,key不存在时调用,拦截KeyError异常
可调用
* __call__
:
实例被调用时调用
上下文管理
__exit__
,__enter__
:
with Point() as p:
同时实现两个方法,才属于上下文管理对象,enter
进入与此对象相关的上下文时执行,exit
退出与此对象相关的上下文时执行, 上下文管理是安全的,发生异常,__exit__
依然执行
__enter__
没有参数,返回值赋给as子句中的变量__exit__
有三个参数都与异常有关:exc_type
,exc_value
,traceback
,如果返回等效True的值,压制异常,否则继续抛出异常
上下文的应用场景:
1. 增强功能
2. 资源管理,打开资源就需要关闭,例如文件对象,网络连接,数据库连接
3. 权限验证,在__enter__
中处理
@contextlib.contextmanager
装饰器,使一个函数具有上下文管理的功能,使用方法
@contextlib.contextmanager
def foo():
print('enter')
try:
yield something # yield只能有一个,作为__enter__方法的返回值
finally:
print('exit')
反射reflection
指的是程序运行时获取定义信息,Python中,能够通过一个对象,找出其type, class, attribute, method的能力,称为反射或自省
getattr(object, name[, default])
: __getattribute__
setattr(object, name, value)
: __setattr__
hasattr(object, name)
: delattr(self, name)
: __delattr__
__setattr__
: __dict__
中.描述器例外.__delattr__
: __getattribute__
: object类
的getattribute方法,即object.__getattribute__(self, name)
,即按照默认属性查找顺序查找, object.__getattribute__(self, name)
,则属性的查找顺序不变 __getattr__
, 没有实现的话, 再抛AttributeError__getattr__
: __get__
, __set__
, __delete__
: class A ;; class B;x=A() ;; b=B()
__get__(self, instance, owner)
: B.x, b.x
访问x时调用,B访问时,instance为None __set__(self, instance, value)
: b.x=value
时调用 __delete__(self, instance)
: __get__
, __set__
, __delete__
三个方法中的任何一个,就称为一个描述器类,这个类的实例作为另一个类的属性值时, __get__
, 就是非数据描述器 non-data descriptor __set__
, 就是数据描述器 data descriptor __dict__
先于非数据描述器,数据描述器先于__dict__
,因为定义__set__
后,设置属性值的时候都会调用__set__
,而不是在__dict__
中添加,即数据描述器绑定的属性行为不能被覆盖,而非数据描述器绑定的属性行为可以(通过__setattr__
方法覆盖) classmethod
,staticmethod
,property
装饰器 __slots__
明确的定义指定的属性,保护实例不被添加其他属性,阻止__dict__
的自动创建 __dict__
可能会占用很大的空间 __slots__
继承不了 __slots__