python2和python3之间的可移植元类
我正在尝试让一个python2程序在python3中工作,它有下面的元类定义。这在Py2上运行得很好。让它与py2和py3兼容的“最佳”方式是什么 它在单元测试中失败,在单元测试中:python2和python3之间的可移植元类,python,python-3.x,Python,Python 3.x,我正在尝试让一个python2程序在python3中工作,它有下面的元类定义。这在Py2上运行得很好。让它与py2和py3兼容的“最佳”方式是什么 它在单元测试中失败,在单元测试中: try: raise Actor.DoesNotExist except Actor.DoesNotExist: pass 失败是: AttributeError: type object 'Actor' has no attribute 'DoesNotExist' 基本元类定义为: clas
try:
raise Actor.DoesNotExist
except Actor.DoesNotExist:
pass
失败是:
AttributeError: type object 'Actor' has no attribute 'DoesNotExist'
基本元类定义为:
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
有一个实用程序
class Document(six.with_metaclass(MetaDocument, object)):
# class definition, without the __metaclass__
唯一的副作用是类层次结构从
>>> Document.__mro__
(<class 'test.Document'>, <type 'object'>)
>>文档。\u__
(, )
到
>>文档。\u__
(, )
因为
with\u元类
实际上返回了一个带有适当元类的新类。您可以使用MetaDocument()
元类作为工厂来生成一个类来替换文档
类,重新使用类属性:
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)
这不需要您手动构建第三个参数,即类主体
您可以将其转换为类装饰器:
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
然后用作:
@with_metaclass(MetaDocument)
class Document(object):
# various and sundry methods and attributes
或者,使用以下选项:
@six.add_metaclass(MetaDocument)
class Document(object):
其中,还负责您可能已定义的任何\uuuuuuuuuuuuuuuuuuuu
;我上面简单的版本没有
six
还有一个:
这将向MRO中注入一个额外的基类。顺便说一句,为什么在这里使用
BaseException
而不是Exception
?您很少应该使用BaseException
。简单回答-不是我的代码,当我解决一般情况时,好的一点会得到解决。@eryksun:Django就是这么做的。每个模型DoesNotExist
异常是从ObjectDoesNotExist
派生的,这有助于使只捕获特定模型异常的代码更加清晰。@eryksun:yup,但由于模型携带异常,因此在使用模型查询时,您可以直接使用它:try:user=user.get(username=username)
,除了User.DoesNotExist:return HttpResponseForbidden()
。在您的第一个代码中,您的意思是文档
,而不是cls
不知从哪里冒出来的吗?这不是某种小技巧吗?是否存在任何“重大”性能缺陷问题?(我特别关注的是没有第三部分库的第一个解决方案)我的猜测是,没有其他方法可以使元类兼容Py2和Py3。@JeromeJ:Python几乎完全做到了这一点;调用元类以生成类对象。在Python3中还有主体准备步骤,但Python2不支持这一步骤,因此在生成多语言解决方案时不必考虑这一点。这个类只生成一次,所以性能几乎不是问题。当我扩展这个类时会触发它吗?如何确保这种情况发生?有一点我不太明白,到目前为止,搜索并没有回答我的问题。(我有一个案例,我让它工作了,一个没有,但我不明白为什么到目前为止)
@six.add_metaclass(MetaDocument)
class Document(object):
class Document(six.with_metaclass(MetaDocument)):