Let us imagine, that you have some list of objects.
You need to call one specific function on each object in that list.
Here is an example :
class Dog:
def sound(self):
print("Woof")
class Cat:
def sound(self):
print("Meow")
class Cow:
def sound(self):
print("Mooo")
animals = [Dog(), Cat(), Cow()]
for a in animals: a.sound()
Nice. Now, imagine that each animal object must have at least two functions : sound
and insight
.
sound
does write line to the output stream and returns nothing, insight
does nothing but returns a string.
We would like to call sound
in each function and to print list containing insight
string of each animal :
class Dog:
def sound(self):
print("Woof")
def insight(self):
return "Humans are best!"
class Cat:
def sound(self):
print("Meow")
def insight(self):
return "Humans are slaves of cats"
class Cow:
def sound(self):
print("Mooo")
def insight(self):
return "Humans are violent indeed"
animals = [Dog(), Cat(), Cow()]
for a in animals: a.sound()
print(f"Insights : {[a.insight() for a in animals]}")
It may seem nice, but we use for loop each time we need to do the same thing with each animal. How may we reduce number of such syntax constructs? We could declare wrapper-class to wrap list of animals, intercepting function calls and returning lists of results :
class PluralAnimal:
def __init__(self, animals):
self.animals = animals
def sound(self):
for a in animals:
a.sound()
def insight(self):
return [a.insight() for a in self.animals]
plural = PluralAnimal(animals)
plural.sound()
print(f"Insights : {plural.insight()}")
Looks much better? Yes, but I have one concern : now we have to declare such wrapper-class for each case of use. For animals, vehicles, employees we have to declare PluralAnimal
, PluralVehicle
, PluralEmployee
.
How may we avoid that?
Dynamic function call interception
If we want to access some attribute of the object in runtime, using name of that attribute, we may use getattr
function :
class Example:
def func(self):
print("Hello, example!")
obj = Example()
func = getattr(obj, "func")
func() # output : Hello, example!
Let us write wrapper-class, using getattr
function :
class Plural:
def __init__(self, objs):
self.objs = objs
def __getattr__(self, name):
def func(*args, **kwargs):
return [getattr(o, name)(*args, **kwargs) for o in self.objs]
return func
plural = Plural(animals)
plural.sound()
print(f"Insights : {plural.insight()}")
That's all for today. Thank you for reading, I would be pleased to read and answer your comments. See you next time.
Top comments (0)