Python - unexpected imports
I hope someone can provide some insight into some of the additional name bindings that Python3 creates during import. Here's a test case:
I created a test package called "spam" (original, I know). It contains 3 files as follows:
The content of the files looks like this:
...__ __ INIT ru:
from .foo import Foo
from .bar import Bar
foo.py:
def Foo():
pass
bar.py:
def Bar():
pass
Pretty simple stuff. When I import the "spam" package, I see that it creates name bindings to the Foo () and Bar () functions in the "spam" namespace, which are expected... It is also not expected to bind the name to the "foo" and "bar" modules in the "spam" namespace as shown below.
What's even more interesting is that these additional module name bindings do not occur if I import the Foo () and Bar () functions in main , as shown below:
Reading the documentation for the import statement (language abstract and tutorial), I don't see anything that could cause this.
Can anyone shed some light on why when importing a function from a module within a package, it also associates a name with the module containing the function?
source to share
Yes - that's right, and part of the Python import mechanism.
There is a lot going on when importing a module, but we can focus on a few:
1) Python checks if the module is loaded - this means that it checks if it is qualifying ban (name with dots) is under sys.modules
2) If not, it actually loads the module: it includes checking for pre-compiled cached bytecode files, parsing, compiling the .py file otherwise, etc.
3) It actually concatenates the names as they are in the command import
: "from .foo import Foo" creates a variable "Foo" in the current namespace that points to "spam.foo.Foo".
Suppose a module is always loaded as a whole and associated with it in the sys.modules dictionary. Also, the import process makes all submodules available in the module namespace visible in that package - this is what makes the names "foo" and "bar" visible in your spam package.
At the end of your file, __init__.py
you can remove the names "foo" and "bar", but that will break the way expected imports and uses of spam.foo work in fundamental ways - basically: sys.modules["spam.foo"]
will exist, but sys.modules["spam"].foo
wont - means that after one tries to do:
import spam.foo
spam.foo.Foo()
Python will give a name error on "foo".
The imported technique will report this as existing (it's in sys.modules), so it doesn't do anything. But "spam.foo" has been removed, so it cannot be reached.
source to share