28

Would it be possible to use a variable as a function name in python? For example:

list = [one, two, three]
for item in list:
    def item():
         some_stuff()
5
  • 1
    So you want a bunch of functions that all do the same thing? Commented Jan 14, 2016 at 16:28
  • 5
    It's clearly an XY problem, please show us WHAT is a problem you are trying to solve, not HOW you think you want to solve it. Commented Jan 14, 2016 at 16:29
  • 2
    Using list as a variable name is a bad idea too... Commented Jan 14, 2016 at 16:33
  • duplicate of stackoverflow.com/questions/13184281/… Commented Jan 14, 2016 at 16:48
  • Whatever you are doing, the way you are thinking is wrong! May be you should learn about generators. Commented Jan 14, 2016 at 16:49

7 Answers 7

34

The trick is to use globals():

globals()['use_variable_as_function_name']()

will be equivalent to

use_variable_as_function_name()

found at: George Sakkis https://bytes.com/topic/python/answers/792283-calling-variable-function-name


The following is a useful application of the above questioning I needed right now (that's why I came here): apply special functions to URLs depending on their nature:

l = ['condition1', 'condition2', 'condition3']

I used to write

if 'condition1.' in href:
    return do_something_condition1()
if 'condition2.' in href:
    return do_something_condition2()
if 'condition3.' in href:
    return do_something_condition3()

and so on - my list has 19 members by now and keeps growing.

While investigating the subject and developing, the function code had been quite naturally part of the main function making it soon horrible to read, so relocating the working code into functions was a great relief already.

This clumsy code above can be substituted by:

for e in l:              # this is my condition list
    if e + '.' in href:  # this is the mechanism to choose the right function
        return globals()['do_something_' + e]()

This way the main code stays simple and legible no matter how long the list of conditions may grow.

Those functions corresponding to the condition labels have to be declared conventionally, of course, depending on the nature of the type of the URL in question:

def do_something_condition1(href):
    # special code 1
    print('========1=======' + href)

def do_something_condition2(href):
    # special code 2
    print('========2=======' + href)

def do_something_condition3(href):
    # special code 3
    print('========3=======' + href)

Test:

>>> href = 'https://google.com'
>>> for e in l:
...     globals()['do_something_' + e](href)
...
========1=======https://google.com
========2=======https://google.com
========3=======https://google.com

Or, to model it closer to the above scenario:

success = '________processed successfully___________ ' 

def do_something_google(href):
    # special code 1
    print('========we do google-specific stuff=======')
    return success + href 

def do_something_bing(href):
    # special code 2
    print('========we do bing-specific stuff=======')
    return success + href 

def do_something_wikipedia(href):
    # special code 3
    print('========we do wikipedia-specific stuff=======')
    return success + href 

Test:

l = ['google', 'bing', 'wikipedia']

href = 'https://google.com'

def test(href):
    for e in l:
        if e + '.' in href:
            return globals()['do_something_' + e](href)

>>> test(href)
========we do google-specific stuff=======
'________processed successfully___________ https://google.com'

Result:

Further elaboration on the problem now just amounts to augment the condition list one by one and write the corresponding functions depending on the argument. The above mechanism will pick the right one thereafter.

Sign up to request clarification or add additional context in comments.

3 Comments

The most thorough answer.
I prefer using locals() to globals(). It seems a little safer to keep the scope smaller, if you can.
How to use this in class method? i'm getting key error :(
11

You can't define a function using a variable but you can rebind the function to the variable name. Here is an example to add them to the module's global namespace.

one = 'one'
two = 'two'
three = 'three'
l = [one, two, three]
def some_stuff():
    print("i am sure some stuff")
for item in l:
    def _f():
        some_stuff()
    globals()[item] = _f
    del _f

one()
two()
three()

4 Comments

I believe this is not sufficient if some_stuff has code that depends on the item (I believe this is the case the OP is describing, even if it's not really well stated).
@enrico.bacis Yeah, it could be that OP has multiple functions some_stuff1() and etc... and is looking to assign one = some_stuff1, two = some_stuff2, and etc... I was trying to match the example assuming he can figure out the real use case.
yes, check my answer to understand what I meant ;) The problem is that like this all the functions are "backed" by the same _f function.
Can I use a variable as function in dot notation? E.g. db.variable_fun('hello') where variable_fun is a function whose name comes from a variable - e.g. from sys._getframe().f_code.co_name
9

Functions in Python are objects that have a name referencing them, so you can pass them around, store in lists and dictionaries (common use when creating jump-tables).

I.e. this works:

   def one():
        print "1"

    def two():
        print "2"

    def three():
        print "3"

    l = [one, two, three]

    for item in l:
        item()

Will print:

1
2
3

Don't use list as variable name, because this way you redefine buildin.

def is the statement that is also executed, unlike function defenitions in compiled languages. So when you call def item(): you don't define function for one, two, three, but redefine item name.

In general it is not quite clear what you're trying to do, but it doesn't look like a good idea. May be explain what you try to accomplish, or rethink the way you want to do it.

1 Comment

The question is : "is it possible to define functions based of a list of names ?" not "is it possible to execute a list of predefined functions ?"
5

Here is a workaround wrapped in a class. It uses a dictionary for the mapping:

class function_class:
    def __init__(self,fCase):
        fDic = {'A':self.A,         # mapping: string --> variable = function name
                'B':self.B,
                'C':self.C}
        self.fActive = fDic[fCase]
    def A(self): print('here runs function A')
    def B(self): print('here runs function B')
    def C(self): print('here runs function C')
    def run_function(self):
        self.fActive()

#---- main ----------        
fList = ['A','B','C']              # list with the function names as strings
for f in fList:                    # run through the list
    g = function_class(f)
    g.run_function()

The output is:

here runs function A
here runs function B
here runs function C

Comments

3

You can do this:

from types import FunctionType
from copy import copy

def copy_function(fn):
    return FunctionType(copy(fn.func_code), copy(fn.func_globals), name=item,
                        argdefs=copy(fn.func_defaults),
                        closure=copy(fn.func_closure))

list = ['one', 'two', 'three']

for item in list:
    def _fn():
        print(item)
    globals()[item] = copy_function(_fn)
list = map(eval, list)

2 Comments

item should be passed as parameter to copy_function and not as global variable.
AttributeError: 'function' object has no attribute 'func_code' - this works
1

The short answer is no. When you declare a variable, you have bound a name to an object. The same is true when you declare a function. You can try it out for yourself in a python console and see what happens:

>name=1
>name
1
>def name(x): print(x+1)

>name
function name at 0x000001CE8B8122F0

1 Comment

OP could assign the function to a variable or perhaps append it to a list and would end up with a closures. Whether that's useful is another question!
1

Here is an updated answer from @enrico.basis:

from types import FunctionType
from copy import copy


def copy_function(fn):
    return FunctionType(
        code=copy(fn.__code__),
        globals=copy(fn.__globals__),
        name=fn.__name__,
        argdefs=copy(fn.__defaults__),
        closure=copy(fn.__closure__)
    )


items = ['print_one', 'print_two', 'print_three']

for ele in items:
    def _f():
        return 'String from {}() function'.format(ele)
    _f.__name__ = ele
    locals()[ele] = copy_function(_f)
    del _f


for ele in items:
    _f = eval(ele)
    print('- {}'.format(_f()))

This will give the following output:

- String from print_one() function
- String from print_two() function
- String from print_three() function

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.