Does Python import instantiate a mystery class? - python

I thought about this for a while and can't think of a better title, sorry.
I'm new'ish to Python, and (like many other's it seems) I just can't get my head around import.
I think I understand 'modules' and 'packages', classes and attributes and all that. It's one specific behavior I need clarified.
Say I have a file, foo.py. It has one line it:
x = 1
If, in another file, I `import foo", I can reference x. And, wonderfully, in another file I can import foo and now those two files can share x. Leaving classes out of the discussion for simplicity, I believe this is the pythonic way to share attributes between files.
Here's the question: Is is fair to say, when I import foo, that foo.py itself is, (for lack of a better metaphor), secretly instantiated by the interpreter?
I realize if I define a class in a module, it follow traditional rules and only become instantiated if I explicitly do so. But, the python interpreter (via the import statement) instantiating an instance of my module in the global namespace is the only way to explain the attribute sharing behavior.
Is this true? Semi-true? Or am I wandering with the Sleestaks in the Land of the Lost?

When you import a module:
if the module has not been previously imported, the file is parsed in to a module object which is added to sys.modules with a key that is the import path from the pythonpath to your module
that module object (or some member thereof) is aliased in the importing namespace, the alias and object being referenced being determined by the specific form of import you used
So when you import foo, the interpreter checks sys.modules for something registered with the name foo. If it finds it, it provides a label foo in the local namespace for the foo module. If it doesn't, it searches down the pythonpath until it finds a foo module, parses that to a module object, adds that object to sys.modules, and adds a label in the local namespace for that module object.
import foo as foof does the same thing, only the local namespace label created is foof. from foo import x follows the same process up to the point of creating a label and reference in the local namespace, instead providing a label x in the namespace for the attribute x from the foo module. from foo import x as foox just combines the 2 ideas.
With classes, you can actually poke around this whole system by crawling up and down the tree using the __module__ attribute.

The import creates an instance of a "module" object. It is worth knowing that this is created only the first time the module is imported. The following times it is imported you are getting a reference to the original. You can create your own module objects on the fly with a bit of instrospection.
import glob # Import any python module
moduleType = type(glob)
onTheFly = moduleType("OnTheFly", "Docstring for this module")
Although there isn't much benefit to creating these.

Yes, indeed its true. If you execute import foo a module object foo is instatiated and the contents of your file e.g a class bar is added as a member of that object.

Related

Replace Python class definition at runtime

This question may sound similar to the following, but I'm not sure how to apply their solutions to my use-case:
How to import a module given the full path?
Can you use a string to instantiate a class?
I have a class Foo defined and imported in my project. However, at runtime I may have a string containing a different definition of Foo (along with lots of other classes and import statements). I'd like to be able to replace the already loaded Foo with the one in my string, in a way that after the operation, anybody who instantiates f = Foo() would instantiate the definition from my string. At the same time, I'd like to ignore any other definitions/imports in my string. How to do this?
Assume the following project structure and use-case:
project/
__init__.py
mytypes/
__init__.py
foo.py # contains the definition 'class Foo'
another_package/
bar.py
main.py
Inside main.py and bar.py I have from mytypes.foo import Foo. After the replace operation detailed above I want both to use the new definition of Foo from the replacement string, but no other definition from my string.
The short answer is: don't do this. You will run into all kinds of strange errors that you will not expect
You can use exec to run some arbitrary code, if you pass a dictionary as the second argument the resulting "globals" from the executed string will be stored in the dictionary
namespace = {}
exec('class Foo:\n x = 10', namespace)
namespace['Foo'] # This will be a class named Foo
You could then assign this to the module
import your_module
your_module.Foo = namespace['Foo']
Now anywhere that your_module.Foo is accessed you will get the class from your string.
However, your module may have been imported at some time before you have patched it, it's very difficult to be able to say for certain when your module will be imported. Someone may have bound Foo using from your_module import Foo, if this has run before your patch then you will not change this Foo class. Even if you only ever access your_module.Foo, if an instance has been initialised before your patch then any subsequent instances will not even have the same type!
f = your_module.Foo()
# run your patch
isinstance(f, your_module.Foo) # False
In the case above f is an instance of a completely different type to the current your_module.Foo

Does Python import copy all the code into the file

When we import a module in a Python script, does this copy all the required code into the script, or does it just let the script know where to find it?
What happens if we don't use the module then in the code, does it get optimized out somehow, like in C/C++?
None of those things are the case.
An import does two things. First, if the requested module has not previously been loaded, the import loads the module. This mostly boils down to creating a new global scope and executing the module's code in that scope to initialize the module. The new global scope is used as the module's attributes, as well as for global variable lookup for any code in the module.
Second, the import binds whatever names were requested. import whatever binds the whatever name to the whatever module object. import whatever.thing also binds the whatever name to the whatever module object. from whatever import somefunc looks up the somefunc attribute on the whatever module object and binds the somefunc name to whatever the attribute lookup finds.
Unused imports cannot be optimized out, because both the module loading and the name binding have effects that some other code might be relying on.

Python import module sharing name with a function in __init__.py

My tree looks like
parent/
|--__init__.py
\--a.py
And the content of __init__.py is
import parent.a as _a
a = 'some string'
When I open up a Python at the top level and import parent.a, I would get the string instead of module. For example import parent.a as the_a; type(the_a) == str.
So I think OK probably import is importing the name from the parent namespace, and it's now overridden. So I figure I can go import parent._a as a_module. But this doesn't work as there is "No module named _a".
This is very confusing. A function can override a module with the same name, but a module cannot take on a new name and "reexport".
Is there any explanation I'm not aware of? Or is this documented feature?
Even more confusing, if I remove the import statement in __init__.py, everything is back normal again (import parent.a; type(parent.a) is module). But why is this different? The a name in parent namespace is still a string.
(I ran on Python 3.5.3 and 2.7.13 with the same results)
In an import statement, the module reference never uses attribute lookups. The statements
import parent.a # as ...
and
from parent.a import ... # as ...
will always look for parent.a in the sys.modules namespace before trying to further initiate module loading from disk.
However, for from ... import name statements, Python does look at attributes of the resolved module to find name, before looking for submodules.
Module globals and the attributes on a module object are the same thing. On import, Python adds submodules as attributes (so globals) to the parent module, but you are free to overwrite those attributes, as you did in your code. However, when you then use an import with the parent.a module path, attributes do not come into play.
From the Submodules section of the Python import system reference documentation:
When a submodule is loaded using any mechanism [...] a binding is placed in the parent module’s namespace to the submodule object. For example, if package spam has a submodule foo, after importing spam.foo, spam will have an attribute foo which is bound to the submodule.
Your import parent.a as _a statement adds two names to the parent namespace; first a is added pointing to the parent.a submodule, and then _a is also set, pointing to the same object.
Your next line replaces the name a with a binding to the 'some string' object.
The Searching section of the same details how Python goes about finding a module when you import:
To begin the search, Python needs the fully qualified name of the module [...] being imported.
[...]
This name will be used in various phases of the import search, and it may be the dotted path to a submodule, e.g. foo.bar.baz. In this case, Python first tries to import foo, then foo.bar, and finally foo.bar.baz. If any of the intermediate imports fail, a ModuleNotFoundError is raised.
then further on
The first place checked during import search is sys.modules. This mapping serves as a cache of all modules that have been previously imported, including the intermediate paths. So if foo.bar.baz was previously imported, sys.modules will contain entries for foo, foo.bar, and foo.bar.baz. Each key will have as its value the corresponding module object.
During import, the module name is looked up in sys.modules and if present, the associated value is the module satisfying the import, and the process completes. [...] If the module name is missing, Python will continue searching for the module.
So when trying to import parent.a all that matters is that sys.modules['parent.a'] exists. sys.modules['parent'].a is not consulted.
Only from module import ... would ever look at attributes. From the import statement documentation:
The from form uses a slightly more complex process:
find the module specified in the from clause, loading and initializing it if necessary;
for each of the identifiers specified in the import clauses:
check if the imported module has an attribute by that name
if not, attempt to import a submodule with that name and then check the imported module again for that attribute
[...]
So from parent import _a would work, as would from parent import a, and you'd get the parent.a submodule and the 'some string' object, respectively.
Note that sys.modules is writable, if you must have import parent._a work, you can always just alter sys.modules directly:
sys.modules['parent._a'] = sys.modules['parent.a'] # make parent._a an alias for parent.a
import parent._a # works now
I think I have a coherent understanding of this problem now, just documenting my findings in case others run into this.
What Martijn said above is mostly true, expanding on that answer, import parent.a as _a is a two step process. The first step is module lookup of parent.a, which never goes through attribute lookup, and then it does a binding onto sys.modules, and then an attribute binding of the module to attribute a in parent. In fact this is all you get if you only use import parent.a. This part is described thoroughly by the previous answer.
The second part as _a does an attribute lookup of parent.a, and binds it onto the name _a. So to answer my original question, now if I go outside and start an interactive Python interpreter, now parent.a has been overwritten to the string in __init__.py, and import parent.a as the_a; the_a would get me the string. In fact, this is the same as import parent.a; parent.a. Both the_a and parent.a are the results of attribute lookup. I could still get the submodule by parent._a or sys.modules["parent.a"].
To answer my follow up question:
Even more confusing, if I remove the import statement in __init__.py, everything is back normal again (import parent.a; type(parent.a) is module). But why is this different? The a name in parent namespace is still a string.
This is when I import parent.a in the outside interactive Python interpreter, it first evaluates __init__.py, which does the overwriting of parent.a to a string. But the import hasn't finished yet, it goes on importing the submodule parent.a, and since we are still in the importing part, we don't do attribute lookups, and so we find the correct submodule. When all this is done, it binds the submodule to a of parent, thus overwriting the string that was overwriting the submodule, and making it all correct again.
This sounds very confusing, but remember (https://docs.python.org/3/reference/import.html#submodules):
When a submodule is loaded using any mechanism (e.g. importlib APIs, the import or import-from statements, or built-in __import__()) a binding is placed in the parent module’s namespace to the submodule object. For example, if package spam has a submodule foo, after importing spam.foo, spam will have an attribute foo which is bound to the submodule. Let’s say you have the following directory structure:
An import parent.a first runs all the module set-up code, and then binds the name.

Importing classes/functions with same name as module

Say I use a python package with the following structure:
package/
bar.py
foo.py
__init__.py
bar.py contains the class bar and foo.py contains the function foo.
When I want to import the function/class do I have to write
from package.bar import bar
from package.foo import foo
or can I write
from package import bar
from package import foo
More generally asked:
Can I always omit the class/function name, when I import a module with the same name as the class/function?
No, you can't omit the module or object name. There is no mechanism that'll implicitly do such imports.
From the Zen of Python:
Explicit is better than implicit.
Note that importing the module itself should always be a valid option too. If from package import bar imported the package.bar.bar object instead, then you'd have to go out of your way to get access to package.bar module itself.
Moreover, such implicit behaviour (auto-importing the object contained in a module rather than the module itself) leads to confusing inconsistencies.
What does import package.bar add to your namespace? Would referencing package.bar be the module or the contained object?
What should happen to code importing such a name, when you rename the contained object? Does from package import bar then give you the module instead? Some operations will still succeed, leading to weird, hard to debug errors, instead of a clear ImportError exception.
Generally speaking, Python modules rarely contain just one thing. Python is not Java, modules consist of closely related groups of objects, not just one class or function.
Now, there is an inherent namespace collision in packages; from package import foo can refer both to names set on the package module, or to a nested module name. Python will first look at the package namespace in that case.
This means you can make an explicit decision to provide the foo and bar objects at the package level, in package/__init__.py:
# in package/__init__.py
from .foo import foo
from .bar import bar
Now from package import foo and from package import bar will give you those objects, masking the nested modules.
The general mechanism of importing objects from submodules into the package namespace is a common method of composing your public API whilst still using internal modules to group your code logically. For example, the json.JSONDecodeError exception in the Python standard library is defined in the json.exceptions module, then imported into json/__init__.py. I generally would discourage masking submodules however; but foo and bar into a module with a different name.

Masquerading real module of a class

Suppose you have the following layout for a python package
./a
./a/__init__.py
./a/_b.py
inside __init__.py you have
from _b import *
and inside _b.py you have
class B(object): pass
If you import from interactive prompt
>>> import a
>>> a.B
<class 'a._b.B'>
>>>
How can I completely hide the existence of _b ?
The problem I am trying to solve is the following: I want a facade package importing "hidden" modules and classes. The classes available from the facade (in my case a) are kept stable and guaranteed for the future. I want, however, freedom to relocate classes "under the hood", hence the hidden modules. This is all nice, but if some client code pickles an object provided by the facade, this pickled data will refer to the hidden module nesting, not to the facade nesting. In other words, if I reposition the B class in a module _c.py, client codes will not be able to unpickle because the pickled classes are referring to a._b.B, which has been moved. If they referred to a.B, I could relocate the B class as much as I want under the hood, without ruining pickled data.
try:
B.__module__= 'a'
Incidentally you probably want an absolute import:
from a._b import *
as relative imports without the new explicit dot syntax are going away (see PEP 328).
ETA re comment:
I would have to set the module explicitly for every class
Yes, I don't think there's a way around that but you could at least automate it, at the end of __init__:
for value in globals().values():
if inspect.isclass(value) and value.__module__.startswith('a.'):
value.__module__= 'a'
(For new-style classes only you could get away with isinstance(value, type) instead of inspect. If the module doesn't have to run as __main__ you could use __name__ instead of hard-coding 'a'.)
You could set the __module__ variable for Class B
class B(object): pass
B.__module__ = 'a'
For classes, functions, and methods, this attribute contains the name of the module in which the object was defined.
Or define it once in your __init__.py:
from a._b import B # change this line, when required, e.g. from a._c import B
B.__module__ = 'a'

Categories