Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pythonic, elegant way of dynamically defining a list of statically defined functions?

I have only started learning Python recently. Let me explain what I am trying to accomplish. I have this .py script that basically has several functions (hard-coded into the script) that all need to be added to a single list, so that I can get the function I require by simply using the index operator as follows:

needed_function = function_list[needed_function_index]

My first attempt at implementing this resulted in the following code structure:

(imports)
function_list = []
(other global variables)

def function_0 = (...)
function_list.append(function_0)

def function_1 = (...)
function_list.append(function_1)

def function_2 = (...)
function_list.append(function_2)

(rest of code)

But I don't like that solution since it isn't very elegant. My goal is to be able to simply add the function definition to the script (without the append call) and the script will automatically add it to the list of functions.

I've thought of defining all the functions within another function, but I don't think I'd get anywhere with those. I thought of maybe "tagging" each function with a decorator but I realized that decorators (if I understand them correctly) are called every time a function is called, and not just once.

After some time I came up with this solution:

(imports)
(global variables)

def function_0 = (...)

def function_1 = (...)

def function_2 = (...)

function_list= [globals()[x] for x in globals() if re.match('^function_[0-9]+$', x)]

(rest of code)

I like it a bit more as a solution, but my only qualm with it is that I would prefer, for cleanliness purposes, to completely define function_list at the top of the script. However, I cannot do that since an invocation of globals() at the top of the script would not contain the functions since they have not been defined yet.

Perhaps I should simply settle for a less elegant solution, or maybe I am not writing my script in an idiomatic way. Whatever the case, any input and suggestions are appreciated.

like image 782
Lanaru Avatar asked Jan 17 '23 07:01

Lanaru


2 Answers

You are mistaken about decorators. They are invoked once when the function is defined, and the function they return is then the value assigned to the function name, and it is that function that is invoked each time. You can do what you want in a decorator without incurring runtime overhead.

my_functions = []

def put_in_list(fn):
    my_functions.append(fn)
    return fn

@put_in_list
def function1():
    pass

@put_in_list
def function2():
    pass

PS: You probably don't need to worry about runtime overhead anyway.

PPS: You are also trying to optimize odd things, you might be better off simply maintaining a list in your file. How often are you adding functions, and with how little thought? A list is not difficult to update in the source file.

like image 97
Ned Batchelder Avatar answered Jan 18 '23 22:01

Ned Batchelder


Example of using a decorator that does not add any overhead to the function call:

my_list = []

def add_to_my_list(func):
    print 'decorator called'
    my_list.append(func)
    return func

@add_to_my_list
def foo():
    print 'foo called'

@add_to_my_list
def bar():
    print 'foo called'

print '-- done defining functions --'
my_list[0]()
my_list[1]()
like image 34
FlorianLudwig Avatar answered Jan 19 '23 00:01

FlorianLudwig