[Tutor] Anti-Patterns in Python Programming

Steven D'Aprano steve at pearwood.info
Sat Jul 12 04:43:11 CEST 2014


On Fri, Jul 11, 2014 at 01:04:59PM -0700, Audrey M Roy wrote:
> Steven, any chance you could clarify how to interpret that section? I'm
> assuming it refers to not importing objects that share state across modules?

Importing objects that share state across modules was not the problem 
I was talking about. Let's have two imaginary modules, spam and eggs:

# spam.py
x = 23


# eggs.py
from spam import x


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

So now it is clear that any link between eggs.x and spam.x is lost, gone 
for good. They are now completely independent variables which happen to 
share the same value.

This is perfectly fine if x is being used as a constant. Since neither 
spam nor eggs are changing x, there's no problem.

It's also perfectly fine if spam.x and eggs.x are *supposed* to be 
independent. If you're intending for eggs to just get it's *initial* 
value from spam, and then treat it as a separate value from then on, 
then there's no problem.

But note that if x is *mutable*, like a list, then eggs.x is NOT a 
copy. It is just a different reference to the same object, which means 
that changes to eggs.x will effect spam.x and visa versa, since they are 
the same mutable object. So that's another possible issue to be 
concerned about.

The problem I meant occurs when you don't intend for the link to be 
lost. The spam module sometimes re-assigns x, giving it a different 
value. In other words, spam.x is used as a variable, not a constant. 
(This is itself a bit of a worry, global state is often harmful and best 
avoided, but sometimes there are reasons for it.) The spam module can 
re-assign x later on:

# inside spam, some function calls this:
global x
x = 42


rebinding spam.x, but eggs.x is oblivious.


The common pattern, where you import a function or a class or a 
constant, and it never gets mutated or rebound, is perfectly fine. But 
there are odd gotchas to "from ... import" that may be surprising. 
That's why I think one needs to be cautious about doing "from ... 
import". You need to think about it: are you sharing an object, where 
modifications to the object will be seen across multiple modules? Is it 
intended as a variable or a constant? If you don't think about it, one 
day you'll be bitten.


-- 
Steven


More information about the Tutor mailing list