[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