web-dev-qa-db-ja.com

オーバーライドする必要があるメソッドをプライベートと見なすことはできますか?

クラスCにメソッドf()があり、Cの実装内でのみ使用することを意図しているが、Cのサブクラスでオーバーライドする必要があるとします。 。

プライベートと見なす、つまり_f()ではなくf()と名付けるのは合理的ですか、それとも「Pythonic」ですか?

つまり、サブクラスに提供されるインターフェースと、継承階層外のコードに提供されるインターフェースを区別しますか?

6
Nicola Musatti

Pythonで言えば、この機能を実装するには Abstract Base Class module を利用する必要があります。

例:

_from abc import ABCMeta, abstractmethod

class MyBaseClass(object):

    __metaclass__ = ABCMeta

    @abstractmethod
    def f(self, *args):
        #"Public" method (accessible from outside of class instance)
        pass


    @abstractmethod
    def _f(self, *args):
        #"Private" method (should only be accessed from with instance)
        pass
_

次に、_f()をオーバーライドせずにMyBaseClassのサブクラスをインスタンス化しようとすると、次のようになります。

_>>> my_base_class = MyBaseClass()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MyBaseClass with abstract methods _f
>>> class B(MyBaseClass):
...     pass
... 
>>> b = B()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class B with abstract methods _f
>>> class B(MyBaseClass):
...     def _f(self):
...             print "foo"
... 
>>> b=B()
>>> b._f()
foo
>>> 
_

Pythonにはプログラムで「プライベート」なメソッドがないことに注意してください。つまり、名前の前の単一の下線(_f())は、メソッドに内部的にのみアクセスする必要があることを示すために使用されます。

5
Joel Cornett

あなたの質問は本当にpythonに固有ではありませんが、C++やC#のような多くのOO言語に適用できます。私はまだハードルールに遭遇していません。しかし、同じ考えが時々私に起こりました。

だから私の意見は次のとおりです:

  • プライベートメソッド-クラスCだけが知っておくべきこと、使用すること。他に誰もいない
  • 保護されたメソッド-派生クラスが知っておくべきおよび/または使用する必要があるもの。
  • パブリックメソッド-外部コードが認識または使用する必要があるもの。

したがって、あなたの例では、関数を保護しますが、クラスCのドキュメントでは、派生クラスがこの関数を直接呼び出すことを意図していないことを非常に明確にしています。むしろ、それを実装し、基本クラスにいつ呼び出すのが適切かを判断させる必要があります。

つまり、派生クラスが実装を提供することを期待しています。したがって、この時点では、そのクラスをコーディングしている人がそのコードを呼び出すのを妨げるものは何もありません。なんとかして「プライベートにマーク」したとしても、その人はそのコードを1回書いたので、もう一度コードを書くか、それが本当にやりたいことであれば、別の方法でコードを実行します。

Pythonicとは何か。私はpython=エキスパートではありませんが、これは言語の慣習だと思います:

  • アンダースコアの接頭辞はありません(f())= public function
  • 二重下線(つまり__f())=プライベート関数
  • 単一の下線(つまり_f())=内部使用関数

Pythonは、人々が私的な日付にアクセスできないようにするために、言語ではなく慣習に大きく依存しています。実際に隠されているものはありませんが、関数名の前に「__」を付けると、インタープリターはその関数名を「変換」します。それが行う理由は、プライベート関数を呼び出すクライアントコードを人々が書くのを阻止するためです(妨げないため)。

c = C()
c.__foo()

...は、関数が存在しないことをインタープリターに通知します。しかし、誰かが本当にあなたのプライベート関数を呼び出したいのなら、彼らはただ書くでしょう:

c._C__foo()      # mangled name (I don't remember exact
                 # naming rules, but point is the same)

python保護された関数にプライベート関数を使用することはお勧めしません。 "__"は、派生クラスを含め、外部に信号を送ることを意図しているようです "触れないでください"。

あなたの場合、私は単一の「_」を使用して、関数がパブリック/外部の消費用ではなく、クラスについて十分な知識を持つ誰か(つまり、派生クラスの実装者はおそらくクライアントのコードを書く人よりも、内部の詳細についての知識が豊富です)。

プライベートシンボルでの "__"(ダブルアンダースコア)の使用について言及しているソースはほとんどありません。

3
DXM

あなたの質問は「Pythonic」の方法とは何かに関するものなので、著者は「しかし、__ privateフォームを避けようとします。私は決して使用しません。」という Pythonのようなコード の命名セクションを参照してください。そして更に重要なことに:

シングルリーディングアンダースコアの規約である_internalを使用することをお勧めします。これは完全に壊された名前ではありません。 「これに注意してください。これは内部実装の詳細です。完全に理解していない場合は触れないでください」と他の人に示しているだけです。それは慣例にすぎません。

言い換えれば、「プライベート」の概念そのものはPythonicではありません。さらに、単一の下線_internal表記は、記述した特別な目的の内部構造に対して明示的に存在します。

1
Gort the Robot

私はPythonに慣れていないので、「Pythonic」の方法で話すことはできません。

C++、C#、Javaなどの言語では、3種類のメンバーを区別するための明示的な規定があります。

  • privateクラス自体にのみアクセス可能なメンバー用
  • public世界中からアクセスできるメンバー向け
  • protected子孫がアクセスできるメンバー

C++では、プライベート仮想関数を使用する(そして派生クラスでそれらをオーバーライドする)イディオムさえあります。詳細は SOに関するこの質問 を参照してください。