Say you have a bunch of factory functions, each of which does two things:
E.g.
class Dog:
def __init__(self, **very_many_kwargs):
pass
def create_police_dog(department, **dog_kwargs):
dog_kwargs['race'] = 'pitbull_terrier'
dog = Dog(**dog_kwargs)
police_academy = PoliceAcademy()
police_academy.train(dog)
return dog
def create_scary_dog(**dog_kwargs):
dog_kwargs['teeth_size'] = 'MAX'
dog_kwargs['eye_color'] = fetch_angry_eye_colors('https://dogs.com')
dog = Dog(**dog_kwargs)
dog.experience_unhappy_childhood()
return dog
How to combine multiple of such functions in series?
Decorators almost work but since you want your modifications to occur both before and after instantiation, they won't chain properly. Instead define a custom system of generic modifiers that can be chained together at creation time:
from abc import ABC, abstractmethod
class DogModifier(ABC):
@abstractmethod
def mod_kwargs(self, **kwargs):
pass
@abstractmethod
def post_init(self, dog):
pass
class PoliceDog(DogModifier):
def __init__(self, department):
self._dept = department
def mod_kwargs(self, **kwargs):
kwargs['race'] = 'pitbull_terrier'
def post_init(self, dog):
PoliceAcademy(self._dept).train(dog)
class ScaryDog(DogModifier):
def mod_kwargs(self, **kwargs):
kwargs['teeth_size'] = 'MAX'
kwargs['eye_color'] = fetch_angry_eye_color('https://dogs.com')
def post_init(self, dog):
dog.experience_unhappy_childhood()
def create_dog(*modifiers, **dog_kwargs):
for m in modifiers:
m.mod_kwargs(**dog_kwargs)
dog = Dog(**dog_kwargs)
for m in modifiers:
m.post_init(dog)
return dog
# ...
police_dog = create_dog(PoliceDog('bomb squad'), kw1='a', kw2='b')
scary_dog = create_dog(ScaryDog(), kw1='x', kw2='y')
scary_police_dog = create_dog(PoliceDog('bomb squad'), ScaryDog(), kw1='z')
*code shown as example only - bugfixes left as an exercise for the reader