以下是使用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']
>>>
答案 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兼容性更新中删除属性。