0

Yet another simple problem giving me issues.

Suppose I have the following:

#!/usr/bin/python 
ref = 30
def f(x):
   print x + ref
f(50)

One aspect that's convenient for my purposes so far is that (I suppose) ref is treated as a global variable by the function f, and so doesn't need to be specified as an argument for f.

However, I get problems when I want to store f in a separate module, say myfunctions:

#!/usr/bin/python 
import myfunctions
ref = 30
myfunctions.f(50)

where myfunctions contains the definition of f as above. When attempting to run this, I get the NameError that "global name 'ref' is not defined."

I am guessing that this is because the main module and the 'myfunctions' module have different global namespaces, but is there a nice way round this - without necessarily having to include ref as an argument for f?

4

1 回答 1

2

As you've discovered global variables don't work like that - nor should they. Here are some things you can do, but shouldn't.

myfunctions.py

ref = 30
def f(x):
    print x + ref

our_caller.py

import myfunctions
myfunctions.f(10) # prints 40
myfunctions.ref = 50
myfunctions.f(10) # prints 60

But then what about some_other_caller.py ?

import myfunctions
myfunctions.f(20) # prints 50? prints 70?

It depends on when you messed around with the global variable in the myfunctions module.

Additionally, as a thought experiment, imagine the code you posted above did work as you expected (it would in some languages). What happens in the case where some_other_caller imports our_caller which imports myfunctions. Which ref is used then? It could be more complex, some_other_caller could call a function in our_caller which in turn calls myfunctions.f - so we use the ref from our_caller? So the behaviour is potentially different if some_other_caller called myfunctions directly?

That's not a world anyone wants to live in.

The better way of doing it is more like:

myfunctions.py

def f(x, ref=30):
    print x + ref

our_caller.py

import myfunctions
myfunctions.f(10) # prints 40
myfunctions.f(10, ref=50) # prints 60

Then people can see what's going on - there's no weird state changing. Global state really is best avoided. You'll hear that again and again. Ignore that advice at your own peril (and that of any poor soul that has to support your code later).

EDIT: Additional to your comment above about your use case it's not uncommon to see a patterns like the following.

REF = 30
ref_count = 0

def f(x, ref=REF, other_thing=None):
    if not other_thing:
        other_thing = ref_count
    print x + ref + other_thing

def add_ref(current_count=None):
    global ref_count
    if current_count is not None:
        ref_count = current_count
    ref_count += 1

You can keep the global variables (REF is more like a global constant). When you call f externally you can choose to supply values for them or allow them to be the defaults. Also, you can call add_ref, supplying it with a new value to use for the global copy in the module.

Again, same rules apply - you've added global state to your module that can be effected by external modules. You need to be very careful about who's changing it and a better architecture would attempt to avoid this situation in the first instance.

于 2013-10-10T13:20:42.603 回答