我正在尝试在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)
您可以使用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注入了额外的基类.