web-dev-qa-db-ja.com

pythonサブクラスでメソッドをプライベートにする

パブリックメソッドをサブクラスでプライベートにすることは可能ですか?これを拡張する他のクラスがいくつかのメソッドを呼び出せるようにしたくありません。ここに例があります:

class A:
    def __init__(self):
        #do something here

    def method(self):
        #some code here

class B(A):
    def __init__(self):
        A.__init__(self)
        #additional initialization goes here

    def method(self):
        #this overrides the method ( and possibly make it private here )

この時点から、Bから拡張するクラスがmethodを呼び出せないようにします。これは可能ですか?

編集:これの「論理的な」理由は、ユーザーが間違った順序でメソッドを呼び出さないようにするためです。

25
Geo

Pythonはソースとして配布されています。プライベートメソッドのアイデア自体はほとんど意味がありません。

プライバシーの問題に不満を持ってBを拡張したいプログラマーは、Bのソースを調べ、methodのソースコードをコピーしてサブクラスC

「プライバシー」を通じて何を得ましたか?あなたが望むことができる最善のことは、あなたの潜在的な顧客をコピーアンドペーストに苛立たせることです。

最悪の場合、パッケージを拡張できないため、パッケージは破棄されます。

そして、はい、すべてのオープンソースは何らかの方法で拡張されています。コードが使用されるすべての用途を予測することはできません。コードがソースとして配布されている場合、将来の使用を防ぐことは困難です。

保護するにはどうすればよいですかPythonコード?


編集「ばかげた」コードについて。

まず、pythonは90%の確率でソースとして配布されます。したがって、ダウンロード、インストール、そしてAPIガイドの読み取りを拒否し、メソッドを順不同で呼び出す馬鹿は、依然としてソースを持っています。何が悪かったのかを理解するために。

私たちは3つのクラスの馬鹿を持っています。

  • APIガイドを読むことを拒否し(またはそれをざっと読み、関連する部分を無視して)、ドキュメントにもかかわらず、メソッドを順不同で呼び出す人。あなたは何かをプライベートにしようとすることができますが、彼らは何か他の間違ったことをするので助けにはなりません-そしてそれについて不平を言います。 [名前は付けませんが、APIの不適切な呼び出しに多くの時間を費やしているように見える人々と協力してきました。また、SOでこのような質問が表示されます。]

    あなたは彼らがカットアンドペーストできる実用的なコードサンプルで彼らを助けることができるだけです。

  • APIに混乱し、想像できるさまざまな方法でメソッドを呼び出す人(そして、想像できない人もいます)。何かをプライベートにしようとすることはできますが、APIを取得することはできません。

    実用的なコードサンプルを提供することによってのみ、彼らを助けることができます。それでも、彼らはそれを間違ってカットアンドペーストします。

  • あなたのAPIを拒否し、それを「ばかげた証拠」にするために書き直したい人。

    あなたは彼らに実用的なコードサンプルを提供することができますが、彼らはあなたのAPIを嫌い、それを書き直すことを主張します。彼らはあなたのAPIがおかしくて、それを改善したとあなたに言うでしょう。

    あなたはこれらの人々を「ばかげた耐性」のエスカレートする軍拡競争に参加させることができます。あなたがまとめたものはすべて分解されます。

この時点で、プライバシーはあなたのために何をしましたか?一部の人々はそれを理解することを拒否します。一部の人々はそれによって混乱しています。そして何人かの人々はそれを回避したいです。

パブリックはどうですか、そしてあなたが「ばか」と呼んでいる人々にあなたのコードから学ばせてください?

11
S.Lott

このテーマで人気のあるファッションとは異なり、areで働いているかどうかに関係なく、パブリック、プライベート、および保護されたメンバーを区別する正当な理由がありますPythonまたはより伝統的なOOP環境。多くの場合、オブジェクトの特殊化のレベルで、特に時間のかかるタスクのための補助メソッドを開発するようになります。言うまでもなく、これらのメソッドは、特殊なコンテキストでは意味がなく、表示されるべきではないため、サブクラスに継承されることは本当に望ましくありません。それでも、これらのメソッドは表示され、タブ補完、オブジェクトナビゲーターなどの有用性が低下します。システムソフトウェア。さまざまな抽象化レベルのすべてが平坦化されてまとめられるためです。これらのプログラミング支援は簡単ではありません。学生であり、同じことを何百万回も楽しんでいる場合にのみ、簡単です。方法を再学習します。

Pythonは歴史的に、官民の区別を実装することがイデオロギーの慣性と互換性の懸念のためにますます困難になるような方法で開発されました。それは明白な真実です。誰もが今までやってきたことを変えるのは本当に頭痛の種です。その結果、今では100万人のPythonファンがいて、そのすべてが同じ1つまたは2つの元の記事を読んで、公的/私的区別が「非Python的」であると明確に判断しています。広く一般的な慣行に対する批判的思考または公平性の欠如は、この機会を即座に使用して、予測可能な多数の弁証学を蓄積します--De Defensione Serpentis-これは合理的な選択からではないと私は考えていますvia pythonis(Pythonの方法)が、他の言語を無視しているため、使用しないことを選択したか、使用に熟練していないか、仕事のために使用できません。

すでに誰かが言ったように、プライベートメソッドと同様の効果を生み出すためにPythonでできる最善のことは、メソッド名の前に____(2つのアンダースコア)を付けることです。 、これが実際に達成する唯一のことは、オブジェクトの___dict___に変換された属性名を挿入することです。たとえば、次のクラス定義があるとします。

_class Dog(object):
    def __bark(self):
        print 'woof'
_

dir(Dog())を実行すると、__Dog__bark_という奇妙なメンバーが表示されます。確かに、このトリックが存在する唯一の理由は、前に説明した問題を回避することです。つまり、継承の防止、オーバーロード、およびスーパーメソッドの置き換えです。

将来、組織が個々の細胞がDNAを複製する方法にアクセスする必要がなく、意識的な心がその組織と内臓を修復する方法を常に理解する必要があることに人々が気付いたときに、プライベートメソッドの標準化された実装があることを願っています。

29
Dan Gabriele

Pythonでこれを本当に行う方法はありません。むしろ非Python的です。

Guidoが言うように、私たちは皆、ここで大人に同意しています。

ここに良いものがあります Python公開 のすべての背後にある哲学の要約。

28
Triptych

メソッドとメンバーの前に1つまたは2つのアンダースコアを付けることができます。単一の下線は「私を使用しないでください、私はこのクラスによってのみ使用されることになっています」を意味し、二重下線はPythonコンパイラにメソッド/メンバー名をマングルするように指示しますクラス名。クラスとそのサブクラスの名前が同じでない限り、メソッド/メンバーは「プライベート」と見なすことができます。

ただし、これまでの要件に対する解決策は、明確なドキュメントを作成することです。ユーザーが間違った順序でメソッドを呼び出さないようにする場合は、ドキュメントでそのように言ってください。

結局のところ、C++プライベートでさえそれほどプライベートではありません。たとえば、古いトリックを考えてみましょう。

#define private public
#include <module>
12
tzot

誰もこれについて言及していないことに驚いていますが、メソッド名の前に1つのアンダースコアを付けることは、「プライベート」としてラベルを付ける正しい方法です。それは実際にはそうではありませんプライベートもちろん(他の回答で説明されているように)、しかしあなたはそこに行きます。

def _i_am_private(self):
    """If you call me from a subclass you are a naughty person!"""
11
Ali Afshar

「すべてが公開されている必要があります」という支持者は、作成者が有用なAPIをユーザーから隠そうとしていると考えています。この男は、Pythonの疑う余地のない法則に違反したくありません。彼は、いくつかのメソッドを使用して有用なAPIを定義し、他のメソッドを使用してそのAPIの実装を整理したいと考えています。 2つの間に分離がない場合、それは作者がばかではないという意味ではありません。これは、作成者が怠惰すぎて実際にAPIを定義できなかったことを意味します。

Pythonでは、プロパティまたはメソッドをプライベートとしてマークする代わりに、弱い「内部使用」インジケーターとして___を付けるか、わずかに強いインジケーターとして____を付けることができます。モジュールでは、同じ方法で名前の前に___を付けることができます。また、モジュールのパブリックAPIを構成する一連の文字列を___all___という変数に入れることもできます。

愚かな一貫性は、小さな心のホブゴブリンです。

7
joeforker

これはかなりの概算かもしれません。 「レスキュー」への字句スコープ:

#!/usr/bin/env python

class Foo(object):
    def __init__(self, name):
        self.name = name
        self.bar()

    def bar(self):
        def baz():
            print "I'm private"
            print self.name

        def quux():
            baz()

        self.quux = quux


if __name__ == "__main__":
    f = Foo("f")
    f.quux()

    g = Foo("g")
    g.quux()

    f.quux()

プリント:

I'm private
f
I'm private
g
I'm private
f
7
joeforker

継承されたメソッドをパブリックからプライベートに変更する継承を解除します。具体的には、is-a関係を壊します。

オープンドアのパブリックメソッドを使用したレストランクラスを想像してみてください(つまり、ディナータイムで、正面玄関の看板を閉じた状態から開いた状態に切り替えたい)。ここで、レストランの実装の詳細の多くを共有するケータリングクラスが必要です(どちらも料理人、キッチン、料理、食品サプライヤー、さらには給仕が必要です)が、ダイニングエリア、正面玄関、またはオープンドアはありません方法。レストランからの相続は間違いです!誰も使用できないようにopen-doorsメソッドをprivateに変更するだけでよいように見えるかもしれませんが、Restaurantのパブリックインターフェイスの一部がopen-doorsであるため、「ケータリングオブジェクトはレストランです」は誤りです。新しい基本クラスを追加してRestaurantをリファクタリングし、RestaurantとCateringの両方がそれから派生することをお勧めします。

保護された継承またはプライベート継承の概念を持つ言語は、実装のためだけにこの継承の概念をサポートしますが、Pythonはそれらの1つではありません。非公開の継承が求められ、封じ込め(別名「has-arelationship」)がより良いパスです。属性を保護または非公開にすることもできます。

Pythonの呪文は、Triptychの回答に記載されている「同意する大人」の哲学を変更して、単一の先行アンダースコアで保護され、二重の先行アンダースコアでプライベートに保護されています。クラスの「危険な」属性とメソッド。例:データ損失を引き起こす可能性のあるものは、非公開にする必要があります(保護するか非公開にするかは、他の要因の影響を受けます)。公開メソッドを使用して、よりシンプルで安全なインターフェイスを提供します。

6
Roger Pate

メソッドを一種のプライベートにするために、次のようにメソッドに名前を付けることができます。

class Foo:
    def __blah():
        pass

class Bar(Foo):
    def callBlah():
        self.__blah() # will throw an exception

ただし、サブクラスは、本当に必要な場合でも、イントロスペクションを通じてメソッドを見つけることができます。

しかし、Python(意図的な設計と選択による)にはプライベートメンバーの概念はありません。

5
Dana

同意する大人の間でさえ、派生クラスにメソッドを公開したくない理由があります。問題は、親>子のような階層を持つことができるかということです。この階層では、ユーザーは親または子のいずれかから派生できますが、プライベートメソッドまたは保護されたメソッドは公開されません。次の例では、ChildはParent .__ privateを公開せずに明示的にオーバーロードします。

class Parent(object):
    def __private(self):
        print 'Parent'

    def go(self):
        self.__private()

class Child(Parent):
    def __init__(self):
        Parent.__init__(self)
        self._Parent__private = self.__private

    def __private(self):
        print 'Child'
1
James Thornbrue
class MyClass(object): 
    def _prtectedfunc(self):
        pass # with one undersocre

    def __privatefunc(self):
        pass # with two undersocre

http://linuxwell.com/2011/07/21/private-protected-and-public-in-python/

1
PersianGulf

このスレッドには多くの良い答えがありますが、ここに実用的な観点からいくらか意見のある答えがあります:

パブリックAPIから低レベルの変数とメソッドを非表示にする必要があります(別名ドキュメント)。したがって、これらのメンバーには常に_または__を添付してください。より大きな質問:それは_か__か?純粋主義者OOPパースペクティブは、常に__をプライベートメンバーに、_を「保護された」メソッド(つまり、アクセス可能、派生クラスからオーバーライド可能)にアタッチすることです。__は、派生クラスがそれをオーバーライドできないようにします。一方で、setattr、テスト容易性、読みやすさなどの使用も困難になります。

私の個人的な見解(および Googleのスタイルガイド )は、__をできるだけ避け、プライベートメンバーには_を使用することです。

しかし、保護されたメンバーはどうですか?図書館のユーザーに、何を上書きする必要があるか、何を上書きする必要があるかをどのように伝えるのですか?ここでは、保護されたメンバーにアンダースコアを使用せず、代わりにdocstringコメントとオプションで基本クラスの@abstractmethodに依存することを好みます。ここでの利点の1つは、保護されたメンバーがさまざまなドキュメントジェネレータから削除されないことです。

0
Shital Shah

このスレッドには多くの良い答えがありますが、ここに実用的な観点からいくらか意見のある答えがあります:

あなたdoパブリックAPI、インテリセンス、ドキュメント、import *などからのプライベートメンバーのクラッドを回避する必要があります。したがって、これらのメンバーには常に_または__を添付してください。

大きな質問:それは_か__か?純粋主義者OOPの観点は、常に__をプライベートメンバーに、_を保護されたメソッドにアタッチすることです。__は名前マングリングを行い、setattrib、テストフレームワークなどの使用を困難にし、読みやすさを低下させます。個人的な見解は、__を可能な限り避け、プライベートメンバーには_を使用することです。

しかし、派生クラスで使用したいがパブリックAPIとしては使用したくない保護されたメンバーについてはどうでしょうか。ここでの私の好みは、アンダースコアをまったく使用しないことです。これにより、これらのメンバーは公開ドキュメントにアクセスできます。次に、docstringを使用して、これらが次のように保護されたメンバーであることをユーザーに通知します。

class Class1:
  def _private1():
    pass

  def protected1():
    """(for derived classes) Does XYZ."""
    pass

  def public1()
    pass
0
Shital Shah