(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类的属性

__getattr__与__getattribute__添加替补实例属性

定义

  • __getattr__是当类调用一个不存在的属性时才会调用 __getattr__魔法函数,它传入的值item就是你这个调用的不存在的值,赋值后就会变成实例属性

  • getattribute__则是无条件的有限执行,所有属性都会被覆盖,访问不到__getattribute__以外的其他属性的值,输出的一直都是__getattribute,所以如果不是特殊情况最好不要用__getattribute__

对比属性描述符

  • 相同:都是想企图调用没有初始化的属性
  • 区别:
    • __getattr__赋值成功后就会变成实例属性,就是类里面加这个方法
    • 属性描述符可以设置类属性,实例属性不用,没有效果

作用

  • 防止没有定义的实例属性直接被访问会报错,这样有一个兜底的效果

__gt__实例对象直接比较大小

  • 四种不同比较

    • __gt__大于:greater than
      __ge__大于等于:greater equal
      __lt__小于:less than
      __le__小于等于:less equal
  • 如何实现四种大小比较:
    • 如果想写的少的话,可以只写两个方法,但要么是__gt__和__le__或__ge__和__lt__
    • 添加装饰器 from functooling import total_ordering 任意一个方法加@total_ordering

__init__初始化

  • 不能添加不定长参数
  1. 引入__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)

相关推荐