Aru*_*ran 2 python methods metaclass python-3.x
我试图为我的项目和 StackOverflow 中的一个有趣的帖子实现单例类
我决定采用提到的元类方法。
现在..我尝试添加一个方法来获取和清除实例(以防用户想要摆脱当前实例并创建一个新实例..):
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
def getInstance(cls):
print("Class is {}".format(cls.__name__))
if not cls in cls._instances:
raise LookupError("No instance of the class {cls} create yet.".format(cls.__name__))
return cls._instances[cls]
def clearInstance(cls):
cls._instances.pop(cls, None)
class someClass(metaclass=Singleton):
def __init__(self,val):
self.value = val
Run Code Online (Sandbox Code Playgroud)
我能够成功创建对象..
In [9]: sc = someClass(1)
In [10]: sc.value
Out[10]: 1
Run Code Online (Sandbox Code Playgroud)
但是当我这样做时dir(someClass),两种方法都没有显示:
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
def getInstance(cls):
print("Class is {}".format(cls.__name__))
if not cls in cls._instances:
raise LookupError("No instance of the class {cls} create yet.".format(cls.__name__))
return cls._instances[cls]
def clearInstance(cls):
cls._instances.pop(cls, None)
class someClass(metaclass=Singleton):
def __init__(self,val):
self.value = val
Run Code Online (Sandbox Code Playgroud)
不过我可以调用这些方法..
In [9]: sc = someClass(1)
In [10]: sc.value
Out[10]: 1
Run Code Online (Sandbox Code Playgroud)
在所有关于元类的例子我在网上看到我看到的__new__,__init__和__call__方法来实现,但我没有看到添加任何额外的方法。向元类添加方法是否正确?
我还尝试了上述元类代码的一个小变化:
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
@classmethod
def getInstance(cls):
print("Class is {}".format(cls.__name__))
if not cls in cls._instances:
raise LookupError("No instance of the class {cls} create yet.".format(cls.__name__))
return cls._instances[cls]
@classmethod
def clearInstance(cls):
cls._instances.pop(cls, None)
Run Code Online (Sandbox Code Playgroud)
将 2 个方法标记为类方法..
现在,当我尝试打电话给他们时:
In [14]: dir(someClass)
Out[14]:
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__']
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,当我将class is其Singleton装饰为classmethod. 否则它会显示正确的类。我不明白这种行为,有人可以解释一下吗?
python元类可以有方法吗?
是的,正如您的第一个示例所示,它们可以有方法,并且可以在实现元类的类上调用它们。
例如在 python-3.x 中,元类type实现了mro属性:
>>> object.mro()
[object]
Run Code Online (Sandbox Code Playgroud)
但是你不能在实例上访问它们:
>>> object().mro()
AttributeError: 'object' object has no attribute 'mro'
Run Code Online (Sandbox Code Playgroud)
但是当我这样做时
dir(someClass),两种方法都没有显示。
dir调用type.__dir__,并且只显示了有限数量的方法:
如果对象是类型或类对象,则列表包含其属性的名称,以及其基类属性的递归名称。
这里没有提到元类的方法。那是因为这些默认情况下是隐藏的。
这就是为什么您也看不到该mro方法的原因:
>>> 'mro' in dir(object)
False
Run Code Online (Sandbox Code Playgroud)
但是dir允许自定义您看到的内容,因此您可以简单地覆盖它。因为__dir__在“实例类”上调用并且您的“元类是您的类的类型”,您必须在元类上实现它:
>>> object.mro()
[object]
Run Code Online (Sandbox Code Playgroud)
现在,当您调用dir.
向元类添加方法是否正确?
这在一定程度上取决于上下文。我会说将方法添加到元类很好。但是,这些应该很少使用。
正如你所看到的,当我将它装饰为
classmethod. 否则它会显示正确的类。我不明白这种行为,有人可以解释一下吗?
仔细想想就很明显了。Singleton是您的班级,someClass当您将其设为a 时classmethod,cls参数将是Singleton. 然而已添加到类_instances的someClass。我可以看到它来自哪里。你所有的方法都需要一个cls参数。这可能让你相信它们“像”类方法(它们在某种程度上,但不是元类,而是实现元类的类!)。
但这只是一个约定,因为 aself实例的典型参数名称是这样, a 实例的典型参数名称也是class如此。当您的元类上有 classmethods 时,可能应该调用第一个参数。还修复了一个小问题(这就是它抛出 a而不是 a的原因):clsmetaclassmetaclsstr.formatKeyErrorLookupError
>>> object().mro()
AttributeError: 'object' object has no attribute 'mro'
Run Code Online (Sandbox Code Playgroud)
因此,您将“类”添加到字典中,然后检查元类是否在字典中(不是)。
通常classmethods,__prepare__元类上的自定义(除了那些应该/可能是 classmethods 的,例如)没有多大意义,因为您很少需要实例的类的类型。
python 元类可以有方法吗?
是的。
但是当我执行 dir(someClass) 时,这两种方法不会显示
与您可能相信的相反,它dir并没有显示一切:
因为
dir()提供它主要是为了方便在交互式提示下使用,所以它尝试提供一组有趣的名称,而不是尝试提供一组严格或一致定义的名称,并且其详细行为可能会在不同版本之间发生变化。例如,当参数是 class 时,元类属性不在结果列表中。
正如你所看到的,当我将它装饰为 classmethod 时,该类 print 说它是 Singleton。
不要用 来装饰它classmethod!这明确表示Singleton您希望该方法对自身或 的子类进行操作Singleton,而不是对 的实例进行操作Singleton。以元类为元类的类Singleton是单例的实例;它们是类这一事实并不是放置classmethodonSingleton方法的理由。