【问题标题】:__getattr__ and __getattribute__ for class/static atributes of dynamically generated classes__getattr__ 和 __getattribute__ 用于动态生成的类的类/静态属性
【发布时间】:2019-09-02 15:20:34
【问题描述】:

This question 回答如何为静态/类属性实现__getattr__ - 使用元类。但是,我想为type() 生成的类实现__getattr____getattribute__,让事情变得更有趣,该类继承了一个具有必须正确执行的自定义元类的类。

总结以上段落的代码:

class Inherited(metaclass=SomeFancyMetaclass):
    ...

generated_class = type("GeneratedClass", (Inherited,), {})

def __class_getattr__(cls, name):  # __getattr__ for class, not sure how the code shall look exactly like
    return getattr(cls, name)

setattr(generated_class, "__getattr__", __class_getattr__)  # similarly for __getattribute__

问题:这可能吗?如果可以,怎么做?有人可以提供一个最小的工作示例吗?

【问题讨论】:

  • 你需要在元类上实现__getattr____setattr__,但是你必须使用元类来生成类,我相信
  • 你可以通过type("GeneratedClass", (Inherited,), {'__getattr__': your_getattr_impl})在一行中创建生成的类,并且your_getattr_impl应该有一个签名(self, name)self而不是cls,因为类的实例将在使用时传递),除非您想在元类级别执行此操作。此外,您真的不需要元类来为 dunder 函数动态创建具有自定义属性的类。你到底想达到什么目的?
  • @metatoaster 他们正在尝试在元类上实现那些 sunder 方法,以便它可以与类属性一起使用
  • @juanpa.arrivillaga 我可以看到,但除非有充分的理由这样做,否则重写元类和使用动态类构造几乎总是矫枉过正。我的意思是建议 OP 采用一种技术,除非有充分的理由同时使用这两种技术。
  • 您应该能够像使用type(...,...,...) 一样使用MyCustomMeta(...,...,...),但他们只需要实际实现MyCustomMeta 我的意思是,所有这些都可能是矫枉过正。为什么现在停止...

标签: python class metaclass getattr


【解决方案1】:

只需让您的元类从 SomeFancyMetaclass 继承,在那里正确实现 __getattr__(和 __getattribute__),并使用此元类,而不是调用 type 来生成您继承的动态类。

虽然你使用了很多不常用的东西,但没有特殊的机制——它应该是普通的 Python——

当然,你没有告诉你想在元类特殊方法中做什么 - 那里可能会执行一些黑魔法 - 如果你正在做__getattribute__,你总是必须格外小心,并将所有你不关心的属性重定向到超级调用,否则,什么都不起作用。

另外,请记住,使用这两种方法进行的属性访问自定义将无法“创建神奇的 dunder 方法” - 也就是说:您的类不会神奇地拥有 __add____dir__ 方法,因为您的元类 __getattribute__ 会生成一个 - 相反,这些是由 Python 运行时固定在特殊插槽中的,它们的检查和调用绕过了 Python 中的正常属性查找。

否则:

class Inherited(metaclass=SomeFancyMetaclass):
    ...

class MagicAttrsMeta(Inherited.__class__):
    def __getattr__(self, attr):
          if attr in ("flying", "circus", "brian", "king_arthur"):
               return "coconut"
          raise AttributeError()


generated_class = MagicAttrsMeta("GeneratedClass", (Inherited,), {})

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多