__init_subclass__
https://docs.python.org/3/reference/datamodel.html#object.__init_subclass__python 3.6 新增。
父类派生子类后会调用该方法,方法中 cls 指向派生出的子类。
- 若
__init_subclass__被定义为普通方法,将会被隐式转换为类方法,故不必使用@classmethod装饰器 - metaclass 不会被传给
__init_subclass__ - 传给一个新类的关键字参数会被传给父类的
__init_subclass__。为保证与父类__init_subclass__兼容,应当将关键字参数中仅子类__init_subclass__需要的参数去掉后再传入父类__init_subclass__
class base:
def __init_subclass__(cls, /, name, **kwargs):
super().__init_subclass__(**kwargs)
print("base __init_subclass__ called")
cls.x = {}
cls.name = name
class a(base, name="jack"):
def __init__(self):
super().__init__()
print("a __init__ called")
def __new__(cls, *args, **kwargs):
super().__new__(cls)
print("a __new__ called")
print(a.x)
print(a.name)
# base __init_subclass__ called
# {}
# jack
class a:
def __init__(self):
super().__init__()
print("a __init__ called")
def __new__(cls, *args, **kwargs):
super().__new__(cls)
print("a __new__ called")
@classmethod
def __init_subclass__(cls, **kwargs):
super().__init_subclass__()
print(kwargs)
print("a __init_subclass__ called")
class b(a, bbb=12):
def __init__(self):
super().__init__()
print("b __init__ called")
def __new__(cls, *args, **kwargs):
super().__new__(cls)
print("b __new__ called")
def __init_subclass__(cls, **kwargs):
super().__init_subclass__()
print("b __init_subclass__ called")
class c(b, ccc=12):
def __init__(self):
super().__init__()
print("c __init__ called")
def __new__(cls, *args, **kwargs):
super().__new__(cls)
print("c __new__ called")
def __init_subclass__(cls, **kwargs):
super().__init_subclass__()
print("c __init_subclass__ called")
__class_getitem__
__class_getitem__方法的目的是允许标准库泛型类的运行时形参化以更方便地对这些类应用 类型提示。
- 若
__class_getitem__被定义为普通方法,将会被隐式转换为类方法,故不必使用@classmethod装饰器 __class_getitem__方法应当返回一个 genericalias 类型
https://docs.python.org/3/reference/datamodel.html#object.__class_getitem__
from typing import list
class a:
def __class_getitem__(cls, item):
print(item)
return "abc"
print(a[0])
if __name__ == '__main__':
int_arr_type = list[int]
list1: int_arr_type = [1]
list2: int_arr_type = []
print(int_arr_type)
__instancecheck__与__subclasscheck__
__instancecheck__可以自定义实例检查逻辑__subclasscheck__可以自定义子类检查逻辑
from typing import any
class meta(type):
def __instancecheck__(self, instance: any) -> bool:
print("instance check")
print(instance)
return true
def __subclasscheck__(self, subclass: type) -> bool:
print("subclass check")
print(subclass)
if subclass is int:
return true
return false
class a(metaclass=meta):
pass
o = a()
print(isinstance(123, a))
print()
print(issubclass(int, a))
# instance check
# 123
# true
#
# subclass check
# <class 'int'>
# true__prepare__
https://peps.python.org/pep-3115
python 3.0 新增。
__prepare__用于为类准备命名空间。
__prepare__定义在元类中并且必须被显式定义为类方法__prepare__方法返回一个映射对象- python 执行类定义语句,会首先调用其元类
__prepare__方法,获得一个映射对象,该映射对象会被作为该类的命名空间,类的属性和方法会被存储在该映射对象中,随后映射对象会成为该类的__dict__属性。
import collections
from typing import any, mapping
# 创建一个 ordereddict 对象作为字典
global_dict = collections.ordereddict()
global_dict["global_dict_name"] = "global_dict"
class mymeta(type):
@classmethod
def __prepare__(metacls, __name: str, __bases: tuple[type, ...], **kwargs: any) -> mapping[str, object]:
print(metacls, __name, __bases, kwargs)
return global_dict
class myclass(metaclass=mymeta):
a = 1
b = 2
c = 3
print(myclass.__dict__)
print("global_dict_name" in myclass.__dict__)
# <class '__main__.mymeta'> myclass () {}
# {'global_dict_name': 'global_dict', '__module__': '__main__', '__firstlineno__': 18, 'a': 1, 'b': 2, 'c': 3, '__static_attributes__': (), '__dict__': <attribute '__dict__' of 'myclass' objects>, '__weakref__': <attribute '__weakref__' of 'myclass' objects>, '__doc__': none}
# true
__mro_entries__
https://docs.python.org/3/reference/datamodel.html#object.__mro_entries__
若某个类的父类不是type的实例(此时父类就是一个普通对象),则定义该类时其基类会被替换为父类中定义的__mro_entries__方法的返回值,若父类中没有定义__mro_entries__方法,此时类的定义会报错attributeerror: 'xxx' object has no attribute 'mro',因为无法进行mro。
class a1:
...
class a2:
def __mro_entries__(self, bases):
return (dict,)
class b1(a1):
print(type(a1), type(a1) is type)
...
class b2(a2()):
print(type(a2()), type(a2()) is not type)
...
print(b1.mro())
print(b2.mro())
# <class 'type'> true
# <class '__main__.a2'> true
# [<class '__main__.b1'>, <class '__main__.a1'>, <class 'object'>]
# [<class '__main__.b2'>, <class 'dict'>, <class 'object'>]到此这篇关于python 冷门魔术方法小结的文章就介绍到这了,更多相关python 冷门魔术方法内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论