class C(object):
def f(self):
print self.__dict__
print dir(self)
c = C()
c.f()
输出:
{}
['__class__', '__delattr__','f',....]
为什么在self.__dict__中没有'f'
class C(object):
def f(self):
print self.__dict__
print dir(self)
c = C()
c.f()
输出:
{}
['__class__', '__delattr__','f',....]
为什么在self.__dict__中没有'f'
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']
对于许多内置类型,也是同样的情况;list
没有 __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']
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)]
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'
因为该属性被添加到类__dict__
中:
>>> Foo.__dict__['ham']
'eggs'
>>> f.__dict__
{}
注意实例__dict__
为空。在Python对象上进行属性查找时,遵循从实例到类型到父类的对象层次结构来搜索属性。
只有当您直接在实例上设置属性时,才会在实例的__dict__
中反映该属性,而类的__dict__
保持不变:
>>> f.stack = 'overflow'
>>> f.__dict__
{'stack': 'overflow'}
>>> 'stack' in Foo.__dict__
False
dir()
不仅会查找对象的__dict__
(有时甚至不存在),它还会使用对象的继承(其类或类型,以及该类或类型的所有超类或父类)来为您提供所有可用属性的完整图像。
实例__dict__
只是该实例上的'本地'属性集,并不包含实例上可用的每个属性。相反,您需要查看类和类的继承树。
函数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}
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>})
一个对象可以引用其类(以及所有祖先类)的属性,但是所引用的类属性并不成为关联dict 的一部分。因此,虽然访问在类C
中定义的函数f
的方式 是合法的,但它并不会出现在c.__dict__
中作为c
的属性。
>>> c.a = 1
>>> c.__dict__
{'a': 1}
类的 dir() 方法和 dict 类型只显示已定义的函数(方法)。实例的 dir() 方法显示数据和方法,而其 dict 属性仅显示数据属性,不包括方法。
class C2:
... def __init__(self, id):
... self.id = id
... def set(self, len):
... self.len = len
...
c2 = C2("stick")
dir(C2)
['__class__',.., '__init__', 'set']
dir(c2)
['__class__',.., '__init__', 'id', 'set']
C2.__dict__
mappingproxy({'__init__': <function C2.__init__ at 0x000001899C61E9D0>, 'set': <function C2.set at 0x000001899C61ED30>,...})
c2.__dict__
{'id': 'stick'}
__dir__
,则dir
函数也会查看它,并返回其中的字符串。这些字符串可能代表那些并不是用正式属性或者属性值实现的内容,而仅仅是在__getattr__
中实现的惰性实现。 - PaulMcGdir()
的作用,因为答案已经很长了,而且我并不需要包含那些细节来表达我的观点。 :-) - Martijn Pietersproperty
对象是一个描述符对象,它存在于类上而不是实例上。属性 getter、setter 或 deleter 的作用完全取决于实现方式。属性可以做任何它想做的事情,它不必与实例有任何关系。在实例上使用dir()
仍将列出类中的任何属性以及实例__dict__
中的任何属性,因此在DatasourceItem
实例上使用dir()
将显示在类上定义的connections
属性和实例上的_connections
属性。 - Martijn PietersDatasourceItem.id
property
对象存在于类上,而不是实例上。instance.id
将触发 getter 方法,然后返回self._id
,其中self._id
是实例上的属性。 - Martijn Pieters