Let's say we have three simulation methods:
def method1(func):
def wrapper(*args, **kwargs):
#Implementation of some simulator backend
#but as a toy model we just pass a string here
return func(*args, simulation_method='method1', **kwargs)
return wrapper
def method2(func):
def wrapper(*args, **kwargs):
#Implementation of some simulator backend
#but as a toy model we just pass a string here
return func(*args, simulation_method='method2', **kwargs)
return wrapper
def method3(func):
def wrapper(*args, **kwargs):
#Implementation of some simulator backend
#but as a toy model we just pass a string here
return func(*args, simulation_method='method3', **kwargs)
return wrapper
such that we can call a simulation
function with a specific method via
@method3
def simulation(simulation_method):
#Implementation of some computation that needs to be simulated
#but as a toy model we just print the following statement:
print(f"Running simulation with {simulation_method} method")
which yields the output
"Running simulation with method3 method"
I now want to define a decorator called MultiSimulation
that repeatedly calls the simulation function while using the given simulation methods with the following syntax:
@MultiSimulation
@method1
@method2
@method3
def simulation(simulation_method):
print(f"Running simulation with {simulation_method} method")
This should give the output:
"Running simulation with method1 method"
"Running simulation with method2 method"
"Running simulation with method3 method"
I am stuck with the definition of MultiSimulation and would be glad to get some help here. Thanks!
I tried different variations such as
def MultiSimulation(func):
def repeated_simulation(*args, **kwargs):
simulation_methods = []
if hasattr(func, '__wrapped__'):
simulation_methods = func.__wrapped__.simulation_methods
result = None
for simulation_method in simulation_methods:
kwargs['simulation_method'] = simulation_method
result = func(*args, **kwargs)
return result
repeated_simulation.simulation_methods = []
repeated_simulation.__wrapped__ = func
return repeated_simulation
but I don't get any output.
With the rework, here what you can get:
@MultiSimulation
@method1
@method2
@method3
def simulation(simulation_method):
print(f"Running simulation with {simulation_method} method")
return simulation_method
print(simulation())
# Running simulation with method1 method
# Running simulation with method2 method
# Running simulation with method3 method
# ['method1', 'method2', 'method3']
You need to update your decorators this way:
def method1(func):
def wrapper1(*args, simulation_method="method1", **kwargs):
return func(*args, simulation_method=simulation_method, **kwargs)
return wrapper1
And you need this decorator:
def MultiSimulation(func):
def repeated_simulation(*args, **kwargs):
tmp_fct = func
results = []
while tmp_fct:
try:
results.append(tmp_fct(*args, **kwargs))
except TypeError:
pass
try:
tmp_fct = tmp_fct.__closure__[0].cell_contents
except TypeError:
break
return results
return repeated_simulation
With this rework of decorators, it's possible to use your original style while getting the return values of the different simulation if necessary.
def method1(func):
def wrapper1(*args, simulation_method="method1", **kwargs):
return func(*args, simulation_method=simulation_method, **kwargs)
return wrapper1
def method2(func):
def wrapper2(*args, simulation_method="method2", **kwargs):
return func(*args, simulation_method=simulation_method, **kwargs)
return wrapper2
def method3(func):
def wrapper3(*args, simulation_method="method3", **kwargs):
return func(*args, simulation_method=simulation_method, **kwargs)
return wrapper3
def MultiSimulation(func):
def repeated_simulation(*args, **kwargs):
tmp_fct = func
results = []
while tmp_fct:
try:
results.append(tmp_fct(*args, **kwargs))
except TypeError:
pass
try:
tmp_fct = tmp_fct.__closure__[0].cell_contents
except TypeError:
break
return results
return repeated_simulation
@MultiSimulation
@method1
@method2
@method3
def simulation(simulation_method):
print(f"Running simulation with {simulation_method} method")
return simulation_method
print(simulation())
# Running simulation with method1 method
# Running simulation with method2 method
# Running simulation with method3 method
# ['method1', 'method2', 'method3']