python中dir和__dict__之间的最大区别是什么

she*_*fly 61 python introspection

class C(object):
    def f(self):
        print self.__dict__
        print dir(self)
c = C()
c.f()
Run Code Online (Sandbox Code Playgroud)

输出:

{}

['__class__', '__delattr__','f',....]
Run Code Online (Sandbox Code Playgroud)

为什么自己没有"f".__ dict__

Mar*_*ers 113

dir() 不仅仅是抬头而已 __dict__

首先,dir()是一种API方法,它知道如何使用属性__dict__来查找对象的属性.

但并非所有对象都具有__dict__属性.例如,如果要向自定义类添加__slots__属性,则该类的实例将不具有__dict__属性,但dir()仍可列出这些实例上的可用属性:

>>> class Foo(object):
...     __slots__ = ('bar',)
...     bar = 'spam'
... 
>>> Foo().__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__dict__'
>>> dir(Foo())
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'bar']
Run Code Online (Sandbox Code Playgroud)

这同样适用于许多内置类型; lists没有__dict__属性,但您仍然可以使用dir()以下命令列出所有属性:

>>> [].__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute '__dict__'
>>> dir([])
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
Run Code Online (Sandbox Code Playgroud)

dir()实例是什么

Python实例有自己的__dict__,但他们的类也是如此:

>>> class Foo(object):
...     bar = 'spam'
... 
>>> Foo().__dict__
{}
>>> Foo.__dict__.items()
[('__dict__', <attribute '__dict__' of 'Foo' objects>), ('__weakref__', <attribute '__weakref__' of 'Foo' objects>), ('__module__', '__main__'), ('bar', 'spam'), ('__doc__', None)]
Run Code Online (Sandbox Code Playgroud)

dir()方法使用两个__dict__属性,使用这两个object属性在实例,类和类的所有祖先上创建可用属性的完整列表.

在类上设置属性时,实例也会看到这些:

>>> f = Foo()
>>> f.ham
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'ham'
>>> Foo.ham = 'eggs'
>>> f.ham
'eggs'
Run Code Online (Sandbox Code Playgroud)

因为该属性已添加到类中__dict__:

>>> Foo.__dict__['ham']
'eggs'
>>> f.__dict__
{}
Run Code Online (Sandbox Code Playgroud)

请注意实例如何__dict__留空.Python对象上的属性查找遵循从实例到类型的对象层次结构到父类来搜索属性.

只有在实例上直接设置属性时,才能看到实例中反映的属性__dict__,而类__dict__保持不变:

>>> f.stack = 'overflow'
>>> f.__dict__
{'stack': 'overflow'}
>>> 'stack' in Foo.__dict__
False
Run Code Online (Sandbox Code Playgroud)

TLDR; 或摘要

dir()不只是查找对象__dict__(有时甚至不存在),它将使用对象的遗产(其类或类型,以及该类或类型的任何超类或父类)来为您提供完整的图片所有可用的属性.

实例__dict__只是该实例上的"本地"属性集,并且不包含实例上可用的每个属性.相反,您还需要查看类和类的继承树.

  • `dir` 也将查看 `__dir__` 如果实现,它可以返回字符串,用于甚至没有实现为正式属性或属性的东西,但只是在 `__getattr__` 中简单地懒惰地实现,例如。 (4认同)
  • @Davos:`property` 对象是一个描述符对象,它存在于类中,而不是实例中。属性 getter、setter 或 deleter 的作用是*完全依赖于实现*。一个属性可以做任何它想做的事情,它根本不需要对实例做任何事情。实例上的 `dir()` 仍然会列出类上的任何属性 * 和实例 `__dict__` 中的任何属性,因此 `DatasourceItem` 实例上的 `dir()` 将显示定义的 `connections` 属性类,以及实例上的 `_connections` 属性。 (2认同)

小智 5

该函数f属于类的字典C. c.__dict__产生特定于实例的属性c.

>>> class C(object):
    def f(self):
        print self.__dict__


>>> c = C()
>>> c.__dict__
{}
>>> c.a = 1
>>> c.__dict__
{'a': 1}
Run Code Online (Sandbox Code Playgroud)

C.__dict__会产生类的属性C,包括函数f.

>>> C.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'C' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'C' objects>, '__doc__': None, 'f': <function f at 0x0313C1F0>})
Run Code Online (Sandbox Code Playgroud)

虽然对象可以引用其类的属性(实际上是所有祖先类),但是这样引用的类属性不会成为关联字典本身的一部分.因此,虽然它是函数合法访问f在类中定义Cc.f(),它不会出现作为一个属性cc.__dict__.

>>> c.a = 1
>>> c.__dict__
{'a': 1}
Run Code Online (Sandbox Code Playgroud)