web-dev-qa-db-ja.com

クラス変数とインスタンス変数の違いは何ですか?

Pythonのクラス変数とインスタンス変数の違いは何ですか?

_class Complex:
    a = 1
_

そして

_class Complex:
    def __init__(self):
        self.a = 1
_

呼び出しの使用:x = Complex().aはどちらの場合もxを1に割り当てます。

__init__()およびselfについてのより詳細な回答をいただければ幸いです。

59

クラスブロックを記述するとき、クラス属性(またはクラス変数)を作成します。 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という名前の属性がありません。しかし、mylistclassはそうであり、メソッドオブジェクトにバインドされています。そのメソッドオブジェクトは_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_でクラス属性にアクセスできることを確認するのは、ほとんど簡単になります。 iClassは両方ともオブジェクトであり、オブジェクトには属性があります。これにより、作成後にクラスを変更する方法を簡単に理解できます。他のオブジェクトと同じ方法で属性を割り当ててください!

実際、インスタンスは、それらを作成するために使用されるクラスと特別な特別な関係を持ちません。 Pythonは、インスタンスで見つからない属性を検索するクラスを知る方法は、隠された___class___属性です。これは、どのクラスであるかを調べるために読むことができます他の属性と同じように、インスタンス:_c = some_instance.__class___。クラスと同じ名前を持っていない場合でも、変数cがクラスにバインドされました。これにより、クラス属性にアクセスしたり、呼び出してさらにインスタンスを作成したりできます(クラスが何であるかわからない場合でも!)。

また、_i.__class___に割り当てて、インスタンスのクラスを変更することもできます!これを行うと、特に何もすぐには起こりません。それは驚くべきことではありません。つまり、インスタンスに存在しない属性を検索すると、Pythonは___class___の新しいコンテンツを検索します。これにはほとんどのメソッドが含まれているため、メソッドは通常、操作しているインスタンスが特定の状態にあることを期待するため、ランダムに実行するとエラーが発生し、非常に混乱しますが、実行できます。 ___class___に保存することはクラスオブジェクトである必要さえありません;それに関連するすべてのPythonは特定の状況下で属性を検索するので、必要なのは適切な種類の属性を持つオブジェクトだけです(いくつかの警告ここでPythonは特定のクラスのクラスまたはインスタンスであることに気を配ります)。

おそらく今のところはこれで十分です。願わくば(ここまで読んだことがあるなら)混乱させないでください。 Pythonは、どのように機能するかを学ぶとすてきです。:)

105
Ben

「インスタンス」変数と呼んでいるものは、実際にはインスタンス変数ではありません。 クラス変数です。 クラスに関する言語リファレンス を参照してください。

この例では、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はそのインスタンスへの参照です。

10
voithos