私はただ学んでいる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
の値に上書きしませんか?
1つはクラス属性で、もう1つはインスタンス属性です。それらは異なりますが、時々同じように見える方法で互いに密接に関連しています。
python属性を検索する方法に関係しています。階層があります。単純な場合は次のようになります。
instance -> Subclass -> Superclass -> object (built-in type)
このようにinstance
の属性を検索すると...
`instance.val`
...実際に起こるのは、first、Pythonインスタンス自体でval
を探します。その後、val
が見つからない場合、そのクラスを探します、Subclass
。その後、val
が見つからない場合は、Subclass
、Superclass
の親を検索します。
>>> class Foo():
foovar = 10
def __init__(self, val):
self.selfvar = val
... Foo
のすべてのインスタンスsharefoovar
が、独自の別個のselfvar
sを持っています。これがどのように機能するかの簡単で具体的な例を示します。
>>> 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]
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
というローカル変数にアクセスしようとします。
コンストラクター内のself.elementはインスタンス変数です(ノードオブジェクトが値を変更する場合、このオブジェクトに対してのみ変更されます)。2番目のバージョンの1つはクラス変数です(したがって、1つのノードオブジェクトが値を変更すると、ノードオブジェクト)。
C++の例えは、クラスの非静的メンバー変数と静的メンバー変数です。
重要な部分は、__init__
へのself
引数です。実際、anyインスタンスメソッドでは、これが最初の引数になります。これは設計により行われます。 Pythonでは、実際にインスタンスにアクセスできるのはメソッド呼び出し中のみであり、self
引数で明示的に表示されます。
class
定義の内部にいる場合、インスタンスはまだないため、実際に変更しているのはクラス自体です。したがって、クラスレベルで属性を定義すると、実際にはインスタンスではなくクラス属性になります。
C(++)と比較すると、これらの言語の「クラス」は、基本的にはそれらが表すオブジェクトの設計図であると言えます。 「これらのオブジェクトには、foo
属性とbar
属性、さらに次のメソッドが必要です。」ただし、Pythonでは、クラス自体がオブジェクトであり、クラスの主な強みは、クラスのメソッドを使用することもある自分自身のコピー(インスタンス)を作成できることです。そのため、「クラス属性としてfoo
とbar
を持ち、さらに、インスタンスを作成するために使用する次のメソッドに似ています」
したがって、設計図ではなく、段階的なハウツーです。
initのself.elementはインスタンス変数です。self.elementと入力することにより、他のメンバー関数で取得/設定できます。クラスで宣言された要素はクラス変数です。Node.elementと入力して取得/設定できます。
クラスを使用して変数にアクセスしようとすると、
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}
詳細 クラスの特別な属性