web-dev-qa-db-ja.com

Pythonクラスメンバー

私はただ学んでいる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__は、定義されているクラスのelement変数と同じではありませんか? elementからNone__init__に渡されたelementの値に上書きしませんか?

43
darksky

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

python属性を検索する方法に関係しています。階層があります。単純な場合は次のようになります。

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

このようにinstanceの属性を検索すると...

`instance.val`

...実際に起こるのは、first、Pythonインスタンス自体でvalを探します。その後、valが見つからない場合、そのクラスを探します、Subclass。その後、valが見つからない場合は、SubclassSuperclassの親を検索します。

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

... Fooのすべてのインスタンスsharefoovarが、独自の別個のselfvarsを持っています。これがどのように機能するかの簡単で具体的な例を示します。

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

foovarに触れない場合は、fFooの両方で同じです。しかし、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.foovarFoo.foovarと同じオブジェクトを参照しているため、オブジェクトを変更すると、変更は階層全体に反映されます。

>>> Foo.foovar = [1]
>>> f = Foo(5)
>>> f.foovar[0] = 99
>>> Foo.foovar
[99]
70
senderle

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というローカル変数にアクセスしようとします。

13
Lee Netherton

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

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

2
Borgleader

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

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

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

したがって、設計図ではなく、段階的なハウツーです。

0
voithos

initのself.elementはインスタンス変数です。self.elementと入力することにより、他のメンバー関数で取得/設定できます。クラスで宣言された要素はクラス変数です。Node.elementと入力して取得/設定できます。

0
waitingkuo

クラスを使用して変数にアクセスしようとすると、

cls.__dict__

しかし、インスタンスで変数にアクセスしようとすると、最初に見えます

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}

詳細 クラスの特別な属性

0
Kallz