27

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()
Alasdair
  • 298,606
  • 55
  • 578
  • 516
thecatwagon
  • 271
  • 1
  • 3
  • 4
  • 1
    So you want a bunch of functions that all do the same thing? – Jeffrey Swan Jan 14 '16 at 16:28
  • 5
    It's clearly an [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem), please show us WHAT is a problem you are trying to solve, not HOW you think you want to solve it. – Łukasz Rogalski Jan 14 '16 at 16:29
  • 2
    Using `list` as a variable name is a bad idea too... – Hugh Bothwell Jan 14 '16 at 16:33
  • duplicate of http://stackoverflow.com/questions/13184281/python-dynamic-function-creation-with-custom-names – rbp Jan 14 '16 at 16:48
  • Whatever you are doing, the way you are thinking is wrong! May be you should learn about [generators](https://wiki.python.org/moin/Generators). – ssapkota Jan 14 '16 at 16:49

7 Answers7

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.

kklepper
  • 763
  • 8
  • 13
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()
tdelaney
  • 73,364
  • 6
  • 83
  • 116
  • 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 Jan 14 '16 at 17:33
  • @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. – tdelaney Jan 14 '16 at 17:39
  • 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. – enrico.bacis Jan 14 '16 at 17:53
  • 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` – Timo Apr 25 '22 at 18:03
8

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.

Nikita
  • 6,101
  • 2
  • 26
  • 44
  • 7
    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 ?" – C.LECLERC Jan 14 '16 at 16:46
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
pyano
  • 1,885
  • 10
  • 28
2

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)
enrico.bacis
  • 30,497
  • 10
  • 86
  • 115
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
Jeff Sell
  • 81
  • 1
  • 4
  • 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! – tdelaney Jan 14 '16 at 16:45
0

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