python2和python3之间的可移植元类

kob*_*las 5 python python-3.x

我正在尝试在python3中运行python2程序,它具有以下Meta类定义.哪个在Py2上运行得很好.什么是让它与py2和py3兼容的"最佳"方法?

它在单元测试中失败了:

try:
    raise Actor.DoesNotExist
except Actor.DoesNotExist:
    pass
Run Code Online (Sandbox Code Playgroud)

失败是:

AttributeError: type object 'Actor' has no attribute 'DoesNotExist'
Run Code Online (Sandbox Code Playgroud)

基本元类定义是:

class MetaDocument(type):
    def __new__(meta,name,bases,dct):

        class DoesNotExist(BaseException):
            pass

        class MultipleDocumentsReturned(BaseException):
            pass
        dct['DoesNotExist'] = DoesNotExist
        dct['MultipleDocumentsReturned'] = MultipleDocumentsReturned
        class_type = type.__new__(meta, name, bases, dct)
        if not class_type in document_classes:
            if name == 'Document' and bases == (object,):
                pass
            else:
                document_classes.append(class_type)
        return class_type

class Document(object):
    __metaclass__ = MetaDocument
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 9

您可以使用MetaDocument()元类的工厂生产类取代你的Document课,再使用类属性:

class Document(object):
    # various and sundry methods and attributes

body = vars(Document).copy()
body.pop('__dict__', None)
body.pop('__weakref__', None)

Document = MetaDocument(Document.__name__, Document.__bases__, body)
Run Code Online (Sandbox Code Playgroud)

这不需要您手动构建第3个参数,即类体.

你可以把它变成一个类装饰器:

def with_metaclass(mcls):
    def decorator(cls):
        body = vars(cls).copy()
        # clean out class body
        body.pop('__dict__', None)
        body.pop('__weakref__', None)
        return mcls(cls.__name__, cls.__bases__, body)
    return decorator
Run Code Online (Sandbox Code Playgroud)

然后用作:

@with_metaclass(MetaDocument)
class Document(object):
    # various and sundry methods and attributes
Run Code Online (Sandbox Code Playgroud)

或者,使用six来实现:

@six.add_metaclass(MetaDocument)
class Document(object):
Run Code Online (Sandbox Code Playgroud)

其中,@six.add_metaclass()装饰也需要的任何照顾__slots__你可能已经定义; 我上面的简单版本没有.

six还有一个six.with_metaclass()基地工厂:

class Document(six.with_metaclass(MetaDocument)):
Run Code Online (Sandbox Code Playgroud)

它为MRO注入了额外的基类.

  • @JeromeJ:Python几乎就是这样;*调用*元类来生成类对象.在Python 3中还有身体准备步骤,但Python 2不支持这一点,因此在生成多语言解决方案时您不必关心它.这节课只产生一次*无论如何*因此表演几乎不成问题. (2认同)