As a programmer, you generally appreciate more control of your data and more control on the behavior of my program itself. It is in this moment when Python comes in our help with all its power letting us get right into the flow of our programming, avoiding us to lose something like define an attribute or get unexpected visitors inside our data.
As Python has constructors and destructors for the classes, so you can define tasks on the creation or destruction of the class, Python can intercept the calling of an specific attribute or even the calling of a not defined one.
__getattr__
What if you don’t define an attribute? Let’s see:
class Running: def __init__(self, start, finish): self.start=start self.finish=finish obj1 = Running(1, 10) print(obj1.start) # 1 print(obj1.finish) # 10 print(obj1.anewone) # --> AttributeError: 'Running' object has no attribute 'anewone'
In this example we have defined two attributes for the class Running
, start and finish during the construction of the class, then after instantiate the class in obj1
we try to print the contents of start, finish and a new attribute not defined call anewone
, raising an Attribute Error exception that exits our program. Bang!
To prevent that previous issue you must call our dearest __getattr__
it will intercept the request over that unknown attribute and will do something about it.
class Running: def __init__(self, start, finish): self.start=start self.finish=finish def __getattr__(self, item): self.__dict__[item] = 0 return 0 obj1 = Running(1, 10) print(obj1.start) # 1 print(obj1.finish) # 10 print(obj1.anewone) # 0
What did happen here?
All seems to be the same, but wait, the __getattr__
keyword is doing something there, assigning zero to the unknown attribute and returning it to show without raising any exception. Cool ah?
What else can I do with attributes?
Well, what if we want to prevent someone from accessing our attributes that starts with a specific substring? That one is hard ah? We would need to run through every attribute defined looking for the forbidden substring and then raise some kind of exception to warn about that protected name of the attribute. How can we do that?
Oh, don´t tell me, another dundee boy.
Yes! __getattribute__
__getattribute__
If you have __getattribute__
method in your class, Python invokes this method for every attribute regardless whether it exists or not.
Let´s see:
class Running: def __init__(self, start, finish): self.start=start self.finish=finish def __getattribute__(self, item): if item.startswith('ane'): raise AttributeError return object.__getattribute__(self,item) # or you can use ---return super().__getattribute__(item) obj1 = Running(1, 10) print(obj1.start) # 1 print(obj1.finish) # 10 print(obj1.anewone) # ... AttributeError
Now you can see how the if condition looks for the substring “ane” at the beginning of every attribute’s name and raise an exception AttributeError when it gets the condition. Easy Peasy.
What if we use the two keywords in the same Class?
Nooo, its the end of world!
Just joking. That is a good question because if the both dundee friends are in the class, __getattribute__
run first (remember it looks into every attribute) and if __getattribute__
need to raise an AttributeError exception, nothing happens and __getattr__
takes the control and do it job. Take care.
Hope you have take some new insights about these dundee boys __getattr__
and __getattribute__
they looks like being the same but they are very different between them.