2

Is there a way to check if an object has an attribute, that doesn't rely on __getattr__ or object implementation specifics?

Consider the code below. I want Proxy to delegate to Wrapped what it can't handle. The code works, but I'd like to avoid the test attr in self.__dict__ (I'd prefer a stable interface to do this, without using implementation quirks). The function hasattr doesn't help here, because it gets routed to the wrapped object via __getattr__.

class Wrapped:
    def __init__(self):
        self.a = 0
        self.b = 1

class Proxy:
    def __init__(self, wrapped):
        object.__setattr__(self, 'wrapped', wrapped)
        object.__setattr__(self, 'a', 2)
    def __getattr__(self, attr):
        return getattr(self.wrapped, attr)
    def __setattr__(self, attr, value):
        if attr in self.__dict__:  # <-- Don't like this, hasattr doesn't work
            object.__setattr__(self, attr, value)
        elif hasattr(self.wrapped, attr):
            setattr(self.wrapped, attr, value)
        else: object.__setattr__(self, attr, value)

Testdrive:

>>> w = Wrapped()
>>> p = Proxy(w)
>>> p.a
2
>>> p.b
1
>>> p.a = 3
>>> p.a
3
>>> w.a
0
>>> p.b = 4
>>> p.b
4
>>> w.b
4
>>> p.c = 5
>>> p.c
5
>>> w.c
AttributeError: 'Wrapped' object has no attribute 'c'

1 Answers1

2

The built-in hasattr() function

is implemented by calling getattr(object, name) and seeing whether it raises an AttributeError or not.

The inspect module has the getattr_static() method, which can be used to

Retrieve attributes without triggering dynamic lookup via the descriptor protocol, __getattr__() or __getattribute__()".

Using this method, you could define a hasattr_static() method similarly to hasattr(), but calling inspect.getattr_static(object, name) instead of getattr(object, name):

import inspect


def hasattr_static(object, name):
    try:
        inspect.getattr_static(object, name)
        return True
    except AttributeError:
        return False

And then use this in the __setattr__() method of your Proxy class as a check:

def __setattr__(self, attr, value):
    if hasattr_static(self, attr):
        object.__setattr__(self, attr, value)
    elif hasattr(self.wrapped, attr):
        setattr(self.wrapped, attr, value)
    else:
        object.__setattr__(self, attr, value)

Alternatively, you coud use the dir() function instead of __dict__ to retrieve a list of attributes of your object, or use inspect.getmembers().

Jonathan Feenstra
  • 2,534
  • 1
  • 15
  • 22