我在考虑自动添加子类到父类,以便使用元类“链接”。然而,从父类继承这些属性会把事情搞砸。有什么好办法可以避免这种情况吗?在
class MetaError(type):
def __init__(cls, name, bases, attrs):
for base in bases:
setattr(base, name, cls)
super(MetaError, cls).__init__(name, bases, attrs)
class BaseError(Exception, object):
def __init__(self, message):
super(BaseError, self).__init__(message)
class HttpError(BaseError):
__metaclass__ = MetaError
class HttpBadRequest(HttpError):
pass
class HttpNotFound(HttpError):
pass
class FileNotFound(HttpNotFound):
pass
class InvalidJson(HttpBadRequest):
pass
http = HttpError
# now I can do
raise http.HttpNotFound('Not found')
raise http.HttpNotFound.FileNotFound('File not found')
raise http.HttpBadRequest.InvalidJson('Invalid json')
# unfortunately this also works
raise http.HttpBadRequest.HttpBadRequest('Bad request')
raise http.HttpBadRequest.HttpNotFound('Not found')
一个相当幼稚的全局映射解决方案似乎也在工作:
好吧,这比一开始看起来要复杂- 因为基本上你想要有类继承关系,但是不要在类继承上使用普通的属性查找路径- 否则,HTTPError作为BaseError的一个子类,将始终拥有BaseError本身的所有属性,因此, 链
BaseError.HTTPError.HTTPError.HTTPError.HTTPError...
将始终有效。在幸运的是,Python提供了一种机制,可以将类注册为其他类的子类,而不需要“物理”继承——也就是说,它被报告为子类,但它的基类或
__mro__
中没有父类,因此,在派生类上进行属性查找(采用了吗?)不在“寄养”父级中搜索属性。在这个机制是通过“abstract base classes”或“abc”通过其ABCMeta元类和“register”方法提供的。在
现在,由于你可能还想申报 使用普通继承语法的类层次结构-即, 能够写
class HTTPError(BaseError):
来表示新的 类派生自BaseError-您可以获得实际的“物理”继承。在因此,我们可以从ABCMeta类继承(而不是
type
)并编写 使物理继承被排除的__new__
方法- 我们还使用setattr
来包含您的代码,而且,我们直接在元类上触发对parentclass.register
的必要调用。在(请注意,由于我们现在正在更改基类,我们需要进行调整 在元类的
__new__
方法中,而不是在__init__
上:快速测试:
^{pr2}$在交互模式下,检查它是否按预期工作:
然后,最重要的是,测试异常层次结构是否真的以这种方式工作:
注意:不需要同时从
Exception
和object
显式继承-Exception
本身已经从object
继承。而且,最重要的是:无论你在做什么项目,尽一切可能把它移到python3.x而不是python2上。Python2是有天数的,而且Python3中有很多很多新特性,您不需要自己使用。(这个答案中的代码是python2/3兼容的,当然是针对__metaclass__
用法声明)。在相关问题 更多 >
编程相关推荐