元类可以有方法吗?
我试图实现单班为我的项目和一个有趣的帖子在StackOverflow上在同一元类可以有方法吗?
Creating a singleton in Python
我决定去与方法中提到的元类..
现在..我试着添加一个方法来获取和清除实例(如果用户希望摆脱当前实例,并创建一个新的..):
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
我能够创建OBJ学分顺利..
In [9]: sc = someClass(1)
In [10]: sc.value
Out[10]: 1
但是当我做dir(someClass)
不显示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__']
不过我能够调用的方法..
In [13]: someClass.getInstance()
Class is someClass
Out[13]: <__main__.someClass at 0x7f728b180860>
在元类的所有例子中,我在网上看到我看到__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)
标记2种方法作为类方法..
现在,当我尝试调用它们:
In [2]: sc = someClass(1)
In [3]: someClass.getInstance()
Class is Singleton
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-3-c83fe01aa254> in <module>()
----> 1 someClass.getInstance()
<ipython-input-1-9efb6548d92d> in getInstance(cls)
12
13 if not cls in cls._instances:
---> 14 raise LookupError("No instance of the class {cls} create yet.".format(cls.__name__))
15
16 return cls._instances[cls]
KeyError: 'cls'
正如你可以看到class is
打印说,其Singleton
当我装饰它为classmethod
。否则它显示正确的类。我不明白这种行为,有人可以解释吗?
python metaclasses是否有方法?
是的。
但是当我做目录(SomeClass的)2种方法不显示
相反,你可能会认为,dir
doesn't show everything:
因为
dir()
主要供应为了便于在交互式提示符下使用,它试图提供一组有趣的名称,而不是试图提供严格或一致定义的一组na mes,并且其详细行为可能会在各版本中发生变化。例如,当参数是类时,元类属性不在结果列表中。
正如你可以看到类是打印表示,其辛格尔顿当我装点它作为类方法。
不要用classmethod
装饰它!那明确说你想要的方法操作Singleton
本身或Singleton
的子类,而不是Singleton
的实例。具有Singleton
作为其元类的类是实例单例;他们是班级的事实不是把classmethod
放在Singleton
的方法上的理由。
类是它们的元类的实例。正如类的实例没有将类的方法作为属性,但仍然可以调用它们一样,类没有将元类的方法作为属性。
python元类可以有方法吗?
是的,因为你的第一个例子显示他们可以有方法,他们可以在实现你的元类的类上调用。
例如在python-3中。X元类type
实现mro
属性:
>>> object.mro()
[object]
但你不能访问它们的实例:
>>> object().mro()
AttributeError: 'object' object has no attribute 'mro'
但是当我做
dir(someClass)
不显示2种方法。
dir
电话type.__dir__
而只是显示的方法,数量有限:
如果对象是一个类型或类对象,列表中包含了属性的名称,并递归的其基地的属性。
没有提及关于这里的元类的方法。这是因为这些是默认隐藏的。
这就是为什么你没有看到mro
方法之一:
>>> 'mro' in dir(object)
False
然而dir
可以定制你所看到的,所以你可以简单地覆盖它。由于__dir__
被称为在“类实例的”和你的“元类是类的类型”你必须实现它在你的元类:
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)
def __dir__(self):
normal_dir = type.__dir__(self)
# Also include all methods that don't start with an underscore and
# not "mro".
normal_dir.extend([f for f in dir(type(self))
if not f.startswith('_') and f != 'mro'])
return normal_dir
class someClass(metaclass=Singleton):
def __init__(self,val):
self.value = val
>>> dir(someClass)
[..., 'clearInstance', 'getInstance']
现在,当你调用类的这些方法都可见dir
。
将方法添加到元类是否正确?
这取决于上下文。我会说将这些方法添加到元类是很好的。但是,这些应该很少使用。
正如你所看到的那样,当我将它装饰为
classmethod
时,这个类是print的。否则它显示正确的类。我不明白这种行为,有人可以解释吗?
这很明显,如果你想一想。 Singleton
是您的someClass
的等级,当您将其设置为classmethod
时,cls
参数将为Singleton
。但是,添加到_instances
的类是someClass
。我可以看到它的来源。您的所有方法都采用cls
参数。这可能会让你相信他们“喜欢”类方法(它们以某种方式,但不是元类,而是实现元类的类)。
但它只是一个约定,因为,像self
是一个class
实例的典型参数的名字,所以是cls
为metaclass
实例的典型参数名称。当你在metaclass上使用类方法时,第一个参数应该叫metacls
。另外随着str.format
固定一个小问题(这是它抛出一个KeyError
而不是LookupError
的原因):
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
print(cls._instances) # print the dict after creating an instance
return cls._instances[cls]
@classmethod
def getInstance(metacls):
print("Class is {}".format(metacls))
if not metacls in metacls._instances:
raise LookupError("No instance of the class {0} create yet.".format(metacls.__name__))
return metacls._instances[metacls]
@classmethod
def clearInstance(metacls):
metacls._instances.pop(metacls, None)
class someClass(metaclass=Singleton):
def __init__(self,val):
self.value = val
>>> sc = someClass(1)
{<class '__main__.someClass'>: <__main__.someClass object at 0x00000235844F8CF8>}
>>> someClass.getInstance()
Class is <class '__main__.Singleton'>
LookupError: No instance of the class Singleton create yet.
,所以添加“类”的字典但你检查元类是在字典(它不是)。
通常定制classmethods
(除了那些应该/可能是类方法,例如__prepare__
)对元类没有多大意义,因为你很少需要你的实例类的类型。
0123我知道,而不是someClass我得到SingletonClass作为CLS的论点..但我不明白为什么我得到的CLS作为SingletonClass一旦我装饰类方法.. –
@ArunKalirajaBaskaran我编辑答案a包含更多细节。如果有什么不清楚,请告诉我。通过回答这个问题,我学到了很多东西,并且由于某些方面对我来说也是新的,所以在文中可能会有点“跳跃”。 :) – MSeifert
虽然我同意他们可以有方法,但也有人问:“向元类添加方法是否正确?” - 这有点难以回答。我肯定会对你的想法在这一点上感兴趣:) – MSeifert