6

重複の可能性:
Python: クラス属性とインスタンス属性の違い

私は Python で OOP について頭を悩ませようとしていますが、クラス内で変数を宣言することになると少し混乱しています。__init__プロシージャの内部または外部で宣言する必要がありますか? 違いは何ですか?

次のコードは問題なく動作します。

# Declaring variables within __init__
class MyClass:
    def __init__(self):
        country = ""
        city = ""
    def information(self):
        print "Hi! I'm from %s, (%s)"%(self.city,self.country)

me = MyClass()
me.country = "Spain"
me.city = "Barcelona"
me.information()

ただし、プロシージャーの外で変数を宣言する__init__こともできます。

# Declaring variables outside of __init__
class MyClass:
    country = ""
    city = ""
    def information(self):
        print "Hi! I'm from %s, (%s)"%(self.city,self.country)

me = MyClass()
me.country = "Spain"
me.city = "Barcelona"
me.information()
4

3 に答える 3

13

最初の例では、インスタンス属性を定義しています。2 つ目は、クラスの属性です

クラス属性は、そのクラスのすべてのインスタンス間で共有されます。インスタンス属性は、その特定のインスタンスによって「所有」されます。

例による違い

違いを理解するために、例を使用してみましょう。

インスタンス属性を持つクラスを定義します。

class MyClassOne:
    def __init__(self):
        self.country = "Spain"
        self.city = "Barcelona"
        self.things = []

そして、クラス属性を持つもの:

class MyClassTwo:
    country = "Spain"
    city = "Barcelona"
    things = []

そして、これらのオブジェクトの 1 つに関する情報を出力する関数:

def information(obj):
    print "I'm from {0}, ({1}). I own: {2}".format(
                obj.city, obj.country, ','.join(obj.things))

MyClassOne2 つのオブジェクトを作成し、1 つを Milan に変更して、Milan に「何か」を与えましょう。

foo1 = MyClassOne()
bar1 = MyClassOne()

foo1.city = "Milan"
foo1.country = "Italy"
foo1.things.append("Something")

を呼び出すとinformation()、期待どおりの値が得られます。foo1bar1

>>> information(foo1)
I'm from Milan, (Italy). I own: Something

>>> information(bar1)
I'm from Barcelona, (Spain). I own: 

ただし、まったく同じことを行うと、 のインスタンスを使用MyClassTwoして、クラス属性がインスタンス間で共有されることがわかります。

foo2 = MyClassTwo()
bar2 = MyClassTwo()

foo2.city = "Milan"
foo2.country = "Italy"
foo2.things.append("Something")

そして、電話information()...

>>> information(foo2)
I'm from Milan, (Italy). I own: Something
>>> information(bar2)
I'm from Barcelona, (Spain). I own: Something

ご覧のとおり、 -thingsはインスタンス間で共有されています。things各インスタンスがアクセスできるリストへの参照です。したがって、任意のインスタンスからのものに追加すると、同じリストが他のすべてのインスタンスで表示されます。

文字列変数でこの動作が見られない理由は、実際には新しい変数をインスタンスに割り当てているためです。この場合、その参照はインスタンスによって「所有」され、クラス レベルでは共有されません。説明するために、新しいリストをのに割り当てましょうbar2

bar2.things = []

これにより、次の結果が得られます。

>>> information(foo2)
I'm from Milan, (Italy). I own: Something
>>> information(bar2)
I'm from Barcelona, (Spain). I own: 
于 2012-12-12T17:34:36.820 に答える
5

コードの 2 つのバージョンは非常に異なっています。Python では、クラスクラス インスタンスの 2 つの異なるエンティティが あります。インスタンスは、次の場合に作成されるものです。

new_instance = my_class()

(は新しいインスタンスです)__init__を介してインスタンスに属性をバインドできます。selfself

class MyClass(object):
    def __init__(self):
        self.country = ""  #every instance will have a `country` attribute initialized to ""

selfとについて特別なことは何もありません__init__すべてのメソッドselfに渡されるインスタンスを表すために使用される通常の名前です(デフォルト)。

a.method()  #-> Inside the class where `method` is defined, `a` gets passed in as `self`

ここで唯一特別なことは__init__、クラスの構築時に呼び出されることです。

a = MyClass()  #implicitly calls `__init__`

属性をクラスにバインドすることもできます (外部に置きます__init__):

class MyClass(object):
    country = ""  #This attribute is a class attribute.

いつでも、次の方法で新しい属性をインスタンスにバインドできます。

my_instance = MyClass()
my_instance.attribute = something

または、次を介してクラスに新しい属性を追加します。

MyClass.attribute = something

今、それは面白くなります。インスタンスに要求された属性がない場合、python は属性のクラスを調べて、それを返します (存在する場合)。したがって、クラス属性は、クラスのすべてのインスタンスがデータを共有する方法です。

検討:

def MyClass(object):
    cls_attr = []
    def __init__(self):
        self.inst_attr = []

a = MyClass()
a.inst_attr.append('a added this')
a.cls_attr.append('a added this to class')
b = MyClass()
print (b.inst_attr) # []  <- empty list, changes to `a` don't affect this.
print (b.cls_attr) # ['a added this to class'] <- Stuff added by `a`!
print (a.inst_attr) #['a added this']
于 2012-12-12T17:04:53.873 に答える
0

クラス スコープ (メソッド外) で変数を定義すると、それはクラス属性になります。メソッド スコープで値を定義すると、それはメソッド ローカル変数になります。selfの属性(またはオブジェクトを参照するその他のラベル) に値を割り当てると、インスタンス属性になります (または変更されます)。

于 2012-12-12T17:02:45.283 に答える