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

 海之蓝水之清清2011 发布于 2022-12-04 14:36

以下是使用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 plus继承的名称wrapped_obj,并且我发现大多数情况下都是这种情况,但并非所有情况都是如此.我尝试使用自定义旧样式类,自定义新样式类和一些内置类,它总是以这种方式工作:我发现的唯一例外是当包装对象是类的实例时_mysql.connection.在这种情况下,dir()我的对象碰巧也知道附加到包装的连接对象的所有方法名称.

我在python文档中读到了dir,这种行为似乎是合法的:dir应该返回一个"有趣的名字"列表,而不是实例的"真实"内容.但我真的无法弄清楚它是如何做到的:它实际上理解我的实现__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']
>>> 

Martijn Piet.. 12

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

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

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

这些已从Python 3中删除,但因为您的连接对象(至少在您使用的旧版本中)仍提供通过您的钩子__methods__找到并在此处使用的属性.__getattr__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()因此您不会在此处看到要访问的对象.

该项目历史文件显示属性的大的Python 3兼容性更新被拆除的1.2.4 Beta 1中.

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

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

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

    这些已从Python 3中删除,但因为您的连接对象(至少在您使用的旧版本中)仍提供通过您的钩子__methods__找到并在此处使用的属性.__getattr__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()因此您不会在此处看到要访问的对象.

    该项目历史文件显示属性的大的Python 3兼容性更新被拆除的1.2.4 Beta 1中.

    2022-12-11 02:57 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有