Python magic gets


__getattribute__ and __getattr__ and __get__ and __getitem__

Lets get into these many gets.


if the lookup attribute does not available in instance’s __dict__, then it will call __getattr__, still if it does not get, raises an AttributeError

The below example will make you clear(in python 2.x)

In [5]: class Test(object):
   ...:     def __init__(self):
   ...:         self.a = 1
   ...:         self.b = 2
   ...:     def __getattr__(self, att):
   ...:         print self.__dict__
   ...:         print "Calling getattr"
   ...:         return 0

In [6]: t = Test()

In [7]: t.__dict__
Out[7]: {'a': 1, 'b': 2}

In [8]: t.a
Out[8]: 1

In [9]: t.c
{'a': 1, 'b': 2}
Calling getattr
Out[9]: 0

In [10]: t.b
Out[10]: 2


If you try to access any data with square bracket of the instance, directly it calls __getitem__ method

This below one is one of the beautiful example which is taken from some source(in python 2.x):

In [4]: class Test(object):
   ...:     def __getitem__(self, items):
   ...:         print '%-15s  %s' % (type(items), items)
   ...: t = Test()
   ...: t[1]
   ...: t['hello world']
   ...: t[1, 'b', 3.0]
   ...: t[5:200:10]
   ...: t['a':'z':3]
   ...: t[object()]

<type 'int'>     1
<type 'str'>     hello world
<type 'tuple'>   (1, 'b', 3.0)
<type 'slice'>   slice(5, 200, 10)
<type 'slice'>   slice('a', 'z', 3)
<type 'object'>  <object object at 0x7f9222469e20>


getter, setter methods are important in oops world to encapsulate the data through these methods. Python provides same accessibility via property. So, the method-attribute can behave as a data-attribute to the instance via property. This is one of the powerful feature to control the data value without much change to the outer world.

So, In the below example, the temperature is just an attribute to the outer world for the class Celsius and with help of property concept, the business logic is encapsulated over temperature without any interference to the outer world

class Celsius:
    def __init__(self, temperature = 0):
        self._temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

    def temperature(self):
        print("Getting value")
        return self._temperature

    def temperature(self, value):
        if value < -273:
            raise ValueError("Temperature below -273 is not possible")
        print("Setting value")
        self._temperature = value
In [117]: c = Celsius()

In [118]: c.temperature
Getting value
Out[118]: 0

In [119]: c.temperature = -300
ValueError                                Traceback (most recent call last)
<ipython-input-119-6dba9f781849> in <module>()
----> 1 c.temperature = -300

<ipython-input-116-5086c5ea8861> in temperature(self, value)
     14     def temperature(self, value):
     15         if value < -273:
---> 16             raise ValueError("Temperature below -273 is not possible")
     17         print("Setting value")
     18         self._temperature = value

ValueError: Temperature below -273 is not possible

In [120]: c.temperature = 30
Setting value

In [121]: c.temperature
Getting value
Out[121]: 30


This method will get called always, if you try to access any attribute, if it could not find then it will throw AttributeError, then it does call to __getattr__ method. So, if you want to keep any security access to any type of attribute this is the right method to cover it up.

Nice example in python 3.x:

In [106]: class Count:
     ...:     def __init__(self,mymin,mymax):
     ...:         self.mymin=mymin
     ...:         self.mymax=mymax
     ...:         self.current=None
     ...:     def __getattr__(self, item):
     ...:             self.__dict__[item]=0
     ...:             return 0
     ...:     def __getattribute__(self, item):
     ...:         print("calling", item)
     ...:         if item.startswith('cur'):
     ...:             raise AttributeError
     ...:         return object.__getattribute__(self,item)
     ...:         # or you can use ---return super().__getattribute__(item)
     ...: obj1 = Count(1,10)
     ...: print(obj1.mymin)
     ...: print(obj1.mymax)
     ...: print(obj1.current)
calling mymin
calling mymax
calling current
calling __dict__

It is very overview about these magic methods in python. Still, lot more to explore to get nuance details about usage.


About Navaneethan

mixed feelings...
This entry was posted in 10min, Python and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s