python3_面向对象

面向对象

OOP Object Oriented Programing
面向对象是认识世界的一种方法论, 一切皆对象
类class: 抽象的概念,一类具有共同特征的事物的集合;用计算机语言来描述,就是属性和方法的集合
实例instance: 类的一个实现
属性,是对象状态的抽象
方法,是对象行为的抽象

面向对象3要素:

  1. 封装
    隐藏数据:对外只暴露一些接口,只能通过接口访问对象
    组装:将数据和操作组装在一起
  2. 继承
    多继承少修改OCP(Open-closed Principle),使用继承来改变
  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<first argument>)
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.
    字典,set用hash值做key,去重的话,要同时提供__eq__方法,来判断是否相同
    不定义虽然是hashable,但hash值不确定
  • __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__
    都有对应的r方法,当第1个参数没有实现方法是,调用第2个参数的r方法.
  • __iadd__,__isub__,__imul__,__itruediv__,__imod__,__ifloordiv__,__ipow__:
    +=, -=, *=, /=, %=,/ /=, **=
    note: 比较大小,只要实现三种就可以,例<,<=,==,另外三种调用实现

容器相关方法
* __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]):
      访问属性值,不存在则返回default,如果没有deault,抛出AttributeError, 调用的是__getattribute__
    • setattr(object, name, value):
      设置object属性值,存在则覆盖,不存在则新增,调用的__setattr__
    • hasattr(object, name):
      判断object是否存在名字为name的属性
    • delattr(self, name):
      删除对象属性,调用的是__delattr__
  • __setattr__:
    当尝试给属性赋值时调用,如果没有实现,object默认添加属性到对象的__dict__中.描述器例外.
  • __delattr__:
    删除对象属性时调用,如果不实现,object默认删除属性
  • __getattribute__:
    getattr(self,name) 和 self.attr 时调用
    如果没有实现,就执行object类的getattribute方法,即object.__getattribute__(self, name),即按照默认属性查找顺序查找,
    如果实现了同时又返回object.__getattribute__(self, name),则属性的查找顺序不变
    如果在其中抛出AttributeError,则调用__getattr__, 没有实现的话, 再抛AttributeError
  • __getattr__:
    访问对象的属性时,按照继承关系查找,查找失败要抛出AttributeE时调用,相当于设置默认值,如果没有实现,抛出AttributeError

描述器Descriptors

  • __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) :
    self是A的实例A(), instance是b, owner是B, value是设置的值
    如果一个类中实现了__get__, __set__, __delete__三个方法中的任何一个,就称为一个描述器类,这个类的实例作为另一个类的属性值时,
    如果仅实现了__get__, 就是非数据描述器 non-data descriptor
    如果同时实现了__set__, 就是数据描述器 data descriptor
    属性搜索__dict__先于非数据描述器,数据描述器先于__dict__,因为定义__set__后,设置属性值的时候都会调用__set__,而不是在__dict__中添加,即数据描述器绑定的属性行为不能被覆盖,而非数据描述器绑定的属性行为可以(通过__setattr__方法覆盖)
    描述器应用:classmethod,staticmethod,property装饰器
    描述器应用:flask作者写的网络工具werkzeug,实现缓冲器

槽位slots

  • __slots__ 明确的定义指定的属性,保护实例不被添加其他属性,阻止__dict__的自动创建
    应用场景: 实例在百万以上,实例属性简单,固定且不用动态增加,如列表节点,Poin等,使用__dict__可能会占用很大的空间
    私有属性可以被继承, __slots__ 继承不了
    使用__slots__

猜你喜欢

转载自blog.csdn.net/qq_33287645/article/details/81417266