[Tutor] What protocol to follow when need to pick either one from __getattr__ and __getattribute__ ?

Peter Otten __peter__ at web.de
Tue Apr 23 13:04:42 EDT 2019


Arup Rakshit wrote:

> I read today 2 methods regarding the customizing the attribute
> access:__getattr__ and __getattribute__ from
> https://docs.python.org/3/reference/datamodel.html#special-method-names.
> What I understood about them is that __getattr__ is called when the
> requested attribute is not found, and an AttributeError is raised. But
> later is called everytime unconditionally. I wrote a simple 2 input
> calculator program, where only 2 operations are permitted Addition and
> Subtraction. Anything else will cause an not permitted error.
> 
> class OperationNotPermitted(AttributeError):
>  pass
> 
> class Calc:
>  def __init__(self, x, y):
>  self.x = x
>  self.y = y
> 
>  def __getattr__(self, name):
>  if name == "sum":
>  return self.x + self.y
>  elif name == 'minus':
>  return self.x - self.y
>  else:
>  raise OperationNotPermitted("operation {} is not
> permitted".format(name))
> 
> And here is a run down:
> 
> from customize_attr_access import *
> cal = Calc(12, 10)
> cal.sum
> 22
> cal.minus
> 2
> cal.mul
> Traceback (most recent call last):
>  Python Shell, prompt 5, line 1
>  # Used internally for debug sandbox under external interpreter
>  File "/Users/aruprakshit/python_playground/customize_attr_access.py",
> line 15, in __getattr__
>  raise OperationNotPermitted("operation {} is not
> permitted".format(name))
> customize_attr_access.OperationNotPermitted: operation mul is not
> permitted
> 
> If I replace __getattr__ with __getattribute__ I found the program works
> exactly same.

No, it doesn't, as __getattribute__ is called for x, and y, too.

     def __getattribute__(self, name):
         if name == "sum":
             return self.x + self.y
         elif name == 'minus':
             return self.x - self.y
         else:
             raise OperationNotPermitted("operation {} is not permitted".format(name))

Accessing cal.sum will therefore trigger a __getattribute__("x") call which in turn will raise an OperationNotPermitted("operation x ...") 
exception.


> Now my questions is in real world when  you have to pick
> between these 2 pair of special method which protocols a Python dev
> checks to pick either of the one? Is there any such thing, or either one
> is fine. Can anyone elaborate this to educate me please?

__getattribute__() is rarely needed, __getattr__() is useful when the
list of calculated attributes is open-ended and uniform (think proxy).
When there is a finite number of calculated attributes the best way to
implement them is usually a property:

class Calc:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    @property
    def sum(self):
        return self.x + self.y

    @property
    def difference(self):
        return self.x - self.y


> 
> doc said:
> 
>  > This method should either return the (computed) attribute value or
> raise an AttributeError exception.
> 
> Another question:
> 
> My question is that: Can I raise a domain error like
> OperationNotPermitted when raising instead of AttributeError ?

You just did ;) I don't think it's a good idea, though.



More information about the Tutor mailing list