(12条消息) 常用的魔法方法
魔法方法
- __dict__动态绑定属性
- __enter__和__exit__用来生成上下文管理器
- __get__与__set__属性描述符-----给类属性添加控制条件
- __getattr__与__getattribute__添加替补实例属性
- __gt__实例对象直接比较大小
- __init__初始化
- __iter__() 返回一个可迭代对象
- __mro__查看继承顺序
- __new__创建实例对象
- __next__() 会返回下一个迭代器对象
- __slots__节省内存
- __str__自定义实例对象打印内容
__dict__动态绑定属性
功能:
- 查当前属性,父类的查不到
- 返回的是字典,可以对它增删改,就是动态改属性
要点:
- 当为数据描述符是,get__优先级高于__dict
当为非数据描述符时,dict__优先级高于__get
__enter__和__exit__用来生成上下文管理器
_enter_
- 必须返回self return self
_exit_
- _exit_(异常类型,异常值,追溯信息) 三个参数必须加上
- 如果加了return True 有异常出现的话不会报错
作用
- 自动完成清理工作,无须手动干预
- 在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处
简化Demo()语句,添加装饰器,但是只能装在函数上
__get__与__set__属性描述符-----给类属性添加控制条件
定义
- 属性描述符是一个强大的通用协议,它是properties、methods、static methods、class methods、和super()调用原理
- 属性描述符是实现了特定协议的类
- 实现了__get__、__set__或__delete__中任意一个方法的类,称之为属性描述符。属性描述符可以控制属性操作时的一些行为。
- 只要具有__get__方法的类就是描述符类。是非数据描述符
如果一个类中具有__get__和__set__两个方法,那么就是数据描述符。
作用
- 描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)
- 它能实现对多个属性运用相同存取逻辑,通俗来说就是:创建一个实例,作为另一个类的属性
- 就是给属性添加条件的
数据查询顺序:
- 描述符设置为类属性
- 如果有同名实例属性:外部设置的值>属性描述符
- 没有同名的实例属性:属性描述符>动态绑定设置实例属性的值__dict__
- 这里是和普通类属性的区别,普通类属性是一定会被实例属性设置的值覆盖的
- 属性描述符设置为实例属性
- 和普通属性一样,外部优先为实例属性的值
- 没有控制条件的效果
创建
- 使用类方法创建描述符
- 定义各异IntField类为描述符
创建IntField类的实例,作为另一个User类的属性
- 定义各异IntField类为描述符
__getattr__与__getattribute__添加替补实例属性
定义
__getattr__是当类调用一个不存在的属性时才会调用 __getattr__魔法函数,它传入的值item就是你这个调用的不存在的值,赋值后就会变成实例属性
getattribute__则是无条件的有限执行,所有属性都会被覆盖,访问不到__getattribute__以外的其他属性的值,输出的一直都是__getattribute,所以如果不是特殊情况最好不要用__getattribute__
对比属性描述符
- 相同:都是想企图调用没有初始化的属性
- 区别:
- __getattr__赋值成功后就会变成实例属性,就是类里面加这个方法
- 属性描述符可以设置类属性,实例属性不用,没有效果
作用
- 防止没有定义的实例属性直接被访问会报错,这样有一个兜底的效果
__gt__实例对象直接比较大小
- 四种不同比较
- __gt__大于:greater than
__ge__大于等于:greater equal
__lt__小于:less than
__le__小于等于:less equal
- __gt__大于:greater than
- 如何实现四种大小比较:
- 如果想写的少的话,可以只写两个方法,但要么是__gt__和__le__或__ge__和__lt__
- 添加装饰器 from functooling import total_ordering 任意一个方法加@total_ordering
__init__初始化
- 不能添加不定长参数
- 引入__init__方法的原因,因为按之前的写法,信息暴露外面,不安全,而且像这样只能一个一个传参,如果可以在类创建是时候就可以把信息传进去,不用调用方法传进去
2.__init__方法 称为初始化方法,也称为构造方法。在创建对象时,会自动执行该方法,为对象的属性设置初始值,所以在该变量里所赋予的属性已经变成了该实例的公用属性,类似类实例,但仅仅针对该实例下
- 即使没有调用__init__方法,还是打印的,会自动执行该方法
- __init__的传参是在类里面传递的 lz=Student('lz’,1) 形参有多少个在类里也要传几个
注意:
- (1)__init__方法可以像函数一样有自定义返回值吗?
- 不可以,不能用return返回值,但是可以用其他函数
- (2)在没有调用该方法的时候,可以调用这__init__方法里面的属性吗?
- 可以,在创建类的时候会自动调用该代码
注意:
类的内部中,除了init方法,其他方法定义属性的属性都需要对象对该方法调用了,才可以访问里面的属性
- 可以,在创建类的时候会自动调用该代码
iter() 返回一个可迭代对象
有了这个方法对象就是可迭代对象
- __iter__可以返回一个可迭代对象
__mro__查看继承顺序
- 类属性
- 允许类查看
__new__创建实例对象
- 由于__new__比__init__先执行,只有对象创建了,才会自动调用初始化方法
- 对于不可变对象会自动创建对象
- 可以修改__new__将类变成单例模式等
next() 会返回下一个迭代器对象
- 有了__next__()的,可迭代对象就会变成迭代器
- 没有iter,类也可以一个一个取数据,就是不是迭代器不能用for循环
__slots__节省内存
- 关闭动态绑定__dict__
__slots__是只读模式,所以也不能给它写入属性值
__slots__是不会继承,不影响子类实例,不会继承,除非子类里面自己定义了
如何创建大量实例节省内存
- 练习需求
在游戏开发中,有一个玩家类Player,每有一个玩家,在服务器内侧有一个player的实例,当在线的人数很多时,将产生大量实例(百万级) - 解决方案:
- 定义类的__slots__属性,声明实例有哪些属性(关闭动态绑定dict,关闭后也不能动态添加dict属性)
- __dict__返回字典,可以对字典进行,动态为p添加属性、删除属性’,会非常占内存
- 添加了 __slots__后,就不能通过dict查属性,也不能通过dict添加属性,不能动态绑定
__str__自定义实例对象打印内容
- 返回值必须是字符串类型
赞 (0)