2016-08-18 22 views
1

official documentationによると、「データ属性はメソッド属性を同じ名前で上書きします」。しかし、私はそれが間違っていることを発見しました。データ属性はPythonのクラスのメソッド属性をオーバーライドしますか?

class C: 
    x = 111 
    def x(self): 
     print('I am x') 
c = C() 
print(c.x) 

上記コードの印刷ステートメントは、Cxは方法ではなく、したがって、111に割り当てられたデータ属性である示し、このコードは、同じ名前の属性およびドキュメントであるデータ属性は、必ずしもメソッドをオーバーライドしないことを示し違う。誰でも私の発見を確認できますか?

P.S.私はPython 3.5とPython 2.7の両方でコードを試してみましたが、同じ結果が得られました。

+2

変数は他の変数を隠すことができます...メソッドと属性、クラスと関数はすべて実際には変数です –

答えて

3

Iは、[D] ATAはオーバーライドメソッドは、同じ名前

と属性属性言葉で表現と

によって(曖昧ため)、それは実際には「データは上書きが以前に割り当てられた属性を意味するチュートリアルが、残念ながらですね/同じ名前の定義されたメソッド属性とその逆:メソッド属性は、同じ名前の以前に割り当てられた/定義されたデータ属性を上書きします。

「Duh」の場合、「データ属性も同じ名前のデータの属性が上書きされていると思われるかもしれません。 (引用されたチュートリアルでの「上書き」と呼ばれる)変数への割り当て(何かの「属性」と呼ばれているかどうかに関わらず)は、命令型プログラミング言語のプロトタイプの特徴のすべてを尽くしたものです。

まあ、私は

名前空間をご紹介しましょう

Pythonのクラスは名前空間です。したがって、このチュートリアルでは、データ属性のメソッド属性内にある内のクラスが名前空間を共有していることがわかります。

ただし、これは異なるクラスの属性には当てはまりません。クラスが別のクラスを継承する場合、そのクラスの親の名前にアクセスできます。継承クラス内のメソッド定義またはデータ割り当てに名前が再使用された場合、親クラスは元の値を保持します。子クラスでは、それらは単に一時的に隠されています。再定義別称を持つ

class A: 
     x = 111 

class B1(A): 
     x = 123 # Shadows A.x 

assert B1.x == 123 

del B1.x   # But after removing B1's own x attribute ... 
assert B1.x == 111 # ... B1.x is just an alias to A.x ! 


# Shadowing can happen at any time: 

class B2(A): 
     pass 

assert B2.x == A.x == 111 

B2.x = 5 # shadowing attributes can also be added after the class definition 

assert B2.x == 5 
assert A.x == 111 

del B2.x 
assert B2.x == A.x == 111 

コントラストこの:あなたは子クラスから名前を削除した場合、それは、あまりにも、再び同じ名前の親の属性へのアクセスを提供します割り当て-RE(チュートリアルでは、それを呼び出すようまたは「上書き」):

class C: 
     x = 555 
     def x(self): 
       print('I am x') 

C().x() # outputs "I am x" 

del C.x 
print(C.x) # AttributeError: 'C' object has no attribute 'x' 

方法C.x()は、一時的にデータ属性C.xをシャドウしませんでした。それはそれを置き換えたので、メソッドを削除すると、xはその名前の下に再表示されるデータ属性ではなく、Cの中に完全にありません。

以上の名前空間

インスタンスは、別の名前空間を追加しますので、シャドーイングのための別の機会:実際には

a = A() 
assert a.x == 111 # instance namespace includes class namespace 

a.x = 1000 
assert a.x == 1000 
assert A.x == 111 # class attribute unchanged 

del a.x 
assert a.x == 111 # sees A.x again 

、Pythonでのすべての(ネストされた)名前空間は、そのように動作:パッケージ、モジュール、クラス、関数、メソッド、インスタンスオブジェクト、内部クラス、ネストされた関数...

変数を読み取るとき、名前空間階層は、名前が見つかるまでボトムアップされます。 (ここでは、を読むことは、変数の名前がバインドされている値(オブジェクト、関数/メソッド、またはビルトイン)を見つけることを意味し、値が変更可能な場合は、値を変更するためにも使用できます)。

オン一方、変数を設定(定義または再定義)するときは、現在の名前空間の名前が使用されます。名前が既に別の名前空間に含まれているのではなく、その名前空間にすでに存在する場合は、前に存在しなかった場合は新しく作成された名前。

+1

メソッド定義はclass-dict( 'obj .__ class __.__ dict__')に終わるのに対し、インスタンス変数はinstance-dict(' obj .__ dict__')で終わります。アトリビュートルックアップはinstance-dictで最初に行われるため、たとえそのメソッドがまだclass-dict(実際の再割り当てなし)であっても、同じ名前のメソッドをシャドウすることがあります。 –

+1

@LukasGraf良い点。私はそれについて別のセクションを追加しました。 –

+0

非常に明確で広範な答えをありがとう。 – candleindark

3

属性はメソッドをオーバーライドし、その逆も同様です。経験則は前者を上書きします。あなたは

class C: 
    x = 111 
    def x(self): 
     print('I am x') 
    x = 112 

c = C() 
print(c.x) 

をすれば、あなたはxの2番目の定義が欠落していた

112 
+0

これは公式文書がこの点で間違っていることに同意しますか? – candleindark

+1

@candleindarkドキュメントの文章は、少なくとも誤解を招くほどのものです。コスタス氏のように、後の課題は前者を上回っています。そして*通常は*、データ属性(インスタンス変数)は最初に '__init __()'に割り当てられます。なぜなら、クラス定義が解析されたときに割り当てられるメソッド定義より後で割り当てられるからです。あなたの例では、** class **レベルの属性を使用しています。そのため、「通常」は当てはまりません。 –

-1

なりますので、公式ドキュメントが間違っていたようにそれが見えた理由、それはです。

+1

xの2番目の定義はどういう意味ですか? – candleindark

関連する問題