2

次のコードを検討してください。

class A(object):
    def do(self):
        print self.z

class B(A):
    def __init__(self, y):
        self.z = y

b = B(3)
b.do()

なぜこれが機能するのですか?を実行するb = B(3)と、属性 z が設定されます。がb.do()呼び出されると、Python の MRO はdoクラス A で関数を見つけます。しかし、なぜサブクラスで定義された属性にアクセスできるのでしょうか?

この機能の使用例はありますか? 例が欲しいです。

4

4 に答える 4

3

これは非常に単純な方法で機能します。属性を設定するステートメントが実行されると、属性が設定されます。属性を読み取るステートメントが実行されると、属性が読み取られます。属性を読み取るコードを書くとき、Python はそのコードが実行されたときに属性存在するかどうかを推測しようとしません。コードが実際実行されるまで待機するだけで、その時点で属性が存在しない場合は、例外が発生します。

デフォルトでは、ユーザー定義クラスのインスタンスに任意の属性をいつでも設定できます。クラスは通常、設定できる「許可された」属性のリストを定義しません(ただし、それを行うこともできます)。実際に属性を設定するだけです。もちろん、存在する属性しか読み取れませんが、実際に読み取ろうとすると、属性が存在するかどうかが問題になります。したがって、属性を読み取ろうとする関数を定義するときに属性が存在するかどうかは問題ではありません。実際にその関数を呼び出すタイミング (または場合) のみが重要です。

あなたの例では、インスタンスが 1 つしかないため、2 つのクラスがあっても問題ありません。インスタンスを 1 つだけ作成し、1 つのインスタンスでメソッドを呼び出すためself、両方のメソッドの は同じオブジェクトです。最初__init__に実行され、属性が on に設定されselfます。次にdoが実行され、同じ から属性が読み取られますself。それだけです。属性がどこに設定されているかは問題ではありません。インスタンスに設定すると、スーパークラス、サブクラス、他のクラスのコード、またはどのクラスでもないコードなど、どこからでもアクセスできます。

于 2012-12-29T00:59:31.477 に答える
1

新しい属性はいつでも任意のオブジェクトに追加できるため、属性の解決はコンパイル時ではなく実行時に行われます。あなたのものから派生した、もう少し有益な次の例を検討してください。

class A(object):
  def do(self):
    print(self.z) # references an attribute which we have't "declared" in an __init__()

#make a new A
aa = A()

# this next line will error, as you would expect, because aa doesn't have a self.z
aa.do()

# but we can make it work now by simply doing
aa.z = -42
aa.do()

最初のものはあなたに怒鳴るでしょうが、2番目のものは予想通り-42を出力します。

Python オブジェクトは単なる辞書です。:)

于 2012-12-29T00:49:22.620 に答える
0

オブジェクトから属性を取得する場合 (print self. attrname )、Python は次の手順に従います。

  1. attrnameが objectname の特別な (つまり、Python が提供する) 属性である場合、それを返します。

  2. attrnameを確認objectname.__class__.__dict__します。存在し、データ記述子である場合は、記述子の結果を返します。のすべてのベースで同じケースを検索します。objectname.__class__

  3. attrnameをチェックobjectname.__dict__し、見つかった場合は返します。objectname がクラスの場合、そのベースも検索します。それがクラスであり、記述子がそのクラスまたはそのベースに存在する場合、記述子の結果を返します。

  4. attrnameを確認objectname.__class__.__dict__します。存在し、非データ記述子である場合は、記述子の結果を返します。存在し、記述子ではない場合は、それを返します。それが存在し、データ記述子である場合、ポイント 2 で戻ってきたので、ここにいるべきではありません。同じケースのすべてのベースを検索します。objectname.__class__

  5. AttributeError を上げる

    ソース

    getsetおよび Python 記述子を理解する

于 2016-05-01T23:52:36.247 に答える
-1

Bオブジェクトをインスタンス化したので、B.__init__が呼び出され、属性が追加されましたz。この属性は、オブジェクトに存在するようになりました。B他の場所で記述されたコードに何らかの形でアクセスできなくなるのは、メソッドの奇妙なオーバーロードされた魔法の共有ローカル変数ではありません。そのようなことはありません。どちらもself、スーパークラスのメソッドに渡されたときに別のオブジェクトにはなりません (そうなった場合、ポリモーフィズムはどのように機能するのでしょうか?)。

また、Aオブジェクトにそのようなオブジェクトがない ( try o = A(); a.z = whatever) という宣言もありません。また、どちらも1selfのインスタンスでdoある必要はありません。実際、宣言はまったくありません。それはすべて「先に進んで試してください」です。これは一種の動的言語の定義です (動的型付けだけではありません)。A

そのオブジェクトの属性は、アクセス元の「コンテキスト」に関係なくz、常に「どこにでも」存在します2 。解決プロセスやその他のいくつかの動作のためにコードが定義されている場所は重要ではありませ3。同じ理由で、C コードを書かなくてもリストのメソッドにアクセスできますlistobject.c;-) いいえ、メソッドは特別なものではありません。それらは単なるオブジェクトでもあり (functionたまたま type のインスタンス)、まったく同じルックアップ シーケンスに関与しています。

1これは少し嘘です。Python 2 ではA.do、最初の引数が を満たさない場合、実際にはエラーをスローする「バインドされたメソッド」オブジェクトになりますisinstance(A, <first arg>)

2delまたは同等の機能 (delattrおよびフレンド)で削除されるまで。

3さて、名前マングリングがあります。理論的には、コードはスタックを検査し、それによって呼び出し元のコード オブジェクトを検査し、それによってそのソース コードの場所を検査することができます。

于 2012-12-29T00:53:46.573 に答える