Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I have a library that accepts a file-like object but assumes that it has a valid .name unless that name is None. This causes it to break when I pass e.g. someproc.stdout as it has a name of <fdopen>. Unfortunately the attribute cannot be deleted or overwritten.

So I've written this simple wrapper to return None in case the name attribute is requested.

class InterceptAttrWrapper(object):
    def __init__(self, obj, attr, value):
        self.obj = obj
        self.attr = attr
        self.value = value

    def __getattribute__(self, name):
        ga = lambda attr: object.__getattribute__(self, attr)
        if name == ga('attr'):
            return ga('value')
        return getattr(ga('obj'), name)

This seems to work fine, I'm using it like this:

proc = subprocess.Popen(..., stdout=subprocess.PIPE)
some_func(InterceptAttrWrapper(proc.stdout, 'name', None))

However, I wonder if:

  • My InterceptAttrWrapper object is missing something that could cause problems.
  • There is a better way to access attributes within __getattribute__. That lambda I'm using right now looks pretty ugly.
share|improve this question

1 Answer

Something to watch out for with your approach is that Python calls certain special methods without looking them up via __getattribute__. For example, the __iter__ method:

>>> w = InterceptAttrWrapper(open('test'), 'attr', 'value')
>>> for line in w: print line
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'InterceptAttrWrapper' object is not iterable

See the documentation on "Special method lookup for new-style classes". If this affects you, then you'll need to add to your wrapper class all the special methods that you need to support (in my example, __iter__, but when wrapping other objects one might need to implement __getitem__, __repr__, __hash__, or others).

Here's a slightly more readable way to get at the wrapper object's own data, together with support for intercepting multiple attributes:

class InterceptAttrWrapper(object):
    """
    Wrap an object and override some of its attributes.

    >>> import sys
    >>> stdin = InterceptAttrWrapper(sys.stdin, name = 'input')
    >>> stdin.mode # Pass through to original object.
    'r'
    >>> stdin.name # Intercept attribute and substitute value.
    'input'
    """
    def __init__(self, obj, **attrs):
        self._data = obj, attrs

    def __getattribute__(self, name):
        obj, attrs = object.__getattribute__(self, '_data')
        try:
            return attrs[name]
        except KeyError:
            return getattr(obj, name)
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.