2

Im trying to create a more dynamic program where I define a function's name based on a variable string.

Trying to define a function using a variable like this:

__func_name__ = "fun"

def __func_name__():
  print('Hello from ' + __func_name__)

fun()

Was wanting this to output:

Hello from fun

The only examples I found were: how to define a function from a string using python

isethi
  • 661
  • 1
  • 10
  • 22
  • You need to use `exec`. But don't. This is not a good thing to do. – rdas Apr 30 '19 at 06:31
  • @rdas Why isn't it a good thing? – isethi Apr 30 '19 at 06:31
  • This is not "more dynamic" - it is simply bad. Do not do it. – Patrick Artner Apr 30 '19 at 06:32
  • Apart from being a huge risk for RCE, it's not better than just normal code: https://stackoverflow.com/questions/1933451/why-should-exec-and-eval-be-avoided – rdas Apr 30 '19 at 06:33
  • @isethi what if you lose/change `__func_name__` - how will you ever reference your function again? What if that name is something you don't want and it ends up clobbering the rest of the code... eg... it inadvertently gets set to a name that shadows another essential function/module or to `open` or `list` or other builtins...? – Jon Clements Apr 30 '19 at 06:34
  • If you simply want the nameof the function you are currently it, you can get its name:: `def fun(): print(fun.__name__)` – Patrick Artner Apr 30 '19 at 06:37
  • @JonClements couldn't you make a black list of what `__func_name__` cannot be. In the blacklist you would define that `open`, `list` etc.. couldn't be used – isethi Apr 30 '19 at 06:37
  • @isethi you could - but that's going even further down the rabbit hole on top of what you want to do here... you'll end up with hundreds of lines of (attempted guard) code that'll still break at some point - you won't be able to debug it effectively... and everyone (including you) will regret not listening to advice here :) Perhaps if you explain why you want to do this - there may well be other more practical options... – Jon Clements Apr 30 '19 at 06:38
  • @JonClements I guess my question is why didn't python make another way to dynamically name functions based on strings and not need exec as to be safe – isethi Apr 30 '19 at 06:40
  • 2
    @isethi why do you think dynamically naming a function is something you should do and why Python should allow you do it? It's dangerous/pretty much pointless... Python does try to avoid letting you shoot yourself in the foot... (although - it does let you if you really want to...) – Jon Clements Apr 30 '19 at 06:41
  • @JonClements I was thinking if you had that capability you could automatically add and remove functions and also analyze them for efficiency and manipulate them using the string functions python lets you do. – isethi Apr 30 '19 at 06:47
  • I'm not sure what you mean by *analyze them for efficiency and manipulate them using the string functions python lets you do*... Also, you could "add" dynamically named functions (with the cavaet of name shadowing/clashing), but unless you're storing them in a `dict` or similar, then you'd have to have some method of keeping track of those (on top of what Python already does internally for code objects etc...) to be able to remove them again... (or to even access them again...). If you could describe what it is you're wanting to do - I'm sure there's bound to be better ways of doing it. – Jon Clements Apr 30 '19 at 06:50
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/192611/discussion-between-isethi-and-jon-clements). – isethi Apr 30 '19 at 06:51

2 Answers2

5

You can update globals:

>>> globals()["my_function_name"] = lambda x: x + 1
>>> my_function_name(10)
11

But usually is more convinient to use a dictionary that have the functions related:

my_func_dict = {
    "__func_name__" : __func_name__,
}

def __func_name__():
  print('Hello')

And then use the dict to take the funtion back using the name as a key:

my_func_dict["__func_name__"]()
Netwave
  • 40,134
  • 6
  • 50
  • 93
  • is there any way to run multiple lines of code inside of that lambda like you would inside of a normal structured function? – isethi Apr 30 '19 at 07:32
  • @isethi, it is better you just define a function for that, I used lambda as an example, but you can use whatever callable object there. – Netwave Apr 30 '19 at 07:33
1

This should do it as well, using the globals to update function name on the fly.

def __func_name__():
  print('Hello from ' + __func_name__.__name__)

globals()['fun'] = __func_name__

fun()

The output will be

Hello from __func_name__
Devesh Kumar Singh
  • 20,259
  • 5
  • 21
  • 40