Access to the caller's globals, not your own

Steven D'Aprano steve+comp.lang.python at pearwood.info
Mon Nov 14 00:20:49 EST 2016


Suppose I have a library function that reads a global configuration setting:

# Toy example
SPAMIFY = True
def make_spam(n):
    if SPAMIFY:
        return "spam"*n
    else:
        return "ham"*n


Don't tell me to make SPAMIFY a parameter of the function. I know that. That's 
what I would normally do, but *occasionally* it is still useful to have a 
global configuration setting, and those are the cases I'm talking about.


Now the caller can say:

import library
library.SPAMIFY = False
result = library.make_spam(99)


but that would be Wrong and Bad and Evil, because you're affecting *other* 
code, not your code, which relies on SPAMIFY being True. Doing this is (maybe) 
okay when testing the library, but not for production use.

What I really want is for make_spam() to be able to look at the caller's 
globals, so that each caller can create their own per-module configuration 
setting:

import library
SPAMIFY = False  # only affects this module, no other modules
result = library.make_spam(99)


But... how can make_spam() look for the caller's globals rather than its own?

I'd rather not do this:


def make_spam(n, namespace):
    SPAMIFY = namespace['SPAMIFY']
    ...

which forces the user to do this:

result = library.make_spam(99, globals())


which defeats the purpose of making it a global setting. (If I wanted to 
*require* the caller to pass a parameter, I would just force them to pass in 
the flag itself. The whole point is to not require that.)

I'd be okay with making the namespace optional:


def make_spam(n, namespace=None):
    if namespace is None:
        namespace = ... # magic to get the caller's globals
    SPAMIFY = namespace['SPAMIFY']
    ...


but what magic do I need? globals() is no good, because it returns the 
library's global namespace, not the caller's.


Any solution ought to work for CPython, IronPython and Jython, at a minimum.




-- 
Steven
299792.458 km/s — not just a good idea, it’s the law!




More information about the Python-list mailing list