Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python2和python3之间的可移植元类_Python_Python 3.x - Fatal编程技术网

python2和python3之间的可移植元类

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

我正在尝试让一个python2程序在python3中工作,它有下面的元类定义。这在Py2上运行得很好。让它与py2和py3兼容的“最佳”方式是什么

它在单元测试中失败,在单元测试中:

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)):