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()
Enter fullscreen mode Exit fullscreen mode
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]}")
Enter fullscreen mode Exit fullscreen mode
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()}")
Enter fullscreen mode Exit fullscreen mode
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!
Enter fullscreen mode Exit fullscreen mode
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()}")
Enter fullscreen mode Exit fullscreen mode
That’s all for today. Thank you for reading, I would be pleased to read and answer your comments. See you next time.
原文链接:Python : advanced way to reduce the amount of repetitive code
暂无评论内容