Python 中的元类

MetaClass in Python

我正在尝试为我的 Class 创建一个 Meta-Class。 我试图在 meta-class

中打印关于我的 class 的信息

现在我已经为 class 创建了两个对象 但是创建第二个对象时没有引用我的 Meta-Class

Meta Class 每个 Class 只调用一次吗??

任何帮助将不胜感激

谢谢

class Singleton(type):
    def __new__(cls,name,bases,attr):
        print (f"name {name}")
        print (f"bases {bases}")
        print (f"attr {attr}")
        print ("Space Please")

        return super(Singleton,cls).__new__(cls,name,bases,attr)

class Multiply(metaclass = Singleton):
    pass
     
objA = Multiply()
objB = Multiply()

print (objA)
print (objB)

是 - 只有在创建 class 时才调用 metaclass 的 __new____init__ 方法。之后,在您的示例中,class 将绑定到 Multiply 名称。在许多方面,它就像 Python 中的任何其他对象一样。当您执行 objA = Multiply() 时,您并不是在创建 type(Multiply) 的新实例,它是元 class - 您正在创建 Multiply 本身的新实例:Multiply.__new__Multiply.__init__ 被调用。

现在,有这样的:Python 中的机制在创建实例时调用 __new____init__ 是元 class __call__方法。也就是说,就像当您使用 __call__ 方法创建任何 class 并将其实例与调用语法 obj() 一起使用时,将调用 type(obj).__call__(obj),当您执行 Multiply() 所谓的(在这种情况下)是 Singleton.__call__(Multiply)。 由于未实现,因此调用了 Singleton 的 superclass,即 type __call__ 方法 - 正是在其中调用了 Multiply.__new____init__ .

就是说,上面的代码中没有任何内容会使您的 classes 表现得像“单例”。 更重要的是您不需要元class就可以在Python中拥有一个单例。这个东西不知道是谁发明的,一直在流传。

首先,如果你真的需要一个单例,你需要做的就是写一个普通的class,没有什么特别的,创建你的单例,然后记录应该使用该实例。正如人们使用 None 一样 - 没有人会不断获得对 Nonetype 的引用并不断调用它来获得 None 引用:

class _Multiply:
   ...

# document that the code should use this instance:
Multiply = _Multiply()

second 或者,如果您的代码需要实例化 class 应该是将要使用的单例,您可以使用class' __new__ 方法本身来控制实例化,不需要 metaclass:


class Multiply:
     _instance = None
     def __new__(cls):
         if not cls._instance:
             cls._instance = super().__new__(cls)    
             # insert any code that would go in `__init__` here:
             ...
             ...
         return cls._instance

Third只是为了演示,不要使用这个,metaclass机制有单例可以在 __call__ 方法中构建:

class Singleton(type):
    registry = {}
    def __new__(mcls,name,bases,attr):
        print(f"name {name}")
        print(f"bases {bases}")
        print(f"attr {attr}")
        print("Class created")
        print ("Space Please")

        return super(Singleton,mcls).__new__(cls,name,bases,attr)
    
    def __call__(cls, *args, **kw):
        registry = type(cls).registry
        if cls not in registry:
            print(f"{cls.__name__} being instantiated for the first time")
            registry[cls] = super().__call__(*args, **kw)
        else:
            print(f"Attempting to create a new instance of {cls.__name__}. Returning single instance instead")
        return registry[cls]
        

class Multiply(metaclass = Singleton):
    pass