213

たとえば、Javaでは、@Overrideアノテーションはオーバーライドのコンパイル時チェックを提供するだけでなく、優れた自己文書化コードを作成します。

私はドキュメントを探しています(ただし、それがpylintのようなチェッカーの指標である場合、それはボーナスです)。コメントやdocstringをどこかに追加できますが、Pythonでオーバーライドを示す慣用的な方法は何ですか?

4

11 に答える 11

240

これと fwc:s の回答に基づいて、pip インストール可能なパッケージを作成しましたhttps://github.com/mkorpela/overrides

時々、私はこの質問を見てここに行き着きます。これは主に、コード ベースで同じバグを (再び) 見た後に発生します。「インターフェース」のメソッドの名前を変更しているときに、誰かが「インターフェース」実装クラスを忘れた..

Python は Java ではありませんが、Python には強力な機能があり、明示的なものは暗黙的なものよりも優れています。現実の世界には、これが役に立った具体的なケースがいくつかあります。

これがオーバーライド デコレータのスケッチです。これにより、パラメーターとして指定されたクラスが、装飾されているメソッドと同じメソッド (または何か) の名前を持っていることが確認されます。

より良い解決策を考えられる場合は、ここに投稿してください。

def overrides(interface_class):
    def overrider(method):
        assert(method.__name__ in dir(interface_class))
        return method
    return overrider

次のように機能します。

class MySuperInterface(object):
    def my_method(self):
        print 'hello world!'


class ConcreteImplementer(MySuperInterface):
    @overrides(MySuperInterface)
    def my_method(self):
        print 'hello kitty!'

欠陥のあるバージョンを実行すると、クラスのロード中にアサーション エラーが発生します。

class ConcreteFaultyImplementer(MySuperInterface):
    @overrides(MySuperInterface)
    def your_method(self):
        print 'bye bye!'

>> AssertionError!!!!!!!
于 2011-11-29T15:07:19.627 に答える
30

これは、interface_class 名の指定を必要としない実装です。

import inspect
import re

def overrides(method):
    # actually can't do this because a method is really just a function while inside a class def'n  
    #assert(inspect.ismethod(method))

    stack = inspect.stack()
    base_classes = re.search(r'class.+\((.+)\)\s*\:', stack[2][4][0]).group(1)

    # handle multiple inheritance
    base_classes = [s.strip() for s in base_classes.split(',')]
    if not base_classes:
        raise ValueError('overrides decorator: unable to determine base class') 

    # stack[0]=overrides, stack[1]=inside class def'n, stack[2]=outside class def'n
    derived_class_locals = stack[2][0].f_locals

    # replace each class name in base_classes with the actual class type
    for i, base_class in enumerate(base_classes):

        if '.' not in base_class:
            base_classes[i] = derived_class_locals[base_class]

        else:
            components = base_class.split('.')

            # obj is either a module or a class
            obj = derived_class_locals[components[0]]

            for c in components[1:]:
                assert(inspect.ismodule(obj) or inspect.isclass(obj))
                obj = getattr(obj, c)

            base_classes[i] = obj


    assert( any( hasattr(cls, method.__name__) for cls in base_classes ) )
    return method
于 2013-01-31T17:13:53.410 に答える
18

文書化のみを目的としてこれが必要な場合は、独自のオーバーライド デコレータを定義できます。

def override(f):
    return f


class MyClass (BaseClass):

    @override
    def method(self):
        pass

実際にオーバーライドをチェックするような方法で override(f) を作成しない限り、これは実際には見栄えに他なりません。

しかし、これは Python です。どうして Java のように書くのでしょうか。

于 2009-07-22T22:33:35.297 に答える
4

PythonはJavaではありません。もちろん、コンパイル時のチェックのようなものは実際にはありません。

docstringのコメントはたくさんあると思います。これにより、メソッドのすべてのユーザーが入力help(obj.method)して、メソッドがオーバーライドであることを確認できます。

を使用してインターフェースを明示的に拡張することもできますclass Foo(Interface)。これにより、ユーザーは入力help(Interface.method)して、メソッドが提供する機能についてのアイデアを得ることができます。

于 2009-07-22T19:32:09.857 に答える
2

他の人が言ったように、Java とは異なり @Overide タグはありませんが、デコレータを使用して独自のタグを作成できますが、内部 dict を使用する代わりに getattrib() グローバル メソッドを使用することをお勧めします。

def Override(superClass):
    def method(func)
        getattr(superClass,method.__name__)
    return method

必要に応じて、独自の try catch で getattr() をキャッチして独自のエラーを発生させることもできますが、この場合は getattr メソッドの方が優れていると思います。

また、これは、クラスメソッドと変数を含む、クラスにバインドされたすべてのアイテムをキャッチします

于 2013-08-12T17:43:44.020 に答える
2

@mkorpela の素晴らしい回答に基づいて、さらに多くのチェックを行う同様のパッケージ ( ipromise pypi github ) を作成しました。

がおよびAから継承し、 がから継承するとします。BCBC

モジュールipromiseは以下をチェックします:

  • A.fオーバーライドする場合はB.fB.f存在し、Aから継承する必要がありますB。(これはオーバーライド パッケージからのチェックです)。

  • A.fパターンがオーバーライドすることB.fを宣言し、それがオーバーライドすることを宣言することはありませんC.f。このメソッドのオーバーライドを停止することを決定する可能性があるため、からAオーバーライドすると言う必要があります。これにより、ダウンストリームの更新が発生することはありません。C.fB

  • パターンがA.fオーバーライドすることを宣言していませんが、そのオーバーライドを宣言してC.fB.fません。

  • A.fオーバーライドすることを宣言するパターンはありませんが、C.fいくつB.fかの からオーバーライドすることを宣言しますD.f

また、抽象メソッドの実装をマークおよびチェックするためのさまざまな機能も備えています。

于 2019-03-14T00:03:47.753 に答える
-1

Hear は最も単純で、Java クラスを使用して Jython で動作します。

class MyClass(SomeJavaClass):
     def __init__(self):
         setattr(self, "name_of_method_to_override", __method_override__)

     def __method_override__(self, some_args):
         some_thing_to_do()
于 2013-11-25T21:02:37.333 に答える