ghostrider
ghostrider

Reputation: 5259

forward declaration on python vs using globals()

I have a global dict like this :

mydict = {
   "name1" : {
       "description"   : "random text 1" ,
       "function_name" : foo
    }
}

This is a global function in a module that doesn't have a if __name__ == "__main__":

That means that I need to declare the foo before I reference it - from what I have tried. Otherwise when I run my code I get 'foo' is not defined.

Later in one of my other function what i want to do is something like :

def randomCaller() :
   # ....
   mydict[ "name1" ][ "function_name"]()

Since I don't want to change how the file is structured - an alternative that I have is to use the name and change the above code into :

mydict = {
   "name1" : {
       "description"   : "random text 1" ,
       "function_name" : "foo"
    }
}
def randomCaller() :
   # ....
   fname = mydict[ "name1" ][ "function_name"]
   globals()[ fname ]()

Is there any concern/risk on the above? Would you suggest something different?

Upvotes: 1

Views: 273

Answers (1)

Green Cloak Guy
Green Cloak Guy

Reputation: 24691

@MarkMeyer came up with a great workaround for this in the comments:

"function_name": lambda *args, **kwargs: foo(*args, **kwargs)

(the arguments can be whatever you need them to be. This is the most flexible arrangement, but if you know foo() will use a certain set of arguments you can arrange the lambda to mirror that).

Ordinarily, this type of use of a lambda would be pretty useless ("why not just call foo in the first place?"). However, in this particular use case, it's uniquely useful, because the name foo is only evaluated when the lambda is called, and not when it's assigned.

In other words, this works on my python console:

>>> f1 = lambda: foo()
>>> f1()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
NameError: name 'foo' is not defined
>>> def foo():
...     print("Hello World!")
...
>>> f1()
Hello World!

That said, this solution is hacky, and might play weirdly with namespaces. The best way to handle the problem would be to just define foo() before defining mydict, but if you absolutely must declare mydict first, you could also simply declare "function_name": None initially, and then set it to foo() after you've defined foo():

mydict = {
    "name1" : {
       "description"   : "random text 1" ,
       "function_name" : None
    }
}
...
def foo():
    ...
mydict["name1"]["function_name"] = foo

Upvotes: 1

Related Questions