:抽象メソッドと抽象メソッドを呼び出し、その戻り値を検証する別の方法 - あなたが本当にそれをしたい場合しかし、あなたは二つの方法にprocess
を分割することができます。
考え方は、メインクラスに__getattribute__
を実装することです。そのため、子クラスが呼び出すメソッドを変更する必要があります。
2つの単純なクラス:モジュールによって定義されるFoo
基本クラスと、APIのユーザーによって定義されるBar
サブクラスを考えます。 Bar
クラスはmethod
メソッドを上書きしますが、Foo.method
と同じ動作を保つように、タイプint
のオブジェクトを返すようにします。
class Foo:
def method(self):
return 1
class Bar(Foo):
def method(self):
return "a"
もちろん、これは問題ありません。 しかし、ここには__getattribute__
メソッドのトリックがあります。
まず、要求された属性の名前が"method"
であるかどうかを確認します。 それがそうなら、実際のmethod
を返す代わりに、私はカスタム関数を作成し、実際にはmethod
の戻り値がint
であることを示しています。
def __getattribute__(self, attribute):
if attribute == "method":
def _f(*args, **kwargs):
result = type(self).method(self, *args, **kwargs)
assert isinstance(result, int)
return result
return _f
は今、__getattribute__
方法はinstance.whatever
は関係なく、その相続ファミリーの任意のクラスの属性として見つけることができるかどうかwhatever
、instance.__getattribute__("whatever")
への呼び出しになりますように定義されます。
したがって、bar = Bar()
の場合、bar.method
は、Foo.__getattribute__
で定義した内部_f
に置き換えられます。
さて、bar.method()
はAssertionError
になりますが、私はそれを修正する場合は、次のように:
class Bar(Foo):
def method(self):
return 1
が実行は罰金になります。
__getattribute__
の定義について
あなたがself.something
を呼び出すことはできませんので、それは__getattribute__
への再帰呼び出しにつながるので、それは、少しトリッキーかもしれません。 この解決策はtype(self).method
を直接参照することであり、クラスメソッドをここではBar
で定義します。この場合 、この方法は、最初のパラメータとしてinstance
をとるので、self
を渡す必要があり、従ってライン:サブクラス自体が__getattribute__
を実装している場合もちろん
result = type(self).method(self, *args, **kwargs)
、このすべては失敗します。 しかし、とにかく、Python APIは簡単に壊れることを忘れないでください。 具体的には、AssertError
を簡単に検出できました。 さて、あなたはsys.exit(1)
でassert
を置き換えることができますが、それは少しも保かもしれません...
私はアイデアを得ました。 これは多かれ少なかれ、アンチ・パターン、Pythonに似ています。なぜなら、ユーザーは自分が望むように自由に行うことを禁止するからです。一方、1はするために、単なるprint
によってassert
/raise
を置き換えることができ は彼らを罰するユーザーの代わりに、を教育します。
私の設計に従うために、プログラマーにコードを強制するにはどうすればいいですか? < - 銃器や脅迫で。 – timgeb
ダックタイピングの原則は、そのようなハイパー明示的なタイピングを禁止します。 'process'が*' ExemplaryClass'のように動作するものを返す限り、それは十分です。しかし、Python 3.4以降の静的型チェックツールを使用して、少なくともその一部をチェックすることができます。 – deceze
@timgebあなたの答えは非常に面白いですが、Python 3.5+では正確ではありません。 – jpic