さて、まず最初に。
Python には「変数の宣言」や「変数の初期化」というものはありません。
単に「割り当て」と呼ぶものがありますが、おそらく「ネーミング」と呼ぶべきでしょう。
割り当てとは、「左側のこの名前は、以前に何を参照していたかに関係なく、右側を評価した結果を参照するようになった」ことを意味します。
foo = 'bar' # the name 'foo' is now a name for the string 'bar'
foo = 2 * 3 # the name 'foo' stops being a name for the string 'bar',
# and starts being a name for the integer 6, resulting from the multiplication
そのため、Python の名前 (おそらく「変数」よりも適切な用語) には関連する型がありません。値はそうです。タイプに関係なく、同じ名前を何にでも再適用できますが、そのタイプに依存する振る舞いは依然として存在します。名前は、単に値 (オブジェクト) を参照する方法です。これは 2 番目の質問に答えます:カスタム型を保持する変数を作成しません。特定の型を保持する変数を作成しません。変数をまったく「作成」しません。オブジェクトに名前を付けます。
2 番目のポイント: Python は、クラスに関して非常に単純な規則に従います。これは、Java、C++、C# などの言語よりも実際にははるかに一貫性があります。ブロック内で宣言されたものはすべてclass
、クラスの一部です。したがって、ここに記述された関数 ( def
) はメソッド、つまりクラス オブジェクトの一部 (インスタンスごとに保存されない) であり、Java、C++、および C# と同様です。ただし、ここにある他の名前もクラスの一部です。繰り返しますが、名前は単なる名前であり、関連付けられた型はありません。Python では関数もオブジェクトです。したがって:
class Example:
data = 42
def method(self): pass
Python では、クラスもオブジェクトです。
これで、 であるすべてのもののクラスを表すという名前のオブジェクトが作成されました。このオブジェクトには、2 つのユーザー指定の属性があります(C++ では「メンバー」、C# では「フィールドまたはプロパティまたはメソッド」、Java では「フィールドまたはメソッド」)。それらの 1 つに名前が付けられ、整数値が格納されます。もう 1 つは という名前で、関数オブジェクトを格納します。(Python が自動的に追加する属性が他にもいくつかあります。)Example
Example
data
42
method
ただし、これらの属性は実際にはオブジェクトの一部ではありません。基本的に、オブジェクトは複数の名前 (属性名) の集まりにすぎません。これ以上分割できないものに到達するまでは。したがって、意図的に設定すれば、クラスの異なるインスタンス間、または異なるクラスのオブジェクト間で値を共有できます。
インスタンスを作成しましょう:
x = Example()
x
これで、 のインスタンスであるという名前の別のオブジェクトができましたExample
。data
とは実際にはオブジェクトの一部ではありませんが、Python が舞台裏で行ういくつかの魔法により、method
これらを参照することはできます。特にx
を検索すると、代わりに「バインドされたメソッド」が得られます (呼び出すと、パラメータとして自動的に渡されますが、直接検索すると発生しません)。method
x
self
Example.method
を使おうとするとどうなりますx.data
か?
それを調べると、最初にオブジェクトで検索されます。オブジェクトに見つからない場合、Python はクラスを調べます。
ただし、 に割り当てると x.data
、Python はオブジェクトに属性を作成します。クラスの属性は置き換えられません。
これにより、オブジェクトの初期化を行うことができます。__init__
Python は、新しいインスタンスが作成されたときに、そのクラスのメソッドを自動的に呼び出します (存在する場合)。このメソッドでは、単純に属性に割り当てて、各オブジェクトのその属性の初期値を設定できます。
class Example:
name = "Ignored"
def __init__(self, name):
self.name = name
# rest as before
name
を作成するときに を指定する必要がありExample
、各インスタンスには独自の がありname
ます。インスタンスの属性が最初に見つかるため、Python はインスタンスのExample.name
を検索するたびにclass 属性を無視します。.name
最後の警告:変更 (突然変異) と代入は別物です!
Python では、文字列は不変です。それらは変更できません。あなたがするとき:
a = 'hi '
b = a
a += 'mom'
元の「hi」文字列は変更しません。それはPythonでは不可能です。代わりに、新しいstring'hi mom'
を作成し、 が の名前ではなくなり、代わりに のa
名前'hi '
になり始め'hi mom'
ます。b
にも名前を付けました。名前を再'hi '
適用した後も、まだ存在し、変更されていないため、 のa
名前b
のままです。'hi '
'hi '
ただし、リストは変更できます。
a = [1, 2, 3]
b = a
a += [4]
これb
も [1, 2, 3, 4]b
です。同じ名前の名前を付けてから、そのa
名前を変更したからです。a
Python は単純にリストの扱いが+=
異なるため、 to nameの新しいリストを作成しませんでした。
クラス属性としてリストがあり、インスタンスを使用してリストを変更した場合、変更は他のすべてのインスタンスで「見られる」ため、これはオブジェクトにとって重要です。これは、(a) データが実際にはクラス オブジェクトの一部であり、インスタンス オブジェクトではないためです。(b) リストを変更していて単純な代入を行っていないため、クラス属性を隠す新しいインスタンス属性を作成していません。