Python冷门魔术方法小结

作者:

文章目录
  • 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__被定义为普通方法,将会被隐式转换为类方法,故不必使用@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__可以自定义子类检查逻辑 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
  • 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
  • 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 冷门魔术方法内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!  您可能感兴趣的文章: 一文带你探索Python中15个常见的魔术方法 深入理解Python虚拟机中魔术方法的使用 深入理解Python虚拟机中常见魔术方法的使用 Python魔术方法深入分析讲解 python深入讲解魔术方法 python进阶之魔术方法详解 Python类型转换的魔术方法详解 Python魔术方法专题 Python魔术方法详解
  • 目录
    • __init_subclass__
    • __class_getitem__
    • __instancecheck__与__subclasscheck__
    • __prepare__
    • __mro_entries__

    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__被定义为普通方法,将会被隐式转换为类方法,故不必使用@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__可以自定义子类检查逻辑
    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

    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
    

    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 冷门魔术方法内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客! 

    您可能感兴趣的文章:

    • 一文带你探索Python中15个常见的魔术方法
    • 深入理解Python虚拟机中魔术方法的使用
    • 深入理解Python虚拟机中常见魔术方法的使用
    • Python魔术方法深入分析讲解
    • python深入讲解魔术方法
    • python进阶之魔术方法详解
    • Python类型转换的魔术方法详解
    • Python魔术方法专题
    • Python魔术方法详解

    站内搜索