Python 设置一个类';使用装饰器的元类
在使用以下*定义类之后,似乎可以更改类的元类:Python 设置一个类';使用装饰器的元类,python,decorator,metaclass,Python,Decorator,Metaclass,在使用以下*定义类之后,似乎可以更改类的元类: class MyMetaClass(type): # Metaclass magic... class A(object): pass A = MyMetaClass(A.__name__, A.__bases__, dict(A.__dict__)) 定义函数 def metaclass_wrapper(cls): return MyMetaClass(cls.__name__, cls.__bases__, dic
class MyMetaClass(type):
# Metaclass magic...
class A(object):
pass
A = MyMetaClass(A.__name__, A.__bases__, dict(A.__dict__))
定义函数
def metaclass_wrapper(cls):
return MyMetaClass(cls.__name__, cls.__bases__, dict(cls.__dict__))
允许我对类定义应用修饰符,如下所示
@metaclass_wrapper
class B(object):
pass
元类魔术似乎应用于B
,但是B
没有\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
属性。即使我正在定义和重新定义一个类,上面的方法是否是将元类应用于类定义的一种明智的方法,或者我还是简单地编写一个类更好
class B(object):
__metaclass__ = MyMetaClass
pass
我想这两种方法有些不同
*请注意,链接问题
MyMetaClass(A.。\uuuuu name\uuuuuuuuuu,A.\uuuuuu base\uuuuuuuuu,A.\uuuuuuu dict\uuuuuuu)
中的原始答案返回一个类型错误
:
TypeError:type()参数3必须是dict,而不是dict\u代理
A
(类定义)的\u dict\u
属性似乎有一个类型dict\u代理
,而A
实例的\u dict\u
属性的类型有一个类型dict
。为什么会这样?这是Python2.x与3.x的区别吗?我对你的问题的总结:“我尝试了一种新的棘手的方法来做一件事,但效果不太好。我应该用简单的方法来代替吗?”
是的,你应该用简单的方法来做。你还没有说你为什么对发明一种新的方法感兴趣。这个类没有
\uuuuuuuuuuuuuuuuuuuuuuuuu
属性集。。。因为你从来没有设定过
使用哪个元类通常由类块中设置的名称决定。元类未设置\uuuuuuuuuuuuuuuuuuu
属性。因此,如果您直接调用一个元类,而不是设置\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
并让Python来解决它
事实上,普通类都是元类类型
的实例,因此如果元类总是在其实例上设置\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
我不会使用你的装饰方法。它掩盖了一个事实,即涉及的元类(以及哪一个元类)仍然是一行样板文件,而且从(名称、基、属性)
的3个定义特性创建一个类只是为了从生成的类中提取这3个位,扔掉该类,然后从这3个位创建一个新的类,这很混乱
在Python 2.x中执行此操作时:
class A(object):
__metaclass__ = MyMeta
def __init__(self):
pass
如果你写下以下内容,你会得到大致相同的结果:
attrs = {}
attrs['__metaclass__'] = MyMeta
def __init__(self):
pass
attrs['__init__'] = __init__
A = attrs.get('__metaclass__', type)('A', (object,), attrs)
实际上,计算元类更为复杂,因为实际上必须搜索所有的基以确定是否存在元类冲突,如果其中一个基没有type
作为其元类,并且attrs
不包含\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
则默认元类是祖先的元类,而不是。在这种情况下,我希望您的decorator“解决方案”与直接使用\uuuuu元类
有所不同。如果在使用\uuuuu元类\uuuuu
会导致元类冲突错误的情况下使用装饰器,我不确定会发生什么,但我不认为这会令人愉快
此外,如果涉及到任何其他元类,您的方法将首先运行它们(可能修改名称、基和属性!),然后将它们从类中取出并使用它创建一个新类。这可能与使用\uuuuu元类\uuuuuu
得到的结果有很大不同
至于\uuuu dict\uuuu
没有给你一个真正的字典,那只是一个实现细节;我猜是因为性能原因。我怀疑是否有任何规范规定(非类)实例的\uuuuu dict\uuu
必须与类的\uuuu dict\uuu
类型相同(顺便说一句,它也是一个实例;只是一个元类的实例)。类的\uuu dict\uuuu
属性是“dictproxy”,它允许您查找属性键,就像它是dict
但仍然不是dict
type
对第三个参数的类型很挑剔;它需要一个真正的dict,而不仅仅是一个“类似dict”的对象(因为它破坏了duck输入而感到羞愧)。这不是2.x对3.x的游戏;Python3的行为方式与此相同,尽管它为dictproxy
提供了更好的字符串表示形式。Python2.4(这是我现有的最古老的2.x)也有类\uuuuu dict\uuuu
对象的dictproxy
。无可否认,我参加聚会有点晚。然而,我觉得这是值得补充的
这是完全可行的。也就是说,有很多其他方法可以实现同样的目标。但是,装饰解决方案尤其允许延迟评估(obj=dec(obj)
),而在类内使用\uuuuuuu元类
则不允许。在典型的装饰风格中,我的解决方案如下
如果只构造类而不更改字典或复制其属性,则可能会遇到一件棘手的事情。该类以前(装饰之前)具有的任何属性都将丢失。所以,完全有必要复制它们,然后像我在解决方案中那样调整它们
就个人而言,我希望能够跟踪对象是如何包装的。因此,我添加了\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
属性,这在严格意义上是不必要的。它还使它更像Python3中类的functools.wrapps
。然而,这对内省是有帮助的。另外,添加了\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
def metaclass(meta):
def metaclass_wrapper(cls):
__name = str(cls.__name__)
__bases = tuple(cls.__bases__)
__dict = dict(cls.__dict__)
for each_slot in __dict.get("__slots__", tuple()):
__dict.pop(each_slot, None)
__dict["__metaclass__"] = meta
__dict["__wrapped__"] = cls
return(meta(__name, __bases, __dict))
return(metaclass_wrapper)
下面是一个简单的例子
class MetaStaticVariablePassed(type):
def __new__(meta, name, bases, dct):
dct["passed"] = True
return(super(MetaStaticVariablePassed, meta).__new__(meta, name, bases, dct))
@metaclass(MetaStaticVariablePassed)
class Test(object):
pass
这会产生一个很好的结果
|1> Test.passed
|.> True
在t中使用decorator
class Test(object):
pass
Test = metaclass_wrapper(Test)
|1> Test.passed
|.> True