Access to the caller's globals, not your own
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Wed Nov 16 03:36:02 EST 2016
On Tuesday 15 November 2016 15:55, Dan Sommers wrote:
> On Mon, 14 Nov 2016 16:20:49 +1100, Steven D'Aprano wrote:
>
>> import library
>> SPAMIFY = False # only affects this module, no other modules
>> result = library.make_spam(99)
>
> I must be missing something, because it seems too obvious:
[snip]
I wouldn't say "obvious" so much as "complex".
A factory function or a class that holds state for a local make_spam() callable
would be a possible solution, but it significantly increases the complexity,
especially for the simple case:
import library
result = library.make_spam(arg)
versus:
import library
make_spam = library.make_library()
result = make_spam(arg)
What a drag.
[...]
> How do you want the following code to work:
>
> import library
> SPAMIFY=False
>
> def make_false_spam():
> return library.make_spam(99)
>
> def make_true_spam():
> global SPAMIFY
> SPAMIFY=True
> return library.make_spam(99)
>
> I don't have to tell you how many things can go wrong with code like
> that. ;-)
Indeed.
> Yes, it's a straw man. No, I don't think we have all the details of
> your use case. Yes, I'm willing to have missed something subtle (or not
> so subtle).
The use-case shouldn't matter, because I think I've been hanging around here
for long enough that you should trust me that I'm not one to abuse global
variables :-)
But, for what its worth...
I have a function, let's call it quartile(data, n). Unfortunately there's about
a dozen different ways to calculate quartiles, and they all give ever-so-
slightly different results. So I end up with:
def quartile(data, n, scheme="Method 7"):
...
which lets the caller choose the specific calculation method they want to use,
or just use the default. *My* default, chosen by me, which may or may not be
convenient.
And then there's a bunch of other functions which depend on quartile(). I don't
have to list them, but there's at least two and may be more. They too will have
an optional parameter to choose a calculation method. And *that* almost rules
out your factory function idea: having to call a factory to create multiple
functions is too confusing for a library API.
quartile, iqr, blah blah blah = library.make_functions()
So while I'd consider that under some circumstances, I don't like it here.
I'd like the caller to be able to set their own default, if they don't like
mine, in the easiest way possible. That means a global.
DEFAULT_SCHEME = "Method 7"
# Late binding of the default, instead of early binding.
def quartile(data, n, scheme=None):
if scheme is None:
scheme = DEFAULT_SCHEME
...
Say they want to match the same calculation method that Excel uses, they can
just modify the library.DEFAULT_SCHEME and forget all about it.
But that's globally global, and I actually want it to only be global to their
own module. Hence my question.
As an alternative, I'm thinking of allowing the caller to set an environment
variable... only that's globally global too.
--
Steven
299792.458 km/s — not just a good idea, it’s the law!
More information about the Python-list
mailing list