构造函数
是一种特殊的方法。主要用来在创建对象时初始化对象
析构函数
析构函数(destructor) 与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作
构造函数init()
实例化对象后自动触发,在__new__之后执行,且无返回值
构造函数new()
- 实例化对象时触发,在init之前执行,调用用于创建一个cls类的实例。
参数:cls必填,代表要实例化的类 返回值:必须返回值,返回实例化出来的实例,实例化对象取决于new方法返回了什么东西
class Foo:def __init__(self):print("我是init方法")def __new__(cls, *args, **kwargs):print('我是new方法')r = super(Foo, cls).__new__(cls)return robj = Foo()print(obj)-------------------#我是new方法#我是init方法#<__main__.Foo object at 0x0000024666434BC8>
- 如果要得到当前类的实例,应当在当前类中的new()方法语句中调用当前类的父类的new()方法
- 如果当前类是直接继承object,当前类的new()方法返回的对象应该为:
def __new__(cls, *args, **kargs):...return object.__new__(cls)
典型的实现例如:super().new(cls,[, ….]) ,通过超类的new()方法来创建一个类的新实例,然后再根据修改新创建的实例再将其返回
class TestMetaClass(type):def __new__(cls, class_name, class_parents, class_attr):logger("this meteclass __new__ func")new_attr = {}# 将类中非__开头的属性、方法等,名称修改为大写for name, value in class_attr.items():logger(f"name={name}, value={value}")if not name.startswith("__"):new_attr[name.upper()] = valuelogger(f"new_attr:{new_attr}")# 调用基类type 的__new__方法返回return super(TestMetaClass, cls).__new__(cls, class_name, class_parents, new_attr)class B(metaclass=TestMetaClass):def __init__(self, *args, **kwargs):logger("this is class __init__ func")super().__init__()def __new__(cls, *args, **kwargs):logger("this is class __new__ func")self = super().__new__(cls)return selfdef func1(self):logger("this is class instance func")B()B().FUNC1()# [I 220520 18:03:01 debug:47] this meteclass __new__ func# [I 220520 18:03:01 debug:50] name=__module__, value=__main__# [I 220520 18:03:01 debug:50] name=__qualname__, value=B# [I 220520 18:03:01 debug:50] name=__init__, value=<function B.__init__ at 0x7f6107b77ae8># [I 220520 18:03:01 debug:50] name=__new__, value=<function B.__new__ at 0x7f6107b77b70># [I 220520 18:03:01 debug:50] name=func1, value=<function B.func1 at 0x7f6107b77bf8># [I 220520 18:03:01 debug:50] name=__classcell__, value=<cell at 0x7f6108413198: empty># [I 220520 18:03:01 debug:53] new_attr:{'FUNC1': <function B.func1 at 0x7f6107b77bf8>}# [I 220520 18:03:01 debug:72] this is class instance func
析构方法 del()
对象被系统回收的时候自动触达(del不一定触发),无返回值
class Foo:def __init__(self):print("我是__init__")def __new__(cls, *args, **kwargs):print('我是new方法')r = super(Foo, cls).__new__(cls)return rdef __del__(self):print("我是__del__")obj = Foo() # 实例化对象后触发__new__(),返回实例化对象,再触发__init__()obj2 = objdel obj #不会触发__del__,__del__总是会在程序的最后触发print("测试是否是最后执行")-----------------------#我是new方法#我是__init__#测试是否是最后执行#我是__del__
call()
当对象像函数一样可以被调用,就相当于是调用它的call()方法
class C(A, B):def __init__(self):print("enter C")super(C, self).__init__()print("leave C")def __call__(self, *args, **kwargs):print("我是call方法")c = C()c() 当对象实例被调用==调用对象call方法-----------#enter C#leave C#我是call方法
str()
返回对象的描述信息
class C(A, B):def __init__(self, name):self.name = nameprint("enter C")super(C, self).__init__()print("leave C")def __str__(self):return "我叫{}".format(self.name)
dict
dict可用来查看数据对象的相关属性,且只包含自己的属性,可以直接增、删、改、查dict
dict与dir()的区别:
dir()是显示属性的包含显示,出了显示自己的,也包括继承来的属性
class A:def __init__(self, name, score):self.name = nameself._score = score@propertydef score(self):return self._score@score.setterdef score(self, value):print("setting score here")if isinstance(value, int):self._score = valueelse:print("please input an int")if __name__ == '__main__':#查看类属性print(AA.__dict__.keys()) # dict_keys(['__module__', 'm', '__dict__', '__weakref__', '__doc__'])print(dir(AA)) # ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'm']#查看类实例属性a = AA()print(a.__dict__.keys()) # dict_keys([])print(dir(a)) # ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'm']
missing()
获取字典key,不存在时会调用此魔术方法
class TestDict(dict):# 其他代码,省略def __missing__(self, key):print("call __missing__")# 新增 keyself[key] = "default"# 返回该项return "default"a = TestDict()print(a["a"])# call __missing__# default
认识hash() 的危险性
重写hash() 方法时,必须保证方法产生的哈希值是稳定的,不会随对象状态而改变 就像定义dataclasses 是指定frozen=True
class TestHash(object):def __init__(self, value: int = 0):self.value = valuedef __hash__(self):return hash(self.value)a = TestHash(1)s = set()s.add(a)print(a in s) # True# 因为定义使用了value的哈希值来作为对象的哈希值,修改了value属性,a对象的哈希值也随之改变了a.value = 2print(a in s) # Fals
