init()
结构和作用与PHP中的__construct大同小异
函数结构
def init(self, [*args]):# code is there
self.args = args
......
函数作用
对类中的属性进行一个初始化
说明
在内存空间开辟完成后, 会对类中的属性进行一个初始化。在面对继承了超类的子类时可以不用重写__init__方法, 在实例化子类的同时会自动调用超类中的__init__方法。
new()
在接触到__new__之前先接触了__init__魔术方法, 以为__init__就是在魔术方法中最先会被执行的那个(初始化类属性)。
后面了解到了__new__这个魔术方法,以为它就是PHP中__wakeup + __construct的一个集合体, 但是在仔细了解过后才发现它的功能不仅限于此。
函数结构:
def new(cls, [*args]):# code is there
instance = super().new(cls)
return instance
至少要有一个cls属性来接收实例化后的类
函数作用:
对类进行一个实例化, 开辟内存空间, 主要用来控制对实例的创建
说明
实例化对象, 并在内存中开辟空间, 实例化的对象可以是其他的类。相对于__init__的对象初始化, __new__则是对对象的一个创建。
如果类中同时存在__new__魔术方法和__init__魔术方法, __new__方法将先于__init__执行(第一顺位执行); 如果要得到当前类的实例, 应当在当前类的__new__方法中调用当前类的父类的__new__方法, 对其中的__new___进行重写。如果当前类直接继承自object的话则应当 return object.new(cls);
在创建一个对象时, 首先执行类中的__new__方法, 通常执行的结构是
super(ClassName, Type).__new__(Type, [*args...])
而后再通过类中的__init__去初始化类中的属性
repr()
作用同__str__, 区别在于使用场景, __str__在终端输出, __repr__在交互式终端输出
函数结构
def repr(self):# code is there
return something
函数作用
说明
在没有定义此函数时, 直接打印对象会返回一个<__main__.ClassName object at 0xaddress>
格式的字符串, 此处调用的就是在Object类中写好的__repr__方法, 在类中定义的__repr__实际上就是对object中__repr__方法的一种重写。
如果同时存在__str__和__repr__函数, 则在交互式终端时优先执行__repr__函数, __str__函数不执行。
str()
同__repr__
函数结构
def str(self):# code is there
return something
函数作用
按照需求在终端打印对象时返回指定的字符串
说明
如果同时存在__str__和__repr__函数, 则在终端时优先执行__str__函数, __repr__函数不执行。
del()
作用同php中的__destruct函数
函数结构
def del(self):# code is there
......
函数作用
当对象被手动或者自动销毁时触发
说明
Python中的GC机制与PHP中的相似, 都是引用计数为0自动回收内存, 只不过Python在回收资源时是按照字典顺序进行内存回收, 而不是创建顺序。所以当系统回收资源是会按照类名A-Za-z的顺序依次进行,且此流程无法掌控。
在循环引用__del__魔术方法的时候, 容易造成垃圾内存导致不可回收。消耗系统资源, 但Python中的GC机制可以通过设置gc.set_debug(gc.DEBUG_LEAK)来对循环引用的内存泄露进行检查,确保不会出现内存泄露的情况。
call()
作用同php中的__invoke()
函数结构
def call(self, [*args]):# code is there
return something
函数作用
当对象被当作函数被调用的时候触发
说明
当类中实现了__call__方法时, ObjectName() 等价于 ObjectName.call()
getattr()
同php中的__get()
函数结构
def getattr(self, [*args]):# code is there
......
函数作用
当获取不存在的对象属性时触发
说明
当属性在__dict__中不被定义导致查找失败的话, 那么在最后就会尝试去调用__getattr__方法作为一个最后被调用的方法。如果类中并没有实现此魔术方法则会抛出AttributeError的异常。
在某些时候或许需要实现一个外部传参的动态定义,此时使用__getattr__来对属性进行定义可以极大的简化此实现过程。
示例
def load(name): # 动态实现的code return 'Content of ' + name class Lazy2(object): def __init__(self): self.__data = {} def __getattr__(self, name): if name not in self.__data: self.__data[name] = load(name) return self.__data[name] def __setattr__(self, name, value): if not name.startswith('_'): raise AttributeError("can't set attribute") object.__setattr__(self, name, value) lazy2 = Lazy2() print(lazy2.first) # 定义了一个first的属性, 属性值和属性名以字典的格式存放在__data中 print(lazy2.__dict__)
setattr()
区别于php中的__set(), python中的__setattr__只要是对类中的属性进行赋值就会被触发,包括__init__中对属性进行初始化时也一样。
函数结构
def setattr(self, key, value): # 除去self以外 至少需要两个参数# code is there
......
函数作用
在对类中的属性进行赋值时触发
说明
如果在类中实现了此方法,则一定要在方法中实现对属性的注册功能, 因为在重写了此方法后对属性进行赋值时, 值并不会自动写入到__dict__中。
示例
class test: def __init__(self, name): self.name = name def __setattr__(self, key, value): self.value = value # 此处如果在__setattr__方法中又对属性进行了赋值操作则又会触发一遍__setattr__方法,导致死循环 # 正确操作应该将变量注册到__dict__中 self.__dict__[key] = value
delattr()
函数结构
def delattr(self, [*args]):# code is there
......
函数作用
在属性被删除的时候调用
说明
在__delattr__方法中也需要避免死循环的问题
示例
class test: def __init__(self, name): self.name = name def __delattr__(self, item): # 正确写法 object.__delattr__(self, item) # or self.__dict__.pop(item) # 死循环, # 当递归次数达到最大次数后会抛出RecursionError: maximum recursion depth exceeded while calling a Python object的异常 # 默认递归最大次数 -> 1000 del self.item