Access to the caller's globals, not your own

Rob Gaddi rgaddi at highlandtechnology.invalid
Mon Nov 14 12:57:27 EST 2016


Steven D'Aprano wrote:

> 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.
>

class Library:
  SPAMIFY = False
  def make_spam(m):
    ...

import library
Library = library.Library()

result = Library.make_spam(99)

-- 
Rob Gaddi, Highland Technology -- www.highlandtechnology.com
Email address domain is currently out of order.  See above to fix.



More information about the Python-list mailing list