Nikhil Mishra
Nikhil Mishra

Reputation: 1250

Trigger a function automatically if any function of a list of functions is called in Python

Is there a way to trigger a function automatically if any of a list of functions is called in python?

Like say function a is attached to a list of functions [b, c, d, e] and if either of [b, c, d, e] is called (for example say b()) then a() is called automatically before it?

I want to use function a to set up some values before b is called so that b can use it.

Like for example:

# function b is some inbuilt, library function
attach(a, b) #attach function b to function a
b()
# If function b is called first function a gets called, it changes up some 
# global variables for the use of function b, then function b gets executed 

I have some global variables and some class methods, The global variables are somethings like CLASSIFIER(e.g. LogisticRegression or XGBClassifier), CLASSIFIER_TYPE(e.g. 'linear' or Tree) which I need to change everytime I call fit and predict methods on their respective pipelines (e.g. pipeline_linear or pipeline_tree).fit/predict. This is because I have written code like:

CLASSIFIER = LogisticRegression
CLASSIFIER_TYPE = 'linear'
pipeline_linear = make_pipeline(preprocessing_pipe, CLASSIFIER())
pipeline_linear.fit(X, y)
CLASSIFIER = XGBClassifier
CLASSIFIER_TYPE = 'tree'
pipeline_tree = make_pipeline(preprocessing_pipe, CLASSIFIER())
pipeline_tree.fit(X, y)
linear_preds = pipeline_linear.predict(X) # This statement throws an error
# because CLASSIFIER and CLASSIFIER_TYPE are not changed
# preprocessing_pipe uses CLASSIFIER_TYPE internally to take care of  
# handling both types of classifiers differently.

So based on the pipeline I am using, the global variables need to be modified accordingly in order for the fit and predict methods to work on the pipelines(pipeline_linear and pipeline_tree).

Any other good approach to take care of these situations will be really helpful!

Upvotes: 0

Views: 1036

Answers (3)

javidcf
javidcf

Reputation: 59731

I think you can still use something like a decorator/wrapper. See if something like this could work for you:

MY_GLOBAL = 123

def wrap_with_global_value(func, global_val):
    def wrap(*args, **kwargs):
        global MY_GLOBAL
        prev_global_val = MY_GLOBAL
        MY_GLOBAL = global_val
        result = func(*args, **kwargs)
        MY_GLOBAL = prev_global_val
        return result
    return wrap

class MyClass(object):
    def my_func(self):
        global MY_GLOBAL
        print('from my_func: MY_GLOBAL is {}.'.format(MY_GLOBAL))

my_obj = MyClass()
my_obj.my_func = wrap_with_global_value(my_obj.my_func, 456)

print('Before calling my_func: MY_GLOBAL is {}.'.format(MY_GLOBAL))
my_obj.my_func()
print('After calling my_func: MY_GLOBAL is {}.'.format(MY_GLOBAL))

Output:

Before calling my_func: MY_GLOBAL is 123.
from my_func: MY_GLOBAL is 456.
After calling my_func: MY_GLOBAL is 123.

You can add functools.wraps if that is important for you.

Upvotes: 2

Dan S
Dan S

Reputation: 286

Surely it would be easier to just call the function at the top of each other function?

def setup():
    # Set some variables
    pass

def target1():
    setup()
    pass

def target2():
    setup()
    pass

Upvotes: 0

msaba92
msaba92

Reputation: 357

Use a wrapper.

If your function is my_function and your list is list_of_functions:

def func_wrapper(query):
    for additional_function in list_of_functions:
        # Do whatever you need to do with your list of functions
        additional_function()

    my_function(query)

Upvotes: 2

Related Questions