1. ホーム
  2. python

[解決済み] Pythonの名前のマングリング

2022-07-08 04:44:37

質問

他の言語では、より良いコードを生成するための一般的なガイドラインとして、常に可能な限りすべてを隠すようにすることが挙げられます。もし変数がprivateかprotectedか迷ったら、privateにするのがよいでしょう。

同じことがPythonにも当てはまりますか?最初はすべてのものに2つの先行するアンダースコアを使用し、必要なときだけそれらをより隠さなくする (1つのアンダースコアのみ) べきでしょうか?

もし慣習として1つのアンダースコアだけを使うのであれば、その根拠も知りたいです。

以下は、私が JBernardoの回答 . 私がなぜこの質問をしたのか、また、なぜPythonが他の言語と違うのかを知りたいのかが説明されています。

私は、すべてのものは必要なものだけ公開され、それ以上は公開されるべきではないと考えるように訓練された言語から来ました。その理由は、そうすることで依存関係を減らし、コードをより安全に変更できるようになるからです。公開から始まって隠蔽に向かうという、物事を逆に行うPythonのやり方は、私には奇妙です。

どのように解決するのですか?

迷ったら、"public" のままにする - つまり、属性名をわかりにくくするようなものを追加しないことです。もし、何らかの内部値を持つクラスがあるのなら、それを気にする必要はありません。書くかわりに

class Stack(object):

    def __init__(self):
        self.__storage = [] # Too uptight

    def push(self, value):
        self.__storage.append(value)

はデフォルトでこれを書きます。

class Stack(object):

    def __init__(self):
        self.storage = [] # No mangling

    def push(self, value):
        self.storage.append(value)

これは確かに物議を醸す方法です。Pythonの初心者はこれを嫌い、Pythonの古株でさえこのデフォルトを軽蔑しています - しかし、いずれにせよこれはデフォルトなので、たとえ不快に感じてもこれに従うことをお勧めします。

もしあなたが 本当に をユーザーに送りたい場合、通常の方法は、変数の前に 1 というアンダースコアを付けることです。これは単なる慣習ですが、人々はこれを理解し、このようなものを扱うときには二重の注意を払うのです。

class Stack(object):

    def __init__(self):
        self._storage = [] # This is ok, but Pythonistas use it to be relaxed about it

    def push(self, value):
        self._storage.append(value)

これは、プロパティ名と属性名の衝突を避けるためにも有効です。

 class Person(object):
     def __init__(self, name, age):
         self.name = name
         self._age = age if age >= 0 else 0
     
     @property
     def age(self):
         return self._age
     
     @age.setter
     def age(self, age):
         if age >= 0:
             self._age = age
         else:
             self._age  = 0

ダブルアンダースコアについてはどうでしょうか?ダブルアンダースコアの魔法を使うのは主に メソッドを誤ってオーバーロードしてしまったり、スーパークラスの属性と名前が衝突してしまったりするのを避けるためです。 . 何度も拡張されるようなクラスを書く場合、これはかなり貴重なものになります。

他の目的で使用したい場合は可能ですが、通常でも推奨でもありません。

EDIT : なぜそうなのでしょうか?通常のPythonのスタイルは、物事を非公開にすることを重視していません - その逆です! その理由はたくさんあるのですが、そのほとんどは議論を呼ぶものです...。そのうちのいくつかを見てみましょう。

Pythonにはプロパティがある

今日、ほとんどのOO言語では、反対のアプローチを採用しています。理論的には、誰もオブジェクトの値を無闇に変更しないので、これはより管理しやすく、結合の少ないクラスをもたらすでしょう。

しかし、そう単純ではありません。例えば、Javaのクラスは多くのゲッターを持ちますが、そのゲッターには を取得します。 という値を のみのセッターです。 を設定します。 を設定するだけです。一つの属性を宣言するために、例えば7行のコードが必要です。Pythonのプログラマーなら、これは不必要に複雑だと言うでしょう。また、実際にはゲッターとセッターを使ってその値を変更できるため、1つのパブリックフィールドを取得するために多くのコードを書くことになります。

では、なぜこのprivate-by-defaultのポリシーに従うのでしょうか?属性をデフォルトでpublicにすればいいのです。もちろん、これはJavaでは問題があります。なぜなら、もしあなたが属性に何らかの検証を加えることにしたら、すべてを変更する必要があるからです。

person.age = age;

をあなたのコードで、言ってみましょう。

person.setAge(age);

setAge() である。

public void setAge(int age) {
    if (age >= 0) {
        this.age = age;
    } else {
        this.age = 0;
    }
}

ですから、Java(や他の言語)では、とにかくゲッターとセッターを使うのがデフォルトです。書くのは面倒ですが、私が説明したような状況に陥った場合、多くの時間を節約することができます。

しかし、Pythonにはプロパティがあるので、Pythonでそれを行う必要はありません。もし、このクラスが

 class Person(object):
     def __init__(self, name, age):
         self.name = name
         self.age = age

...そして、年齢を検証することにした場合、このメソッドは変更する必要はありません。 person.age = age の部分を変更する必要はありません。ただ、(以下に示すように)プロパティを追加するだけです。

 class Person(object):
     def __init__(self, name, age):
         self.name = name
         self._age = age if age >= 0 else 0
     
     @property
     def age(self):
         return self._age
     
     @age.setter
     def age(self, age):
         if age >= 0:
             self._age = age
         else:
             self._age  = 0

仮に、それができてなおかつ person.age = age が使えるとしたら、なぜプライベートフィールドやゲッターやセッターを追加するのでしょうか?

(また PythonはJavaではありません ゲッターとセッターを使うことの害について書かれたこの記事 .).

とにかくすべてが見える - そして隠そうとすると作業が複雑になる

プライベート属性を持つ言語においてさえ、いくつかのリフレクション/イントロスペクションライブラリを通してそれらにアクセスすることができます。そして、人々はフレームワークや緊急の必要性を解決するために、それをたくさん行います。問題は、イントロスペクションライブラリは、パブリック属性でできることを行う複雑な方法に過ぎないということです。

Pythonは非常に動的な言語なので、クラスにこの負担を追加することは逆効果です。

問題は見ることができないことではありません。 が必要であることです。 であることです。

Pythonistaにとって、カプセル化はクラスの内部を見ることができないことではなく、それを見ないようにすることができることです。カプセル化とは、ユーザーが内部の詳細を気にすることなく使用できるコンポーネントの特性です。もしあなたがその実装について気にせずにコンポーネントを使うことができるなら、それは(Pythonプログラマーの意見では)カプセル化されていると言えます。

さて、実装の詳細を考えずに使えるクラスを書いたのであれば、もし 欲しい が何らかの理由でクラスの内部を覗きたい場合にも問題ありません。ポイントは、APIが優れていることであり、あとは細部です。

Guidoはそう言いました

まあ、これは議論の余地がない。 彼はそう言った、実際に . ("open kimono."で検索してください)

これが文化だ

はい、いくつかの理由はありますが、決定的な理由はありません。これは主にPythonでプログラミングする際の文化的な側面です。率直に言って、それは他の方法でもあり得ます - しかし、そうではありません。また、逆に聞くこともできます。ある言語ではなぜデフォルトでprivate属性を使うのでしょうか?それはこれらの言語の文化であり、それぞれの選択には利点と欠点があるからです。

すでにこの文化があるのですから、それに従うのが得策です。さもなければ、Pythonのプログラマーに __ を削除するよう指示されることになります。)