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