构造函数

  1. 是一种特殊的方法。主要用来在创建对象时初始化对象

析构函数

析构函数(destructor) 与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作

构造函数init()

  1. 实例化对象后自动触发,在__new__之后执行,且无返回值

构造函数new()

  1. 实例化对象时触发,在init之前执行,调用用于创建一个cls类的实例。

    参数:cls必填,代表要实例化的类 返回值:必须返回值,返回实例化出来的实例,实例化对象取决于new方法返回了什么东西

  1. class Foo:
  2. def __init__(self):
  3. print("我是init方法")
  4. def __new__(cls, *args, **kwargs):
  5. print('我是new方法')
  6. r = super(Foo, cls).__new__(cls)
  7. return r
  8. obj = Foo()
  9. print(obj)
  10. -------------------
  11. #我是new方法
  12. #我是init方法
  13. #<__main__.Foo object at 0x0000024666434BC8>
  • 如果要得到当前类的实例,应当在当前类中的new()方法语句中调用当前类的父类的new()方法
  • 如果当前类是直接继承object,当前类的new()方法返回的对象应该为:
  1. def __new__(cls, *args, **kargs):
  2. ...
  3. return object.__new__(cls)

典型的实现例如:super().new(cls,[, ….]) ,通过超类的new()方法来创建一个类的新实例,然后再根据修改新创建的实例再将其返回

  1. class TestMetaClass(type):
  2. def __new__(cls, class_name, class_parents, class_attr):
  3. logger("this meteclass __new__ func")
  4. new_attr = {}
  5. # 将类中非__开头的属性、方法等,名称修改为大写
  6. for name, value in class_attr.items():
  7. logger(f"name={name}, value={value}")
  8. if not name.startswith("__"):
  9. new_attr[name.upper()] = value
  10. logger(f"new_attr:{new_attr}")
  11. # 调用基类type 的__new__方法返回
  12. return super(TestMetaClass, cls).__new__(cls, class_name, class_parents, new_attr)
  13. class B(metaclass=TestMetaClass):
  14. def __init__(self, *args, **kwargs):
  15. logger("this is class __init__ func")
  16. super().__init__()
  17. def __new__(cls, *args, **kwargs):
  18. logger("this is class __new__ func")
  19. self = super().__new__(cls)
  20. return self
  21. def func1(self):
  22. logger("this is class instance func")
  23. B()
  24. B().FUNC1()
  25. # [I 220520 18:03:01 debug:47] this meteclass __new__ func
  26. # [I 220520 18:03:01 debug:50] name=__module__, value=__main__
  27. # [I 220520 18:03:01 debug:50] name=__qualname__, value=B
  28. # [I 220520 18:03:01 debug:50] name=__init__, value=<function B.__init__ at 0x7f6107b77ae8>
  29. # [I 220520 18:03:01 debug:50] name=__new__, value=<function B.__new__ at 0x7f6107b77b70>
  30. # [I 220520 18:03:01 debug:50] name=func1, value=<function B.func1 at 0x7f6107b77bf8>
  31. # [I 220520 18:03:01 debug:50] name=__classcell__, value=<cell at 0x7f6108413198: empty>
  32. # [I 220520 18:03:01 debug:53] new_attr:{'FUNC1': <function B.func1 at 0x7f6107b77bf8>}
  33. # [I 220520 18:03:01 debug:72] this is class instance func

析构方法 del()

对象被系统回收的时候自动触达(del不一定触发),无返回值

  1. class Foo:
  2. def __init__(self):
  3. print("我是__init__")
  4. def __new__(cls, *args, **kwargs):
  5. print('我是new方法')
  6. r = super(Foo, cls).__new__(cls)
  7. return r
  8. def __del__(self):
  9. print("我是__del__")
  10. obj = Foo() # 实例化对象后触发__new__(),返回实例化对象,再触发__init__()
  11. obj2 = obj
  12. del obj #不会触发__del__,__del__总是会在程序的最后触发
  13. print("测试是否是最后执行")
  14. -----------------------
  15. #我是new方法
  16. #我是__init__
  17. #测试是否是最后执行
  18. #我是__del__

call()

当对象像函数一样可以被调用,就相当于是调用它的call()方法

  1. class C(A, B):
  2. def __init__(self):
  3. print("enter C")
  4. super(C, self).__init__()
  5. print("leave C")
  6. def __call__(self, *args, **kwargs):
  7. print("我是call方法")
  8. c = C()
  9. c() 当对象实例被调用==调用对象call方法
  10. -----------
  11. #enter C
  12. #leave C
  13. #我是call方法

str()

返回对象的描述信息

  1. class C(A, B):
  2. def __init__(self, name):
  3. self.name = name
  4. print("enter C")
  5. super(C, self).__init__()
  6. print("leave C")
  7. def __str__(self):
  8. return "我叫{}".format(self.name)

dict

dict可用来查看数据对象的相关属性,且只包含自己的属性,可以直接增、删、改、查dict

dict与dir()的区别:
dir()是显示属性的包含显示,出了显示自己的,也包括继承来的属性

  1. class A:
  2. def __init__(self, name, score):
  3. self.name = name
  4. self._score = score
  5. @property
  6. def score(self):
  7. return self._score
  8. @score.setter
  9. def score(self, value):
  10. print("setting score here")
  11. if isinstance(value, int):
  12. self._score = value
  13. else:
  14. print("please input an int")
  15. if __name__ == '__main__':
  16. #查看类属性
  17. print(AA.__dict__.keys()) # dict_keys(['__module__', 'm', '__dict__', '__weakref__', '__doc__'])
  18. 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']
  19. #查看类实例属性
  20. a = AA()
  21. print(a.__dict__.keys()) # dict_keys([])
  22. 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,不存在时会调用此魔术方法

  1. class TestDict(dict):
  2. # 其他代码,省略
  3. def __missing__(self, key):
  4. print("call __missing__")
  5. # 新增 key
  6. self[key] = "default"
  7. # 返回该项
  8. return "default"
  9. a = TestDict()
  10. print(a["a"])
  11. # call __missing__
  12. # default

认识hash() 的危险性

重写hash() 方法时,必须保证方法产生的哈希值是稳定的,不会随对象状态而改变 就像定义dataclasses 是指定frozen=True

  1. class TestHash(object):
  2. def __init__(self, value: int = 0):
  3. self.value = value
  4. def __hash__(self):
  5. return hash(self.value)
  6. a = TestHash(1)
  7. s = set()
  8. s.add(a)
  9. print(a in s) # True
  10. # 因为定义使用了value的哈希值来作为对象的哈希值,修改了value属性,a对象的哈希值也随之改变了
  11. a.value = 2
  12. print(a in s) # Fals