14
class MyClass(object):
    pass

print MyClass.__mro__
print dir(MyClass)

出力:

(<class '__main__.MyClass'>, <type 'object'>)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']

__mro__が記載されていないのはなぜdir()ですか?

4

2 に答える 2

21

私も最近同じことを疑問に思っていました。mro私は、「Pythonの実装の原因は何ですか/__mro__にリストされていませんdirか?そして、リストするために何を信頼できますdirか?」に沿った回答を探していました。mro単純に「Python のドキュメントはinを含めないことをどのように正当化しdirますか?」よりも プログラミング言語の動作に対する私の期待が実際の動作と一致しない場合、それは言語の理解が正しくないことを意味するため、好きではありません-それが単なるバグでない限りurllib2.escape. それで、答えがわかるまで、少し掘り下げました。

上記のコメントのドキュメントから引用された adolfopa 行は、dir の動作を説明するのに適しています。

「オブジェクトがタイプまたはクラス オブジェクトの場合、リストにはその属性の名前と、そのベースの属性が再帰的に含まれます。」

これは何を意味するのでしょうか?クラスとその各スーパークラスdirから属性を再帰的に収集します。__dict____dict__

set(dir(object)) == set(dict(object.__dict__).keys() #True



class A(object):
    ...

class B(object):
    ...

class C(B):
    ...

class D(C,A):
    ...

set(dir(D)) == set(D.__dict__.keys()) + set(C.__dict__.keys()) \
   + set(B.__dict__.keys()) + set(A.__dict__.keys()) \
   + set(object.__dict__.keys()) #True

dir(object)リストされていない理由は__mro__mroオブジェクトの属性ではないためです。それらは の属性ですtype。それ自身を定義しないすべてのクラス__metaclass__は のインスタンスですtype。ほとんどのメタクラス サブクラスtype. このようなメタクラスのインスタンスも同様に型のインスタンスです。MyClass.__mro__と同じtype.__getattribute__(MyClass,'__mro__')です。

Python がクラスを実装する方法は、必然的に dir の動作に関してわずかな異常を生み出します。

通常、dir(MyClass) == dir(MyClass(*requiredparameters)) #True.

ただし、dir(type) == dir(type(*requiredparameters)) #Falseこれがそうでない可能性がある唯一の方法は、type.__dict__dirが同じである場合でした。これは、自明のことですが、 の目的ではありませんdir

ちょっと待って!は再帰的な合計によって作成されますが、その最後の部分を変更して、それがただではなく になるdirようにできないのはなぜですか。そうすれば、/と、クラス オブジェクトが持つ他のすべての属性を持ちますか? ああ、でもそれらはクラスではなく、クラス オブジェクトの属性になります。さて、違いは何ですか?dir(object)object.__dict__.keys()object.__dict__.keys() + type.__dict__.keys()mro__mro__

検討

list.__mro__ #(<type 'list'>, <type 'object'>)

一方

[].__mro__
# Traceback (most recent call last):
#  File "<stdin>", line 1, in <module>
# AttributeError: 'list' object has no attribute '__mro__'

dirこれで、何をリストに載せることが期待でき、何をリストに載せないことが期待できるかを答えるのに適した場所にdirいます. 簡単な答えは、すでに説明したものです。__dict__クラスのすべてのキーとそのスーパークラスのそれぞれのすべてのキーを__dict__再帰的にリストします。インスタンスの場合、インスタンスの .xml にあるすべてのパラメータも含まれます__dict__。負のスペースを埋めるために、 で定義されている__getattr__もの__getattribute__も、__dict__. また、タイプ/メタタイプの属性もリストしません。


私が指摘しなければならないと思うもう1つのこと:私がこれを書いている時点で受け入れられている回答であるダンの回答には、不正確または少なくとも誤解を招く情報が含まれています。

組み込みオブジェクトの属性は設定できないため、ある意味でtype.__mro__は「読み取り専用」ですが、それと同じ方法でのみlist.appendですtype.mro

MyClass.__mro__ = "Hello world!"エラーにはなりません。で定義されているメソッド解決順序には影響しませんtype。そのため、その動作を変更しようとしても、期待した効果が得られない場合があります。(Python でクラスの属性を定義する方法はこのように機能するため、これが行うことは、予想さMyClass(*requiredparameters).__mro__れる"Hello World!"はずだったものになります。)__mro__メタクラスを作成するために型をサブクラス化するときにオーバーライドすることもできます。オーバーライドしない場合は、オーバーライドしない他のものと同様に継承されます。(型のサブクラスではなく、型のインスタンスを返す関数ではないメタクラスを作成している場合は、おそらく、自分が何をしているのかを十分に理解しているので、これについて心配する必要はありません。しかし__mro__サブクラス化していないため、継承されませんtype

ドキュメント(スーパーの動作を説明)によると:

型の __mro__ 属性には、getattr() と super() の両方で使用されるメソッド解決の検索順序がリストされています。この属性は動的であり、継承階層が更新されるたびに変更される可能性があります。

したがって、直接変更する__mro__と、変更とほぼ同じように、期待どおりに動作するはずmroです。ただし、通常は、関数をオーバーライドすることで目的の動作を取得する方が簡単です。(サブクラス化を適切に処理するために何をする必要があるかを考えてください。)

于 2013-08-03T18:27:49.297 に答える
8

Python ドキュメントから:

dir() は、主に対話型プロンプトで使用するための利便性として提供されているため、厳密にまたは一貫して定義された名前のセットを提供しようとするよりも、興味深い名前のセットを提供しようとします。また、その詳細な動作はリリース間で変わる可能性があります。たとえば、引数がクラスの場合、メタクラス属性は結果リストに含まれません。

__mro__クラスが複数の基本クラスから継承されている場合に、メソッドの解決を決定するために使用される読み取り専用の属性です。この動作をカスタマイズする場合は、mro()メソッドをオーバーライドするメタクラス (クラス インスタンスの作成を目的とする特別な種類のオブジェクト) を使用する必要があります。__mro__いずれにしても変わらない。

于 2013-05-21T06:38:25.937 に答える