【问题标题】:How to access __getattr__ while using __slots__如何在使用 __slots__ 时访问 __getattr__
【发布时间】:2017-04-20 02:02:31
【问题描述】:

在申请__slots__之前,我可以这样做:

class C(object):

    def __init__(self):
        self.m_A = 1

    def __getattr__(self, name):
        if name in ("A"):
            return self.__dict__["m_%s" % name]
        raise AttributeError(name)

a = C()
a.A

现在,我想使用__slots__;但是,这会禁用 __dict__ 导致我的代码中断。

所以,我的问题是:

  1. 还有其他办法吗?(property除外)

  2. 使用__slots__时,Python如何访问对象属性?

【问题讨论】:

  • 还可以考虑修改标题以总结 question - 目前它似乎是 __slots__statement 以及扩展 this question不值得任何人花时间。
  • 我看过,但不是我想要的。

标签: python


【解决方案1】:

只是改变:

return self.__dict__["m_%s" % name]

到:

return getattr(self, "m_%s" % name)

前者使用不适用的实现细节,后者通过名称显式查找新属性。

注意:对于这种特定情况,我会完全避免 __getattr__ 因为涉及太多开销,而只是这样做:

@property
def A(self):
    return self.m_A

这将表现相同,并且运行速度更快(通过__getattr__getattr 调用的通用调度比通过属性描述符的目标查找更昂贵)。如果你有十几个这样的插槽来创建只读访问器,你仍然可以通过在创建类之后添加访问器来相当便宜地使用这种模式:

from operator import attrgetter

class Foo(object):
     __slots__ = 'm_XXX', 'm_YYY', etc.

     ... rest of class body ...

# Add readonly accessors sans m_ prefix for each slot with an m_ prefix:
for membername in Foo.__slots__:
    if membername.startswith('m_'):
        setattr(Foo, membername.replace('m_', '', 1), property(attrgetter(membername)))

【讨论】:

  • 我有很多m_A这样的属性,所以property不能满足我的需求。
  • @JohnHe:如果你使用__slots__,你的属性列表是有限的,如果它们都是简单的只读访问器,一堆两行访问器函数(一个用于装饰器,一个用于函数和返回)不是不合理的,它会更快。您实际上也可以概括这种特定模式;我会将其编辑到我的答案中。
  • @JohnHe:添加了概括创建propertys 的示例,将__getattr__ 的运行时开销替换为微不足道的定义时间开销。
  • 是否有一些像__dict__ 这样的内置变量?
  • @JohnHe:不确定您所说的“内置变量......对此”是什么意思。类本身(在类定义退出后)将具有实现类__dict__ 上的槽的描述符,但值本身存储在对象内部,有点像tuple 存储其内容,但没有向程序员公开索引。 dir() 将为您提供所有插槽的字符串名称(以及大量其他特殊的内部事物),但没有直接等效于 __dict__ 的为您提供完整的映射。
【解决方案2】:

从这里快速阅读插槽如何工作的描述:Usage of __slots__?

您可以通过将它们添加到 __slots__ 变量来定义可以设置/获取的属性名称。如果您想动态定义它们,似乎将 __dict__ 添加到插槽中的项目列表中是可行的方法。

【讨论】:

    猜你喜欢
    • 2021-01-04
    • 1970-01-01
    • 2012-06-01
    • 2021-04-08
    • 2011-05-24
    • 2014-05-28
    • 2017-05-24
    • 2010-10-03
    相关资源
    最近更新 更多