Java/PHP から来た場合、Python がオブジェクト指向をどのように行うかについて知っておく必要があるいくつかのポイントを次に示します。
Python では、クラスも完全に普通のオブジェクトです。つまり、クラス自体がメンバー変数を持つことができます (通常は属性と呼びます)。クラス ブロックで割り当てた名前はすべて、そのインスタンスの属性ではなく、クラス自体の属性になります (def
メソッドを作成する関数ブロックを含みます。メソッドはすべて Python にあります)。
通常は 1 つのクラスと多数のインスタンスがあるため、クラス属性は Java クラスの静的変数と同様の目的を果たすことができますが、まったく同じ概念ではありません。
クラス ブロックで名前を割り当てても、クラスの実際のインスタンスに属性が作成されることはありません。オブジェクト (任意のオブジェクト、クラス、または通常のインスタンス) に属性を作成する唯一の方法は、それが存在するときに属性を割り当てることです。したがって、クラスのインスタンスが持つすべての変数の標準的な宣言は__init__
、Python のメソッドに存在し、属性を に割り当てる必要がありますself
。
例えば:
class Foo(object):
foo = "I am a class attribute"
def __init__(self):
self.bar = "I am an instance attribute"
これが新しい Python プログラマーをしばしば混乱させるのは、インスタンスから属性を読み取ろうとする試みが実際foo
に機能し、クラス属性を見つけることです (これは、メソッド呼び出しが呼び出すはずの関数を見つける方法です)。そのため、クラス ブロックでインスタンス属性を宣言することは、最初のカジュアルな遊びのように見えます。しかし、実際にはfoo
、すべてのインスタンス間で共有される属性は 1 つだけです。これは、可変オブジェクトであり、各インスタンスに独自のコピーがあると予想される場合、非常に悪い可能性があります。
Python にはアクセス制御がないため、プライベート変数のようなものはありません。これは、Python が十分に動的であるため、そのような制限をいつでも回避できるため、少し無意味になります。
代わりに、Python プログラマーは、クライアント コードを記述するプログラマーがどの名前がパブリック API の一部であり、どの名前が実装の詳細であるかを確実に把握できるようにするために、ドキュメントと規則に依存する傾向があります。次に、誰もがルールをほぼ尊重し、コードを処理する必要がないものは、変更に頼るべきではないと信じています。
とにかく、どの言語でも、単純なゲッターとセッターを持つ属性は実際には「パブリック」です。考えられる唯一の懸念は、「いつか」getter/setter の実装を変更して、インターフェイスを変更しないと簡単ではなくなることです。Python は、プロパティを使用してこの問題に対処できます (基本的に、属性の読み取りまたは書き込みのように見えるメソッド呼び出しを行うことができます)。そのため、実際に何かが行われている場合を除き、getter/setter メソッドを使用する理由はまったくありません。
そのため、通常、クライアント コードがオブジェクトを操作するためのインターフェイスにフィールドの読み取りと書き込みが含まれる場合は、通常の属性が読み取りと書き込みに使用できることを単純に文書化します。属性 (またはメソッド) が純粋に内部使用であることを明確にしたい場合は、通常、名前を 1 つのアンダースコアで開始します。これにより、その名前を使用する人は誰でも内部名にアクセスしていることを知ることができます (先頭のアンダースコアを入力する必要があるため)。そのため、誰かが「誤って」プライベート属性を使用することを心配する必要はありません。
コンストラクターに関しては、__init__
メソッドを__construct
PHP からのものとして扱うだけで、期待どおりに動作します (ただし、Python メソッドは明示的にパラメーターを受け取ることを忘れないでself
ください。暗黙的ではありませんthis
)。
__init__
コンストラクターとは多少異なるこの神話が広まっているため、コンストラクターと呼ぶべきではありません。私が知る限り、犯人はDive Into Pythonであり、奇妙なことに次のように述べています。
これをクラスのコンストラクターと呼ぶのは魅力的ですが、正しくありません。コンストラクターのように見え (慣例により__init__
、クラスに対して定義された最初のメソッド)、コンストラクターのように動作し (クラスの新しく作成されたインスタンスで実行される最初のコード部分)、さらにはコンストラクターのように聞こえる ( 「init」は確かにコンストラクターっぽい性質を示唆しています)。が呼び出されるまでにオブジェクトが既に構築されており__init__
、クラスの新しいインスタンスへの有効な参照が既に存在するため、不正解です。
しかし、「オブジェクト__init__
は呼び出されるまでにすでに構築されており、クラスの新しいインスタンスへの有効な参照がすでにある」というのは、従来のコンストラクターがどのように機能するかを正確に特徴付けているため、作成者がそこで何をしようとしているのかわかりません.
( Python のドキュメントが取っているように見える公式の行は、それMyClass(arg1, arg2)
がコンストラクター式__init__
であるというものです。どちらも__new__
、コンストラクター式に与えられた引数を受け取ると説明されており、__init__
明示的にコンストラクターと呼ばれています。これらの用語は両方ともめったに使用されません。ドキュメントでは、彼らは__init__
ほとんどいつも言っているだけです。)
したがって、これはコンストラクターではないと言う人を無視することを強くお勧めします。コンストラクターとの類推によって理解しようとする方が、コンストラクターとコンストラクターとの間の重要な違いを理解しようとする__init__
よりもはるかに優れています。__init__
__init__
以上をまとめると、PHP クラスの慣用的な翻訳は次のようになります。
class MyClass(object):
def __init__(self, myMember):
self.myMember = myMember