次の間に意味のある違いはありますか?
class A(object):
foo = 5 # some default value
対。
class B(object):
def __init__(self, foo=5):
self.foo = foo
多くのインスタンスを作成している場合、2つのスタイルのパフォーマンスまたはスペース要件に違いはありますか?コードを読むとき、2つのスタイルの意味が大幅に異なると思いますか?
次の間に意味のある違いはありますか?
class A(object):
foo = 5 # some default value
対。
class B(object):
def __init__(self, foo=5):
self.foo = foo
多くのインスタンスを作成している場合、2つのスタイルのパフォーマンスまたはスペース要件に違いはありますか?コードを読むとき、2つのスタイルの意味が大幅に異なると思いますか?
重要なセマンティックの違いがあります (パフォーマンスの考慮事項を超えて):
例えば:
>>> class A: foo = []
>>> a, b = A(), A()
>>> a.foo.append(5)
>>> b.foo
[5]
>>> class A:
... def __init__(self): self.foo = []
>>> a, b = A(), A()
>>> a.foo.append(5)
>>> b.foo
[]
違いは、クラスの属性がすべてのインスタンスで共有されることです。インスタンスの属性は、そのインスタンスに固有です。
C++ からの場合、クラスの属性は静的メンバー変数に似ています。
これは非常に良い投稿であり、以下に要約します。
class Bar(object):
## No need for dot syntax
class_var = 1
def __init__(self, i_var):
self.i_var = i_var
## Need dot syntax as we've left scope of class namespace
Bar.class_var
## 1
foo = MyClass(2)
## Finds i_var in foo's instance namespace
foo.i_var
## 2
## Doesn't find class_var in instance namespace…
## So look's in class namespace (Bar.__dict__)
foo.class_var
## 1
そして視覚的な形で
クラス属性の割り当て
クラスにアクセスしてクラス属性を設定すると、すべてのインスタンスの値が上書きされます
foo = Bar(2)
foo.class_var
## 1
Bar.class_var = 2
foo.class_var
## 2
インスタンスにアクセスしてクラス変数を設定すると、そのインスタンスの値のみがオーバーライドされます。これは基本的にクラス変数をオーバーライドし、直感的にそのインスタンスでのみ使用可能なインスタンス変数に変換します。
foo = Bar(2)
foo.class_var
## 1
foo.class_var = 2
foo.class_var
## 2
Bar.class_var
## 1
クラス属性はいつ使用しますか?
定数の格納。クラス属性はクラス自体の属性としてアクセスできるため、クラス全体のクラス固有の定数を格納するためにそれらを使用すると便利なことがよくあります。
class Circle(object):
pi = 3.14159
def __init__(self, radius):
self.radius = radius
def area(self):
return Circle.pi * self.radius * self.radius
Circle.pi
## 3.14159
c = Circle(10)
c.pi
## 3.14159
c.area()
## 314.159
デフォルト値の定義。些細な例として、制限付きリスト (つまり、特定の数以下の要素しか保持できないリスト) を作成し、デフォルトの上限を 10 アイテムにすることを選択する場合があります。
class MyClass(object):
limit = 10
def __init__(self):
self.data = []
def item(self, i):
return self.data[i]
def add(self, e):
if len(self.data) >= self.limit:
raise Exception("Too many elements")
self.data.append(e)
MyClass.limit
## 10
ここのコメントと、重複としてマークされた他の2つの質問の人々はすべて、これについて同じように混乱しているように見えるので、Alex Coventryの.
アレックスがリストのような可変型の値を割り当てているという事実は、物事が共有されているかどうかとは何の関係もありません。これは、id
関数またはis
演算子で確認できます。
>>> class A: foo = object()
>>> a, b = A(), A()
>>> a.foo is b.foo
True
>>> class A:
... def __init__(self): self.foo = object()
>>> a, b = A(), A()
>>> a.foo is b.foo
False
(なぜ私がobject()
の代わりにを使用したのか疑問に思っているなら5
、それは、ここでは触れたくない他の 2 つの問題に遭遇するのを避けるためです。2 つの異なる理由により、完全に個別に作成され5
た が最終的にnumber の同じインスタンス5
。ただし、完全に個別に作成されたobject()
はできません。)
では、なぜa.foo.append(5)
Alex の例では に影響するb.foo
のにa.foo = 5
、私の例では影響しないのでしょうか? さて、アレックスの例を試してみてください。そこにも影響がa.foo = 5
ないことに注意してください。b.foo
a.foo = 5
a.foo
の名前になっているだけです5
。b.foo
これは、 や、以前参照していた古い値の他の名前には影響しませんa.foo
。* クラス属性を隠すインスタンス属性を作成するのは少し難しいです**。ここで起こっています。
アレックスがリストを使用した理由が明らかになったといいのですが: リストを変更できるということは、2 つの変数が同じリストに名前を付けていることを示すのが簡単であることを意味します。同じリストの 2 つの名前。
* C++ のような言語を使用している人が混乱するのは、Python では値が変数に格納されないことです。値はそれ自体で値の土地に住んでいます。変数は値の名前にすぎず、代入は値の新しい名前を作成するだけです。それが役立つ場合は、各 Python 変数をshared_ptr<T>
ではなく と考えてT
ください。
** 一部の人々は、クラス属性を、インスタンスが設定する場合と設定しない場合があるインスタンス属性の「デフォルト値」として使用することで、これを利用しています。これは場合によっては便利ですが、混乱を招く可能性もありますので注意してください。