如何在不破坏默认行为的情况下覆盖 __getattr__ ?

发布于 2024-08-24 07:42:41 字数 150 浏览 11 评论 0原文

如何覆盖 __getattr__类的方法而不破坏默认行为?

How do I override the __getattr__ method of a class without breaking the default behavior?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

微凉 2024-08-31 07:42:41

重写__getattr__应该没问题——__getattr__仅作为最后的手段被调用,即如果实例中没有与名称匹配的属性。例如,如果您访问 foo.bar,则仅当 foo 没有名为 bar 的属性时才会调用 __getattr__ >。如果您不想处理该属性,请引发 AttributeError

class Foo(object):
    def __getattr__(self, name):
        if some_predicate(name):
            # ...
        else:
            # Default behaviour
            raise AttributeError

但是,与 __getattr__ 不同,__getattribute__ 将首先被调用(仅适用)对于新样式类,即从对象继承的类)。在这种情况下,您可以保留默认行为,如下所示:

class Foo(object):
    def __getattribute__(self, name):
        if some_predicate(name):
            # ...
        else:
            # Default behaviour
            return object.__getattribute__(self, name)

请参阅Python 文档了解更多信息

Overriding __getattr__ should be fine -- __getattr__ is only called as a last resort i.e. if there are no attributes in the instance that match the name. For instance, if you access foo.bar, then __getattr__ will only be called if foo has no attribute called bar. If the attribute is one you don't want to handle, raise AttributeError:

class Foo(object):
    def __getattr__(self, name):
        if some_predicate(name):
            # ...
        else:
            # Default behaviour
            raise AttributeError

However, unlike __getattr__, __getattribute__ will be called first (only works for new style classes i.e. those that inherit from object). In this case, you can preserve default behaviour like so:

class Foo(object):
    def __getattribute__(self, name):
        if some_predicate(name):
            # ...
        else:
            # Default behaviour
            return object.__getattribute__(self, name)

See the Python docs for more.

梨涡 2024-08-31 07:42:41
class A(object):
    def __init__(self):
        self.a = 42

    def __getattr__(self, attr):
        if attr in ["b", "c"]:
            return 42
        raise AttributeError("%r object has no attribute %r" %
                             (self.__class__.__name__, attr))

>>> a = A()
>>> a.a
42
>>> a.b
42
>>> a.missing
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 8, in __getattr__
AttributeError: 'A' object has no attribute 'missing'
>>> hasattr(a, "b")
True
>>> hasattr(a, "missing")
False
class A(object):
    def __init__(self):
        self.a = 42

    def __getattr__(self, attr):
        if attr in ["b", "c"]:
            return 42
        raise AttributeError("%r object has no attribute %r" %
                             (self.__class__.__name__, attr))

>>> a = A()
>>> a.a
42
>>> a.b
42
>>> a.missing
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 8, in __getattr__
AttributeError: 'A' object has no attribute 'missing'
>>> hasattr(a, "b")
True
>>> hasattr(a, "missing")
False
归途 2024-08-31 07:42:41

为了扩展迈克尔的答案,如果您想使用 __getattr__ 维护默认行为,您可以这样做:

class Foo(object):
    def __getattr__(self, name):
        if name == 'something':
            return 42

        # Default behaviour
        return self.__getattribute__(name)

现在异常消息更具描述性:

>>> foo.something
42
>>> foo.error
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __getattr__
AttributeError: 'Foo' object has no attribute 'error'

To extend Michael answer, if you want to maintain the default behavior using __getattr__, you can do it like so:

class Foo(object):
    def __getattr__(self, name):
        if name == 'something':
            return 42

        # Default behaviour
        return self.__getattribute__(name)

Now the exception message is more descriptive:

>>> foo.something
42
>>> foo.error
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __getattr__
AttributeError: 'Foo' object has no attribute 'error'
双马尾 2024-08-31 07:42:41

人们在这次讨论中忽略了一件重要的事情——如果你的类不是抽象的并且你收到名称为“__isabstractmethod__”的 getattr,Python 需要在 __getattr__ 中引发 AttributeError。

There is one important thing people are missing in this discussion - Python requires to raise AttributeError in __getattr__ if your class isn't abstract and you receive getattr of name: '__isabstractmethod__'.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文