Strange effect with import
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Thu Dec 20 17:13:13 EST 2012
On Thu, 20 Dec 2012 20:39:19 +0000, Jens Thoms Toerring wrote:
> Hi,
>
> I hope that this isn't a stupid question, asked already a
> hundred times, but I haven't found anything definitive on the problem I
> got bitten by. I have two Python files like this:
>
> -------- S1.py ------
> import random
> import S2
>
> class R( object ) :
> r = random.random( )
>
> if __name__ == "__main__" :
> print R.r
> S2.p( )
>
> -------- S2.py ------
> import S1
>
> def p( ) :
> print S1.R.r
>
> and my expectation was that the static variable 'r' of class R
The terminology we prefer here is "class attribute", not "static
variable". Attributes are always assigned in dynamic storage, whether
they are per-instance or on the class.
> would be
> identical when accessed from S1.py and S2.py. Unfortunately, that isn't
> the case, the output is different (and R seems to get instantiated
> twice).
You don't instantiate R at all. You only ever refer to the class object,
you never instantiate it to create an instance. What you are actually
seeing is a side-effect of the way Python modules are imported:
- Python modules are instances that are instantiated at import
time, and then cached by module name;
- the module name is *usually* the file name (sans .py extension),
except when you are running it as a script, in which case it
gets set to the special value "__main__" instead.
So the end result is that you actually end up with THREE module objects,
__main__, S2 and S1, even though there are only two module *files*. Both
__main__ and S1 are instantiated from the same source code and contain
the same objects: both have a class called R, with fully-qualified names
__main__.R and S1.R, but they are separate objects.
[...]
> or, alternatively, if I put the defintion of class R into a third file
> which I then import from the other 2 files, things suddenly start to
> work as expected/ Can someone explain what's going one here? I found
> this a bit surprising.
You have a combination of two tricky situations:
* A circular import: module S1 imports S2, and S2 imports S1.
* A .py file, S1.py, being used as both an importable module
and a runnable script.
Circular imports are usually hard to get rid at the best of time.
Combined with the second factor, they can lead to perplexing errors, as
you have just found out.
> This is, of course, not my "real" code - it would be much more sensible
> to pass the number to the function in the second file as an argument -
> but is the smallest possinle program I could come up with that
> demonstrate the problem.
And let me say sincerely, thank you for doing so! You would be amazed how
many people do not make any effort to simplify their problem before
asking for help.
> In my "real" code it's unfortunately not
> possible to pass that number to whatever is going to use it in the
> other file, I have to simulate a kind of global variable
> shared between different files.
Well, I find that hard to believe. "Not convenient"? I could believe
that. "Difficult"? Maybe. "Tricky"? I could even believe that. But "not
possible"? No, I don't believe that it is impossible to pass variables
around as method arguments.
--
Steven
More information about the Python-list
mailing list