【问题标题】:__getattr__ for class atributes?__getattr__ 用于类属性?
【发布时间】:2021-09-27 02:50:55
【问题描述】:

对于一个类Foo

class Foo:
    ...

有没有办法在Foo.XXX(任意类属性XXX,例如barbar2等)被解析时调用特定方法,但在Foo().XXX(一个任意实例属性)是否已解决?据我所知,覆盖

def __getattr__(self, a):
    ...

仅适用于第二种情况。我想受益于 __getattr__ for instances 仅在未找到相应属性时才被调用。有谁知道这应该如何解决?我已经阅读了the manual 并没有发现任何相关性。

我并不特别关心如果有人试图为Foo 的任何类或实例属性赋值会发生什么。

用例(避免XY):

Foo 类是信使。 Foo 的实例基本上是带有额外步骤的元组。但是,Foo 有一些特殊情况,我想将其存储为Foo 的类属性(我使用特殊的装饰器进行了管理)。然而,Foo 的特殊情况的数量正在逐渐增加,而它们的差异非常微不足道。每当有人想要Foo.SPECIAL_CASE_123 时调用这个特殊函数对我来说在代码方面非常有效,因为从"SPECIAL_CASE_123" 到实际特殊情况的映射非常快并且非常类似于将"SPECIAL_CASE_456" 映射到其他相应的特殊情况案例。

【问题讨论】:

  • 需要更清楚一点:所以给定foo = Foo(),尝试分配给实例时会发生什么,即foo.XXX = some_value?在任何情况下,您似乎都试图拦截或修改object attribute lookup 以阻止特定步骤(即在实例级别)。解释您的确切用例也非常有用,因为很少需要这样做(以避免an XY problem)。
  • @metatoaster 感谢您关心我的问题,我会更新正文。
  • 如果您可以通过填写主体(以显示某些属性)和示例代码来完成示例 class Foo: 以通过类和实例访问它以及预期的行为会更好代码。
  • 与其实现神奇的属性查找行为,不如考虑编写一个静态方法或类方法来管理这些“特殊情况”实例。
  • @CaptainTrojan:是的,但是你可以用一个类方法来完成所有这些。您不需要为每个特殊实例编写单独的方法。

标签: python attributes metaclass magic-methods getattr


【解决方案1】:

使用元类来定义类的行为方式。具体来说,重新定义类的__getattr__ 以更改类中缺少的属性的处理方式:

# The "Type of Foo"
class MetaFoo(type):
    def __getattr__(cls, item):
        return f"Dynamically handled: {item}"


class Foo(metaclass=MetaFoo):
    REGULAR_CASE_22 = "Catch 22"

print(Foo.REGULAR_CASE_22)     # Catch 22
print(Foo.SPECIAL_CASE_123)    # Dynamically handled: SPECIAL_CASE_123
print(Foo().REGULAR_CASE_22)   # Catch 22
print(Foo().SPECIAL_CASE_123)  # AttributeError: 'Foo' object has no attribute 'SPECIAL_CASE_123'

请注意,某些属性查找(例如 __add__ 等特殊方法)将绕过元类属性查找。

【讨论】:

  • 您似乎混淆了一些输出。
  • @user2357112supportsMonica 感谢您的提醒。现在应该修好了。
  • > “元类比 99% 的用户所担心的更深奥。如果你想知道你是否需要它们,你就不需要(真正需要它们的人肯定知道他们需要它们,并且不需要解释为什么)。” ——蒂姆·彼得斯。我想你要找的是class descriptors@u
  • @lonetwin:描述符只管理一个属性。
  • @lonetwin 不要高估我对此事的理解,但目前,我觉得我知道我为什么需要它们。
【解决方案2】:

你可以试试@classmethods:

class Foo:        
    @classmethod
    def XXX(self, a):
        return a
print(Foo.XXX('Hello World'))

输出:

Hello World

【讨论】:

  • 如果我没有在我的问题正文中正确指定这一点,那我很糟糕,但我的意思是 XXX 是一般的 anything,而不是专门的 XXX。我会尽快更新。
猜你喜欢
  • 2019-09-02
  • 2019-05-05
  • 2014-09-26
  • 2021-07-12
  • 2020-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多