exec, import and isinstance
Peter Otten
__peter__ at web.de
Tue Feb 8 04:36:54 EST 2011
Michele Petrazzo wrote:
> Hi all,
> I'm playing with python internals and I'm discovering a strange behavior
> of isinstance. Considering the following test case:
>
> test/bar.py
> test/b.py
> test/a/__init__.py
> test/a/foo.py
>
> -- __init__.py -> empty
>
> --- foo.py:
> class foo: pass
> c = foo
>
> --- b.py
> def ret():
> d = {}
> #s = "import sys;sys.path.append('a');import foo" ## this cause the
> problem
> s = "import sys;from a import foo"
> exec s in d
> return d["foo"].c
>
> --- bar.py
> import a.foo
> import b
>
> c1 = a.foo.foo
> c2 = b.ret()
>
> print c1, c2
> print isinstance(c2(), c1)
> ---
>
> Executing bar.py, I receive:
> a.foo.foo a.foo.foo
> True
>
> But, if I replace the indicated line, python doesn't recognize anymore
> the instance and I receive:
> a.foo.foo foo.foo
> False
>
> Why? I don't understand how python see the instance. Or
> better, does it see only the path? The classes (and the instances) are
> the same!
>
> Thanks for all that help me to turn the light on...
>
> Michele
You are importing the same module twice, once as foo and once as a.foo.
To avoid importing a module that was already imported Python looks into the
module cache sys.modules. If the module is already there it uses the cached
version.
In your case the cache contains the module, but under the key "a.foo" which
Python cannot magically recognize as being the same as just "foo". Therefore
the code in the module is executed twice and you get two distinct versions
of every object in it.
Here is a simplified demo:
$ mkdir package
$ touch package/__init__.py
$ echo 'print "importing", __name__' > package/module.py
$ python
Python 2.6.4 (r264:75706, Dec 7 2009, 18:43:55)
[GCC 4.4.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path.append("package")
>>> from package import module
importing package.module
>>> import module
importing module
Conclusion: never allow a path in sys.path that leads into a package.
Also, never import the main script; again you'll get two versions of the
contents, this time filed in the cache under the script's filename and under
"__main__".
Peter
More information about the Python-list
mailing list