0

I need to have a global dict with string as keys and function references as values. I don't want to write something similar to a switch, because I need to be able to fetch the keys list from another script. I tried to write a script looking like that :

GLOBAL_VARIABLE = {'id_1' : func_1,
                   'id_2' : func_2,
                   'id_3' : func_3
                  }

def get_id_list():
    return GLOBAL_VARIABLE.keys()

def func_1(arg):
    <do some stuff>

def func_2(arg):
    <do some stuff>

def func_3(arg):
    <do some stuff>

But when I do this, Python throws me an error "NameError: name 'func_1' is not defined". The only two solutions I could think of were:

  • Declare the global variable at the end of the file, but then it's really annoying if I have to edit it, I'd rather have this info as close as possible from the top of the file.

  • Declare a hackish function "get_global_variable" that (create and) return the exact same dict. It's working, but it's pretty ugly.

Is there a way to do some lazy declaration and/or what would be a more pythonic way to tackle this situation?

4
  • 1
    No, you need to define the dictionary (or at least populate it) after the functions are defined. Commented Apr 16, 2015 at 15:17
  • I really would like to avoid having this declaration deep at the bottom of my file for both practical and readability reasons. Commented Apr 16, 2015 at 15:48
  • If your IDE's any good, it doesn't matter where in the file it is! Commented Apr 16, 2015 at 15:56
  • I'd like to be able to edit those scripts with nothing more than Vi on the fly over a plain SSH connection. Commented Apr 16, 2015 at 16:02

3 Answers 3

3

The Pythonic way is to declare the variable after the function, regardless of how it may appear. Don't worry, other people will understand perfectly well why this is done.

Or if you really, really need to have variables appear before functions in a module, move the functions into a separate module and then import them. No kill like overkill...

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

3 Comments

the problem is that I might have to add lots of such function AND i need to be able to map them with a string identifier, I don't want to change imports on the caller file every time I add or change the id of such a function in this file. In fact I don't want the caller file to have the names of those functions, he's basically just iterating over them, hence the id fetching.
Sounds like you'd find a decorator to enumerate them to be useful.
I never really used decorator, but indeed looking at chepner's response, it looks like it might definitely solve my problem.
2

Define a decorator that adds the function references to the dictionary as you define the functions.

GLOBAL_VARIABLE = {}
def export(tag):
    def _(f):
        GLOBAL_VARIABLE[tag] = f
        return f
    return _

@export('id_1')
def func_1(arg):
    <do some stuff>

@export('id_2')
def func_2(arg):
    <do some stuff>

@export('id_3')
def func_3(arg):
    <do some stuff>

1 Comment

The name export, by the way, is borrowed from a co-worker who uses a similar function to add functions to __all__ in a module. Not sure how widespread this idea is, but I definitely didn't come up with it myself.
0

I hate this but it would "work".

Instead of literal variables, the name of each function is put in GLOBAL_VARIABLE.

>>> GLOBAL_VARIABLE = {
...     "id_1": "func_1",
...     "id_2": "func_2",
...     "id_3": "func_3",
... }

The functions are defined like before.

>>> def func_1():
...     return 1
...
>>> def func_2():
...     return 2
...
>>> def func_3():
...     return 3
...

After the function definitions, the function names in GLOBAL_VARIABLE are looked up to find the actual functions. These replace the names.

>>> GLOBAL_VARIABLE = {key: globals()[value] for (key, value) in GLOBAL_VARIABLE
.items()}

 

>>> GLOBAL_VARIABLE["id_1"]
<function func_1 at ...>
>>> GLOBAL_VARIABLE["id_2"]
<function func_2 at ...>

1 Comment

Yeah that's pretty hackish too, but it's already way prettier that what I did, I might use that for a start.

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.