dir()用__getattr__执行什么样的python魔术?

时间:2014-12-19 13:38:21

标签: python python-2.7

以下是使用MySQLdb 1.2.3的python 2.7。

我需要一个类包装器来向不支持它的对象添加一些属性(带有__slots__的类和/或用C语言编写的一些类)所以我得到了类似这样的东西:

class Wrapper(object):

    def __init__(self, obj):
        self._wrapped_obj = obj

    def __getattr__(self, obj):
        return getattr(self._wrapped_obj, attr)

我原本期望在我的dir()实例上调用的Wrapper内置函数应该只返回object加上wrapped_obj继承的名称,并且我发现这实际上是大多数案例,但不适用于所有案例。我尝试使用自定义旧样式类,自定义新样式类和一些内置类,它总是以这种方式工作:我发现的唯一例外是当包装对象是类_mysql.connection的实例时。在这种情况下,我的对象上的dir()碰巧也知道附加到包装连接对象的所有方法名称。

我在python文档中读到了dir,这种行为似乎是合法的:dir应该返回一个"有趣的名字"的列表,而不是&# 34;实"实例的内容。但是我真的无法理解它是如何做到的:它实际上理解我的__getattr__的实现并解析为附加项目?如果这是真的,为什么只有那个connection类而不是更简单的dict呢?

这是一些粘贴的代码,作为这种奇怪行为的一个例子:

>>> from _mysql import connection
>>> c = connection(**connection_parameters)
>>> c
<_mysql.connection open to '127.0.0.1' at a16920>
>>> 
>>> dir(c)
['affected_rows', 'autocommit', 'change_user', 'character_set_name', 'close', 'commit', 'dump_debug_info', 'errno', 'error', 'escape', 'escape_string', 'field_count', 'get_character_set_info', 'get_host_info', 'get_proto_info', 'get_server_info', 'info', 'insert_id', 'kill', 'next_result', 'ping', 'query', 'rollback', 'select_db', 'set_character_set', 'set_server_option', 'shutdown', 'sqlstate', 'stat', 'store_result', 'string_literal', 'thread_id', 'use_result', 'warning_count']
>>> 
>>> w = Wrapper(c)
>>> dir(w)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattr__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_wrapped_obj', 'affected_rows', 'autocommit', 'change_user', 'character_set_name', 'close', 'commit', 'dump_debug_info', 'errno', 'error', 'escape', 'escape_string', 'field_count', 'get_character_set_info', 'get_host_info', 'get_proto_info', 'get_server_info', 'info', 'insert_id', 'kill', 'next_result', 'ping', 'query', 'rollback', 'select_db', 'set_character_set', 'set_server_option', 'shutdown', 'sqlstate', 'stat', 'store_result', 'string_literal', 'thread_id', 'use_result', 'warning_count']
>>> 
>>> d = Wrapper({})
>>> dir(d)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattr__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_wrapped_obj']
>>> 

1 个答案:

答案 0 :(得分:12)

Python 2中有两个不推荐使用的属性,object.__members__ and object.__methods__;这些旨在支持dir()扩展类型(C定义的对象):

  

object.__methods__
  自2.2版开始不推荐使用:使用内置函数dir()获取对象属性的列表。此属性不再可用。

     

object.__members__
  自2.2版以来不推荐使用:使用内置函数dir()获取对象属性的列表。此属性不再可用。

这些已从Python 3中删除,但是因为您的连接对象(至少在您使用的旧版本中)仍提供通过__methods__挂钩<找到的__getattr__属性/ em>并由dir()在这里使用。

如果您向print方法添加__getattr__语句,则会看到要访问的属性:

>>> class Wrapper(object):
...     def __init__(self, obj):
...         self._wrapped_obj = obj
...     def __getattr__(self, obj):
...         print 'getattr', obj
...         return getattr(self._wrapped_obj, attr)
... 
>>> dir(Wrapper({}))
getattr __members__
getattr __methods__
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattr__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_wrapped_obj']

对于新式对象,dir()支持的较新__dir__ method只能在该类型上正确查找,因此您无法在此处查看此内容。

project HISTORY file建议在1.2.4 beta 1的大型Python 3兼容性更新中删除属性。