Pythonのクラス変数とインスタンス変数の違いは何ですか?
_class Complex:
a = 1
_
そして
_class Complex:
def __init__(self):
self.a = 1
_
呼び出しの使用:x = Complex().a
はどちらの場合もxを1に割り当てます。
__init__()
およびself
についてのより詳細な回答をいただければ幸いです。
クラスブロックを記述するとき、クラス属性(またはクラス変数)を作成します。 def
で定義するメソッドを含む、クラスブロックで割り当てるすべての名前がクラス属性になります。
クラスインスタンスが作成された後、インスタンスへの参照を持つものはすべて、インスタンス属性を作成できます。メソッド内部では、「現在の」インスタンスはほとんど常にself
という名前にバインドされているため、これらを「自己変数」と考えています。通常、オブジェクト指向の設計では、クラスにアタッチされたコードはそのクラスのインスタンスの属性を制御することになっているため、ほとんどすべてのインスタンス属性の割り当ては、self
メソッドのパラメーター。
多くの場合、クラス属性は、Java、C#、C++などの言語で見られるstatic変数(またはメソッド)と比較されます。ただし、より深い理解を目指したい場合は、クラス属性を静的変数と「同じ」と考えることは避けます。多くの場合同じ目的で使用されますが、基本的な概念はまったく異なります。これについては、行の下の「詳細」セクションで説明します。
例!
_class SomeClass:
def __init__(self):
self.foo = 'I am an instance attribute called foo'
self.foo_list = []
bar = 'I am a class attribute called bar'
bar_list = []
_
このブロックの実行後、3つのクラス属性を持つクラスSomeClass
があります:___init__
_、bar
、および_bar_list
_。
次に、インスタンスを作成します。
_instance = SomeClass()
_
これが発生すると、SomeClass
の___init__
_メソッドが実行され、self
パラメーターで新しいインスタンスを受け取ります。このメソッドは、2つのインスタンス属性foo
および_foo_list
_を作成します。次に、このインスタンスはinstance
変数に割り当てられるため、2つのインスタンス属性foo
および_foo_list
_を持つものにバインドされます。
だが:
_print instance.bar
_
与える:
_I am a class attribute called bar
_
どうしてそうなった?ドット構文で属性を取得しようとすると、属性が存在しない場合、Pythonとにかくリクエストを処理するための一連の手順です。次に行うことは、インスタンスのクラスのclass attributesを調べることです。この場合、bar
で属性SomeClass
が見つかったため、それを返しました。
それはまた、メソッド呼び出しの仕組みです。たとえば、mylist.append(5)
を呼び出すと、mylist
にはappend
という名前の属性がありません。しかし、mylist
のclassはそうであり、メソッドオブジェクトにバインドされています。そのメソッドオブジェクトは_mylist.append
_ビットによって返され、_(5)
_ビットは引数_5
_でメソッドを呼び出します。
これが便利な方法は、allSomeClass
のインスタンスが同じbar
属性にアクセスできることです。 100万個のインスタンスを作成できますが、すべての文字列を見つけることができるため、その1つの文字列をメモリに保存するだけで済みます。
ただし、少し注意する必要があります。次の操作をご覧ください。
_sc1 = SomeClass()
sc1.foo_list.append(1)
sc1.bar_list.append(2)
sc2 = SomeClass()
sc2.foo_list.append(10)
sc2.bar_list.append(20)
print sc1.foo_list
print sc1.bar_list
print sc2.foo_list
print sc2.bar_list
_
これは何を印刷すると思いますか?
_[1]
[2, 20]
[10]
[2, 20]
_
これは、各インスタンスに_foo_list
_の独自のコピーがあるため、個別に追加されたためです。ただし、allインスタンスは同じ_bar_list
_へのアクセスを共有します。したがって、sc1.bar_list.append(2)
を実行すると、_sc2
_がまだ存在していなくても、_sc2
_に影響がありました。同様に、sc2.bar_list.append(20)
は、_bar_list
_を通じて取得した_sc1
_に影響を与えました。多くの場合、これはあなたが望むものではありません。
高度な研究が続きます。 :)
JavaやC#のような静的に型付けされた従来のOO言語から来たPythonを本当に理解するには、クラスを少し考え直すことを学ぶ必要があります。
Javaでは、クラスは実際にはthingそのものではありません。クラスを書くとき、そのクラスのすべてのインスタンスが共通して持っているものをより多く宣言しています。実行時には、インスタンス(および静的メソッド/変数、ただし、これらは実際にはクラスに関連付けられた名前空間内のグローバル変数と関数にすぎず、OO実際には何もしません)。クラスは実行時にインスタンスがどのようになるかをソースコードに書き留める方法;インスタンスは実行中のプログラムではなく、ソースコードにのみ存在します。
Pythonでは、クラスは特別なものではありません。それは他の何かと同じオブジェクトです。したがって、「クラス属性」は実際には「インスタンス属性」とまったく同じものです。現実には「属性」だけがあります。区別する唯一の理由は、クラスではないオブジェクトとは異なるクラスであるオブジェクトをuseする傾向があるからです。基礎となる機械はすべて同じです。これが、クラス属性を他の言語の静的変数と考えるのは間違いだと言う理由です。
しかし、実際にPython Javaスタイルのクラスとは異なるクラスを作成することは、他のオブジェクトと同じことです各クラスはあるクラスのインスタンスです!
Pythonでは、ほとんどのクラスはtype
と呼ばれる組み込みクラスのインスタンスです。クラスの一般的な動作を制御するのはこのクラスであり、すべてのOOのように処理します。デフォルトのOOクラスのインスタンスを持つ方法独自の属性を持ち、クラスで定義された共通のメソッド/属性を持つPythonは単なるプロトコルです。必要に応じて、ほとんどの部分を変更できます。metaclass、それはtype
とは異なるクラスのインスタンスであるクラスを定義することだけです。
クラスに関する唯一の「特別な」こと(デフォルトで動作するようにするすべての組み込み機構を除く)は、type
のインスタンスを簡単に作成できるようにするクラスブロック構文です。 。この:
_class Foo(BaseFoo):
def __init__(self, foo):
self.foo = foo
z = 28
_
以下とほぼ同等です。
_def __init__(self, foo):
self.foo = foo
classdict = {'__init__': __init__, 'z': 28 }
Foo = type('Foo', (BaseFoo,) classdict)
_
そして、classdict
のすべてのコンテンツが作成されるオブジェクトの属性になるように調整します。
したがって、i = Class(); i.attribute
と同じように簡単に_Class.attribute
_でクラス属性にアクセスできることを確認するのは、ほとんど簡単になります。 i
とClass
は両方ともオブジェクトであり、オブジェクトには属性があります。これにより、作成後にクラスを変更する方法を簡単に理解できます。他のオブジェクトと同じ方法で属性を割り当ててください!
実際、インスタンスは、それらを作成するために使用されるクラスと特別な特別な関係を持ちません。 Pythonは、インスタンスで見つからない属性を検索するクラスを知る方法は、隠された___class__
_属性です。これは、どのクラスであるかを調べるために読むことができます他の属性と同じように、インスタンス:_c = some_instance.__class__
_。クラスと同じ名前を持っていない場合でも、変数c
がクラスにバインドされました。これにより、クラス属性にアクセスしたり、呼び出してさらにインスタンスを作成したりできます(クラスが何であるかわからない場合でも!)。
また、_i.__class__
_に割り当てて、インスタンスのクラスを変更することもできます!これを行うと、特に何もすぐには起こりません。それは驚くべきことではありません。つまり、インスタンスに存在しない属性を検索すると、Pythonは___class__
_の新しいコンテンツを検索します。これにはほとんどのメソッドが含まれているため、メソッドは通常、操作しているインスタンスが特定の状態にあることを期待するため、ランダムに実行するとエラーが発生し、非常に混乱しますが、実行できます。 ___class__
_に保存することはクラスオブジェクトである必要さえありません;それに関連するすべてのPythonは特定の状況下で属性を検索するので、必要なのは適切な種類の属性を持つオブジェクトだけです(いくつかの警告ここでPythonは特定のクラスのクラスまたはインスタンスであることに気を配ります)。
おそらく今のところはこれで十分です。願わくば(ここまで読んだことがあるなら)混乱させないでください。 Pythonは、どのように機能するかを学ぶとすてきです。:)
「インスタンス」変数と呼んでいるものは、実際にはインスタンス変数ではありません。 クラス変数です。 クラスに関する言語リファレンス を参照してください。
この例では、a
は不変であるため、インスタンス変数のように見えます。可変オブジェクトを割り当てた場合にclass変数が見られるという性質があります。
>>> class Complex:
>>> a = []
>>>
>>> b = Complex()
>>> c = Complex()
>>>
>>> # What do they look like?
>>> b.a
[]
>>> c.a
[]
>>>
>>> # Change b...
>>> b.a.append('Hello')
>>> b.a
['Hello']
>>> # What does c look like?
>>> c.a
['Hello']
self
を使用した場合、それは真のインスタンス変数になるため、各インスタンスは独自の一意のa
を持ちます。オブジェクトの__init__
関数は 新しいインスタンスが作成されたときに呼び出される であり、self
はそのインスタンスへの参照です。