[Tutor] Anti-Patterns in Python Programming

Steven D'Aprano steve at pearwood.info
Mon Jul 14 03:21:35 CEST 2014


On Sun, Jul 13, 2014 at 08:01:03PM -0400, Audrey M Roy wrote:

[...]
> > This is perfectly clean: the eggs module reaches into the spam module,
> > grabs the current value of x (23), and sticks that value into itself.
> > What it's doing may be more clear if we re-write eggs.py in a slightly
> > longer way:
> >
> > import spam
> > x = spam.x
> > del spam
> 
> This was the piece of information that was missing in my head. Thank you. At
> first I was surprised to learn that x was rebound in the local namespace. I had
> always assumed it worked differently, as some sort of special reference to
> the original object rather than a copy.

Yes! That's *exactly* the issue that can cause confusion.


> With this in mind, is the uncommon pattern of using "from...import" to create
> a reference to a mutable object in the current namespace okay to use in
> some cases?
> Or is it bad practice?
> I'm not sure whether to think of it as an occasionally-useful feature or as an
> avoid-at-all-costs hack.

You mean something like this?

# === shared.py ===
data = ['stuff', 'goes', 'here']

# === a.py ===
from shared import data
data.insert(0, 'more')

# === b.py ===
from shared import data
# result of this next line depends on whether a or b runs first
print(data[0] == 'more')



What you're doing here is effectively creating a global variable which 
is shared across multiple modules, instead of safely confined to a 
single module. So long as you only mutate data, and not re-assign it, 
all the other modules will see the same changes.

That makes it occassionally useful, but more often you should avoid this 
as an example of "global variables considered harmful".

(If anyone is unsure about why global variables should be avoided, 
please ask.)

If I really needed this, I'd rather do `import shared` and then refer to 
`shared.data`. That way, it is obvious that you're accessing an external 
object, and you're not limited to mutation methods, you can re-bind the 
value as well:

shared.data = 42

But I stress that, apart from a few exceptions such as application-wide 
config options, relying on global variables is usually a bad idea.



-- 
Steven


More information about the Tutor mailing list