61

私はPythonを学んでいて、Cのバックグラウンドを持っているので、両方に混乱や混乱がある場合はお知らせください。

次のクラスがあると仮定します。

class Node(object):
    def __init__(self, element):
        self.element = element
        self.left = self.right = None

    @classmethod
    def tree(cls, element, left, right):
        node = cls(element)
        node.left = left
        node.right = right
        return node

Nodeこれは、コンストラクターをオーバーロードして、必要に応じてさまざまな引数を処理できるようにする、という名前のクラスです。

次のことを行うのとは対照的に、(上記のように)のみで定義self.elementすることの違いは何ですか?__init__

class Node(object):
    element, left, right = None
    def __init__(self, element):
        self.element = element
        self.left = self.right = None

クラスの変数が定義されているのと同じself.elementではありませんか?渡された値をから上書きするだけではないでしょうか。__init__elementelementNoneelement__init__

4

7 に答える 7

99

1つはクラス属性で、もう1つはインスタンス属性です。それらは異なりますが、時々同じように見えるように互いに密接に関連しています。

これは、Pythonが属性を検索する方法と関係があります。階層があります。単純なケースでは、次のようになります。

instance -> Subclass -> Superclass -> object (built-in type)

このような属性を探すときinstance...

`instance.val`

...実際に起こることは、最初valに、Pythonがインスタンス自体を検索することです。次に、が見つからない場合valは、そのクラスを調べますSubclass。次に、そこに見つからない場合は、valの親を調べます。これは、これを行うと...SubclassSuperclass

>>> class Foo():
    foovar = 10  
    def __init__(self, val):
        self.selfvar = val

Foo ...共有 のすべてのインスタンスですfoovarが、独自の独自selfvarのがあります。これがどのように機能するかの簡単で具体的な例です。

>>> f = Foo(5)
>>> f.foovar
10
>>> Foo.foovar
10

触れない場合はfoovar、との両方fで同じですFoo。しかし、私たちが変更した場合f.foovar...

>>> f.foovar = 5
>>> f.foovar
5
>>> Foo.foovar
10

...の値を効果的にマスクするインスタンス属性を追加しますFoo.foovar。ここで、直接変更しても、インスタンスFoo.foovarには影響しません。foo

>>> Foo.foovar = 7
>>> f.foovar
5

ただし、新しいfooインスタンスには影響します。

>>> Foo(5).foovar
7

また、可変オブジェクトは間接参照の別のレイヤーを追加することにも注意してください(mgilsonが私に思い出させたように)。ここでf.foovarは、と同じオブジェクトを参照しているFoo.foovarため、オブジェクトを変更すると、変更は階層の上位に伝播されます。

>>> Foo.foovar = [1]
>>> f = Foo(5)
>>> f.foovar[0] = 99
>>> Foo.foovar
[99]
于 2012-09-13T15:39:02.040 に答える
23

Pythonでは、同じ名前のクラス変数とインスタンス変数を持つことができます。それらはメモリ内に別々に配置されており、アクセス方法はまったく異なります。

あなたのコードでは:

class Node(object):
    element, left, right = None
    def __init__(self, element):
        self.element = element
        self.left = self.right = None

(関数の外にある__init__)最初の変数のセットは、クラス変数と呼ばれます。これらは、などを使用して後でアクセスできますNode.element。これらは、C ++の静的メンバー変数と同等であり、クラスのすべてのインスタンスで共有されます。

(関数内の)2番目の変数セットは__init__インスタンス変数と呼ばれます。selfこれらは、オブジェクトを介して、たとえばself.element、またはインスタンス名によって、たとえばmyNode.elementクラスの外部からアクセスされます。

メンバー関数内からこれらのいずれかにアクセスするには、self.variableまたはフォームのいずれかを使用する必要があることに注意してください。Node.variableアクセスするだけvariableで、と呼ばれるローカル変数にアクセスしようとしますvariable

于 2012-09-13T15:42:46.000 に答える
2

self.elementコンストラクター(つまり-__init__メソッド)の内部にはインスタンス変数があり(ノードオブジェクトがその値を変更すると、このオブジェクトに対してのみ変更されます)、2番目のバージョンのインスタンスはクラス変数です(したがって、1つのノードオブジェクトがその値を変更すると、変更されます)すべてのノードオブジェクトに対して)。

C ++の例えは、クラス内の非静的メンバー変数と静的メンバー変数です。

于 2012-09-13T15:29:03.733 に答える
1

重要な部分はへのself引数__init__です。実際、どのインスタンスメソッドでも、これが最初の引数になります。これは設計によって行われます。Pythonでは、インスタンスに実際にアクセスできるのはメソッド呼び出し中のみであり、self引数とともに明示的に示されます。

定義の中にいるときは、classまだインスタンスがないので、実際に変更しているのはクラス自体です。したがって、クラスレベルで属性を定義すると、それらは実際にはインスタンスではなくクラス属性になります。

C ++と比較すると、これらの言語の「クラス」は、基本的に、それらが表すオブジェクトの青写真であると言えます。「これらのオブジェクトにはfoobar属性と、さらに次のメソッドが必要です。」ただし、Pythonでは、クラスはそれ自体がオブジェクトであり、その主な強みは、クラスのメソッドを使用することもある、クラス自体のコピー(インスタンス)を作成できることです。つまり、「クラス属性として、さらに、インスタンスを作成するために使用する次のメソッドを持っている」というようなものfooです。bar

したがって、青写真ではなく、段階的なハウツーです。

于 2012-09-13T15:34:15.623 に答える
0

self.elementインスタンス__init__変数であり、を入力することにより、他のメンバー関数で取得/設定できます。クラスで宣言されているのはクラス変数であり、と入力することで取得/設定できます。self.elementelementNode.element

于 2012-09-13T15:35:25.973 に答える
0

クラス「表記法」を使用して変数にアクセスしようとすると、それは調査するだけです。

cls.__dict__

しかし、インスタンス「notation」を使用して変数にアクセスしようとすると、最初に

self.__dict__ 

目的のメンバーが見つかった場合は戻ります。見つからなかった場合は、

cls.__dict__

ここでclsはクラスです

class Test:
    temp_1=10
    temp_2=20

    def __init__(self):
        self.test_1=10
        self.test_2=20

    @classmethod
    def c_test(cls):
        pass

    def t_method(self):
        pass


print Test.__dict__
print Test().__dict__

出力

{'c_test': <classmethod object at 0x7fede8f35a60>, '__module__': '__main__', 't_method': <function t_method at 0x7fede8f336e0>, 'temp_1': 10, '__doc__': None, '__init__': <function __init__ at 0x7fede8f335f0>, 'temp_2': 20}

{'test_2': 20, 'test_1': 10}

詳細クラスの特殊属性について

于 2017-07-30T07:36:54.597 に答える
0

上記の回答のいずれにも言及されていない別の「視点」で回答を追加したかった(それらが良くないと言っているわけではない!!)->オブジェクトの「サイズ」。

はじめに:Pythonでは、良くも悪くも、実行時に特定のオブジェクトインスタンスに「新しい」(追加の)INSTANCEクラスメンバーを「作成」(追加)することができます。つまり、特定のクラスに2つのインスタンスがある場合です。メンバーの場合、オブジェクトインスタンスの作成後に3番目のメンバーを追加できます。これは、クラスのこの特定のインスタンスにのみ追加されます(つまり、クラスの「ブループリント」は変更されません)。以下のサンプルコードの#1)を参照してください。

ここで、この「新しい」INSTANCEメンバーの名前が、たまたま「グローバル」クラスメンバーと同じ名前である場合、この特定のオブジェクトインスタンスに対して、と同じ名前の追加のインスタンスメンバーが追加されます。すでに持っている(そしてこのクラスの他のすべてのインスタンスと共有する)クラスメンバー。以下のサンプルコードの#2)を参照してください。

->したがって、「設定目的」で「グローバル」(クラス)メンバーにアクセスする場合、クラス名ではなく、特定のインスタンスオブジェクトを介してアクセスします。つまり、my_class_obj2.class_data_member = some_value以下MyClass.class_data_memberのサンプルコードでは、次のようになります。この特定のインスタンスでは、追加のインスタンスメンバーが作成されます。したがって、そのサイズも変更されます(サンプルコードを実行すると、2つの異なるインスタンスのサイズが2つあることがわかります。 Pythonのサイズが「割り当て」であるため、のサイズが->my_class_obj2より大きいことを期待していましmy_class_objたが、そうではありません。Pythonのオブジェクトのサイズに関する詳細は、このQ&Aで確認できます。そこからパッケージのasizeof関数での使用例を取り上げました)。pympler

より完全な例については、以下のコードを参照してください。

import sys
from pympler import asizeof

class MyClass:

    class_data_member = 15

    def __init__(self, num):
        self.num = num
        self.string = ""

    def define_some_class_member(self):
        pass

    def print_me(self):
        self.x = 17
        print("MyClass::print_me - num is:" + str(self.num) + ", string is:" + self.string)
        print("MyClass::print_me - self.x is:" + str(self.x))

    def foo(self):
        print("Hi there form " + __class__.__name__ + "::foo")


def classes_and_object_example():
    func_name = "classes_and_object_example - "
    print(func_name + "creating MyClass object")
    my_class_obj = MyClass(12)
    my_class_obj.print_me()

    print(func_name + "creating another MyClass object")
    my_class_obj2 = MyClass(17)
    my_class_obj2.print_me()

    # 1)
    my_class_obj.some_new_instance_member = 90
    print(func_name + "the new additional instance member is:" + str(my_class_obj.some_new_instance_member))
    # Pay attention that the "new instance member" was added to my_class_obj and NOT to my_class_obj2 so the below statement is illegal
    # print("the new additional instance member is:" + str(my_class_obj2.some_new_instance_member))

    print(func_name + "the \"global\" data member seen by my_class_obj.class_data_member"
      + " is:" + str(my_class_obj.class_data_member) + " and the \"global\" data member seen by my_class_obj2.class_data_member"
      + " is (also):" + str(my_class_obj2.class_data_member))

    # 2)
    my_class_obj2.class_data_member = 99
    print(func_name + "the \"global\" data member seen by my_class_obj2.class_data_member"
      + " after intentionally modifying it is:" + str(my_class_obj2.class_data_member) + ", while on the other hand it is STILL seen by my_class_obj.class_data_member"
      + " as:" + str(MyClass.class_data_member))

    MyClass.class_data_member = 67
    print(func_name + "after setting the \"global (static)\" data member that is shared among all MyClass instances"
      + " using the assignemt:MyClass.class_data_member = 67, its value is:" + str(MyClass.class_data_member) + ", while on the other hand my_class_obj2 STILL has its \"own\" INSTANCE member with the same name and value of:" 
      + str(my_class_obj2.class_data_member))

    size_of_my_class_orig_object = asizeof.asizeof(my_class_obj)
    print(func_name + "the size of a MyClass object instance is:" + str(size_of_my_class_orig_object))

    size_of_my_class_modified_object = asizeof.asizeof(my_class_obj2)
    print(func_name + "the size of a MyClass object instance after \"adding\" to it an additional instance member is:" + str(size_of_my_class_modified_object))

# run the sample code for illustration
classes_and_object_example()
于 2020-07-28T07:47:20.377 に答える