转自:http://www.cnblogs.com/ifantastic/p/3768415.html

首先需要知道的是,dir() 是 Python 提供的一个 API 函数,dir() 函数会自动寻找一个对象的所有属性,包括搜索 __dict__ 中列出的属性。

  不是所有的对象都有 __dict__ 属性。例如,如果你在一个类中添加了 __slots__ 属性,那么这个类的实例将不会拥有 __dict__ 属性,但是 dir() 仍然可以找到并列出它的实例所有有效属性。

>>> class Foo(object):
... __slots__ = ('bar', )
... bar = 'spam'
... >>> Foo.__dict__
dict_proxy({'__module__': '__main__', 'bar': 'spam', '__slots__': ('bar',), '__doc__': None}) >>> 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'] >>> dir(Foo())
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'bar']

  同理许多内建类型都没有 __dict__ 属性,例如 list 没有 __dict__ 属性,但你仍然可以通过 dir() 列出 list 所有的属性。

>>> [].__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__,而它们对应的类也有自己的 __dict__:

>>> class Foo(object):
... bar = 'spam'
...
>>> Foo().__dict__
{}
>>> Foo.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__module__': '__main__', 'bar': 'spam', '__doc__': None})

  dir() 函数会遍历 Foo,Foo() 和 object 的 __dict__ 属性,从而为 Foo 类,它的实例以及它所有的被继承类创建一个完整有效的属性列表。

  当你对一个类设置属性时,它的实例也会受到影响:

>>> 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'

  这是因为 'ham' 属性被添加到了 Foo 类的 __dict__ 属性中:

>>> Foo.__dict__
dict_proxy({'__module__': '__main__', 'bar': 'spam', 'ham': 'eggs', '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None})
>>> f.__dict__
{}

  尽管 Foo 的实例 f 自己的 __dict__ 为空,但它还是能拥有作为类属性的 'ham'。Python 中,一个对象的属性查找顺序遵循首先查找实例对象自己,然后是类,接着是类的父类。

  所以当你直接对一个实例设置属性时,会看到实例的 __dict__ 中添加了该属性,但它所属的类的 __dict__ 却不受影响。

>>> f.stack = 'overflow'
>>> f.__dict__
{'stack': 'overflow'}
>>> Foo.__dict__
dict_proxy({'__module__': '__main__', 'bar': 'spam', 'ham': 'eggs', '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None})

  dir() 所做的不是查找一个对象的 __dict__ 属性(这个属性有时甚至都不存在),它使用的是对象的继承关系来反馈一个对象的完整的有效属性。

  一个实例的 __dict__ 属性仅仅是那个实例的局部属性集合,不包含该实例所有有效属性。所以如果你想获取一个对象所有有效属性,你应该使用 dir() 来替代 __dict__ 或者 __slots__。

关于__slots__

  合理使用 __slots__ 属性可以节省一个对象所消耗的空间。一个普通对象使用一个 dict 来保存它自己的属性,你可以动态地向其中添加或删除属性,但是如果使用 __slots__ 属性,那么该对象用来保存其自身属性的结构一旦创建则不能再进行任何修改。因此使用 slot 结构的对象节省了一部分开销。虽然有时这是一个很有用的优化方案,但是它也可能没那么有用,因为如果 Python 解释器足够动态,那么它完全可以在向对象添加属性时只请求该对象所使用的 dict。

  如何让 CPython 变得足够强大可以自动节省空间而不使用 __slots__ 属性是一项重大工程,这也许就是为什么它依然存在于 P3k 中的原因吧。

Python 官方关于 __slots__ 的介绍

  在默认情况下,Python 的新类和旧类的实例都有一个字典来存储属性值。这对于那些没什么实例属性的对象来说太浪费空间了,当需要创建大量实例的时候,这个问题变得尤为突出。

  因此这种默认做法可以通过在新式类中定义一个 __slots__ 属性从而得到解决。__slots__ 声明中包含若干实例变量,并为每个实例预留恰好足够的空间来保存每个变量,因为没有为每个实例都创建一个字典,从而节省空间。

__slots__

这个类变量可以是 string,iterable 或者是被实例使用的一连串 string。如果在新式类中定义了 __slots__,__slots__ 会为声明了的变量预留空间,同时阻止该类为它的每个实例自动创建 __dict__ 和 __weakref__。

使用 __slots__ 须知

  • 当继承一个没有 __slots__ 属性的类时,子类会自动拥有 __dict__ 属性,因此在子类中定义 __slots__ 是毫无意义的,你可以自由访问子类的 __dict__ 属性,所有未在 __slots__ 中声明的属性会保存在 __dict__ 中。
  • 在缺少 __dict__ 变量的情况下,实例不能接受新的不在 __slots__ 声明内的变量作为属性,如果试图给这样的类赋予一个未在 __slots__ 声明的变量作为属性会抛出 AttributeError。但是如果你确实需要能够动态添加属性,那么将字符串 '__dict__' 纳入 __slots__ 的声明中。如果同时在类中定义 __dict__ 和 __slots__ 是不行的,因为 __slots__ 会阻止 __dict__ 属性的创建。(本条 Python 2.3 及其以后有效)
  • 在缺少 __weakref__ 变量的情况下,定义了 __slots__ 的类不支持对其实例的弱引用。如果需要,请将字符串 '__weakref__' 纳入 __slots__ 声明中。(本条Python 2.3及其以后有效)
  • __slots__ 的实现原理是在 class 级别为其所声明的每个变量创建 descriptor,由此带来的结果就是,类属性不能用于为 __slots__ 声明中的实例变量设置默认值,否则类属性会覆写描述符的赋值功能。
  • __slots__ 声明只对它所处的类有效,因此,含有 __slots__ 的类的子类会自动创建一个 __dict__,除非在子类中也声明一个 __slots__ (在这个 __slots__ 声明应该只包含父类未声明的变量)。
  • 如果一个类中定义了一个在基类中相同的变量,那么子类实例将不能访问基类中定义的实例变量,除非直接从基类中读取描述符。在将来,可能会添加一个检查来阻止这种情况。
  • 非空的 __slots__ 对某些类无效,某些类是指源自含有长度属性的内建类型,例如 long, str 和 tuple。
  • 任何非字符串的可迭代的对象都可以赋值给 __slots__ 。具有映射特性的对象也可以赋值为 __slots__。但是,在将来,每个键的值可能会赋予特别的含义。
  • __class__ 赋值只有当两个类都具有相同的 __slots__ 时才有效。(本条 Python 2.6 及其以后有效)

python中__dict__和dir()的更多相关文章

  1. python中__dict__与dir()的区别

    在python中__dict__与dir()都可以返回一个对象的属性,区别在于: __dict__是对象的一个属性,而dir()是一个built-in的方法: __dict__返回一个对象的属性名和值 ...

  2. python之__dict__与dir(转载)

    Python下一切皆对象,每个对象都有多个属性(attribute),Python对属性有一套统一的管理方案. __dict__与dir()的区别: dir()是一个函数,返回的是list: __di ...

  3. Python 由__dict__和dir()引发的一些思考

    关于__dict__和dir()的区别和作用请参考这篇文章:http://blog.csdn.net/lis_12/article/details/53521554 说下我当时遇到的问题: class ...

  4. python 中 __dict__函数的使用

    class F: def __init__(self, name, age): self.name = name self.age = age obj = F('tom', 20)s = obj.__ ...

  5. python中dir,__dict__ , __setitem__(),__getitem__()

    class Testa: pass class Testb(object): pass if __name__ == '__main__': print 'testb = ',dir(Testb) p ...

  6. Python中import机制

    Python语言中import的使用很简单,直接使用import module_name语句导入即可.这里我主要写一下"import"的本质. Python官方定义:Python ...

  7. python 中dir()和__dict__的区别

    Python __dict__与dir() 出处(http://blog.csdn.net/lis_12/article/details/53521554). Python下一切皆对象,每个对象都有多 ...

  8. python中的__dict__和dir()的区别

    Python下一切皆对象,每个对象都有多个属性(attribute),Python对属性有一套统一的管理方案. __dict__与dir()的区别: dir()是一个函数,返回的是list: __di ...

  9. python中类与对象的命名空间(静态属性的陷阱)、__dict__ 和 dir() 在继承中使用说明

    1. 面向对象的概念 1)类是一类抽象的事物,对象是一个具体的事物:用类创建对象的过程,称为实例化. 2)类就是一个模子,只知道在这个模子里有什么属性.什么方法,但是不知道这些属性.方法具体是什么: ...

随机推荐

  1. 使用NodeJS+AngularJS+MongoDB实现一个Web数据扒取-分析-展示的系统

    说到Web爬虫,Python占了半壁江山.但是Web页面不是Python的强项了,如果需要扒取Web数据,再Mashup出来一个自己的系统,全端JS是个不错的解决方案(其实不用Python扒数据是因为 ...

  2. 1014: [JSOI2008]火星人prefix - BZOJ

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...

  3. [JavaScript] js 判断闰年

    /** * 判断闰年函数 * @param {number} year 要判断的年份 * @return {bool} 返回布尔值 * * 其实只要满足下面几个条件即可. * 1.普通年能被4整除且不 ...

  4. jQuery中的join方法

    和JS 中的JOIN 方法一样,将一数组按照JOIN的参数连接起来.比如: var arr = [ "a", "b", "c", " ...

  5. spoj 178

    输出相邻的点   比较简单吧....... #include <cstdio> #include <cstring> using namespace std; int main ...

  6. highcharts 多数据+切换

    var highchartsOptions = { chart:{ renderTo:'container' }, title:{ text:'指标数据' }, tooltip:{ pointForm ...

  7. xcode 把cocos2d-x 以源码的形式包含进自己的项目适合, 性能分析问题的错误

    性能分析:出现如下错误: xcode profile  Variable has incomplete type   class “CC_DLL” 解决办法:在 xcode的Build Setting ...

  8. cctype头文件(字符处理库)的使用

    C++ 中cctype头文件的使用 头文件cctype(字符处理库)中定义了有关字符判断与处理的库函数,使用前要包含头文件: #include <cctype> using namespa ...

  9. 基于http.sys来开发的,真的是非常稳定

    真正的WEB服务器是不会用Indy写的.因为它是基于每连接每线程的. 其实真正的服务器需要下很多功夫,无法快速开发的.比如说,字符串处理.玩服务器基本上就是玩内存.举个例子: var str:Ansi ...

  10. 1400 - "Ray, Pass me the dishes!"

    哈哈,原来题意看错了,但有多个解的时候,输出起点靠前的,如果起点一样,则输出终点靠前的,修改后AC的代码如下: #include <cstdio> #include <iostrea ...