构造函数
是一种特殊的方法。主要用来在创建对象时初始化对象
析构函数
析构函数(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 r
obj = 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()] = value
logger(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 self
def 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 r
def __del__(self):
print("我是__del__")
obj = Foo() # 实例化对象后触发__new__(),返回实例化对象,再触发__init__()
obj2 = obj
del 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 = name
print("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 = name
self._score = score
@property
def score(self):
return self._score
@score.setter
def score(self, value):
print("setting score here")
if isinstance(value, int):
self._score = value
else:
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__")
# 新增 key
self[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 = value
def __hash__(self):
return hash(self.value)
a = TestHash(1)
s = set()
s.add(a)
print(a in s) # True
# 因为定义使用了value的哈希值来作为对象的哈希值,修改了value属性,a对象的哈希值也随之改变了
a.value = 2
print(a in s) # Fals