まあ、これが最初で、それはseensより扱いにくいことが判明 - 基本的には、クラスの継承関係を持つようにしたいが、クラスの継承に通常の属性検索パスを使用しないため、 - それ以外の場合は を、HTTPError、たとえば、BaseErrorのサブクラスであると、BaseError自体にすべての属性セットが存在します。したがって、 のチェーンBaseError.HTTPError.HTTPError.HTTPError.HTTPError...
は常に有効です。それはそれは、サブクラスとして報告されているが、その塩基または__mro__
で親クラスを持っていない - -
幸い、Pythonは「物理」の継承せず、提供他のサブクラスとしてクラスを登録するためのメカニズムを行い、したがって、派生クラスの属性参照(「?」)は、「里親」の親の属性を検索しません。
このメカニズムは、 "abstract base classes"または "abc"、ABCMetaメタクラス、および "register"メソッドによって提供されます。今
そして、原因事実のためにあなたはまた、おそらく通常の継承構文で あなたのクラス階層を宣言したい - つまり、 は新しい クラスを示すためにclass HTTPError(BaseError):
を書き込むことができることがBaseErrorから派生した - あなたは、実際の取得"物理的な"継承。
だから、我々は(代わりにtype
の)ABCMetaクラスから継承することができ、物理的な継承は除外されるように __new__
メソッドを書く - を、私たちはあなたにも、また、あなたのコードで意図封じ込めのためsetattr
を使用し、私たちはparentclass.register
への必要な呼び出しをメタクラス上で直接起動します。
(私たちは今、基本クラスを変更しているとして、我々はない__init__
に、メタクラスの__new__
方法で をいじる必要があることに注意してください:
from abc import ABCMeta
class MetaError(ABCMeta):
def __new__(metacls, name, bases, attrs):
new_bases = []
base_iter = list(reversed(bases))
seen = []
register_this = None
while base_iter:
base = base_iter.pop(0)
if base in seen:
continue
seen.append(base)
if isinstance(base, MetaError):
register_this = base
base_iter = list(reversed(base.__mro__)) + base_iter
else:
new_bases.insert(0, base)
cls = super(MetaError, metacls).__new__(metacls, name, tuple(new_bases), attrs)
if register_this:
setattr(register_this, name, cls)
register_this.register(cls)
return cls
そして簡単なテストのために:
class BaseError(Exception):
__metaclass__ = MetaError
class HTTPError(BaseError):
pass
class HTTPBadRequest(HTTPError):
pass
対話モードで
、あなたが意図したとおり、それが動作するか確認してください。
In [38]: BaseError.HTTPError
Out[38]: __main__.HTTPError
In [39]: BaseError.HTTPError.HTTPError
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-39-5d5d03751646> in <module>()
----> 1 BaseError.HTTPError.HTTPError
AttributeError: type object 'HTTPError' has no attribute 'HTTPError'
In [40]: HTTPError.__mro__
Out[40]: (__main__.HTTPError, Exception, BaseException, object)
In [41]: issubclass(HTTPError, BaseError)
Out[41]: True
In [42]: issubclass(HTTPBadRequest, BaseError)
Out[42]: True
In [43]: BaseError.HTTPError.HTTPBadRequest
Out[43]: __main__.HTTPBadRequest
In [44]: BaseError.HTTPBadRequest
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-44-b40d65ca66c6> in <module>()
----> 1 BaseError.HTTPBadRequest
AttributeError: type object 'BaseError' has no attribute 'HTTPBadRequest'
を
そして、すべての最も重要な、例外階層は、実際にこのように動作するかどうかテストする:
In [45]: try:
....: raise HTTPError
....: except BaseError:
....: print("it works")
....: except HTTPError:
....: print("not so much")
....:
it works
いくつかの注意事項:明示的Exception
とobject
の両方から継承する必要 - Exception
自体がすでにobject
から継承しません。そして、最も重要なのは、作業しているプロジェクトがあれば、Python 2の代わりにPython 3.xに移動することが可能です。Python 2には数えられた日があります。Python 3には数多くの新機能があります使用することを除いて。 (この回答のコードはPython 2/3と互換性がありますが、もちろん__metaclass__
用法宣言のためです)。
感謝を。私はうまくいくかもしれません(代わりに、グローバルマッピングベースのソリューションもうまくいくと思われます) – root