-1

I want to add some logging to __getattr__ method in python classic class. It work well normally, but when using operator overloading, something was wrong.

My code follows:

class A:
    def __getattr__(self, item):
        print('attr:'+ item)
    def __getattribute__(self, item):
        print('attribute:' + item)
        return object.__getattribute__(self, item)
    def __add__(self, other):
        return 2

b = A()
a = b + 1
print(a)

in the line a = b + 1, it will run the __getattr__ method, and the value of item will be __coerce__. In this case, I don't know how to handle it.

Blckknght
  • 100,903
  • 11
  • 120
  • 169
Xiangyu.Wu
  • 459
  • 1
  • 5
  • 18
  • 3
    Why are you using old-style classes? Note that `__getattribute__` will not work with old-style classes anyway. – BrenBarn May 24 '14 at 04:59
  • Basic aproach is to return self.__dict__[item]. In the above example, it works. But you should be careful: if you implement a __setattr__ you may have a lot of problems;if you set a metaclass, the thing get more complicated. Post a more clear example, so the practical use of __getattr__ be obvious. In the above piece of code it just slow down acces to class data/attr. – cox May 24 '14 at 05:18

1 Answers1

3

The trouble you have is that your __getattr__ method is returning None. Since that's a valid attribute value, Python doesn't know that this is just the default return value from a function that doesn't have a return statement.

If you don't have anything to return from __getattr__, you should probably raise an AttributeError rather than returning None by default. In this specific situation, Python is checking for a __coerce__ method. If there is an AttributeError, it will be suppressed and the interpreter will fall back on other behavior (using __add__). Try something like this:

def __getattr__(self, item):
    print('attr:', item)
    raise AttributeError("%s object has no attribute named %r" %
                         (self.__class__.__name__, item))

Now, Python's automatic lookup for __coerce__ will fail, but because it fails in the expected way, the exception will be ignored and the __add__ method will be called as you expect.

One final thing: Old-style classes in Python are thoroughly obsolete (and have been removed from Python 3). You should not use them unless you need to maintain compatibility in very old software that ran on Python versions prior to 2.2 (which was released more than 12 years ago in 2001, so this compatibility issue is becoming a bit ridiculous). For new code that does not have to work with such ancient Python versions, you should use new-style classes everywhere. Because you're using an old-style class, your __getattribute__ method will never be called (only __getattr__).

Blckknght
  • 100,903
  • 11
  • 120
  • 169