Why are imported packages visible inside other packages? - python

If I create a package named foo that imports bar, why is bar visible under foo as foo.bar when I import foo in another module? Is there a way to prevent this; to keep bar hidden so as not to clutter the namespace?

Import bar wherever you use it, rather than globally
If bar is being used in a function, import as
def func():
import bar
....
Or even,
if __name__ == '__main__':
import bar
my_main(bar)
Or if you love classes,
class Fubar():
def __init__(self):
import bar
self.bar = bar

Imports in Python are really just another form of name assignment. There is really no difference between an object that has been imported into foo and one that has been defined in foo - they are both visible internally and externally in exactly the same way. So no, there is no way to prevent this.
I don't really see how this is cluttering the namespace, though. You've still only imported one name, foo, into your other module.

TL;DR: Python Imports create named bindings for pieces of code so they can be referenced and used.
An import is essentially binding a piece of code to a name. So the namespace should always reflect what has been imported. If you hide that you may end up causing unexpected problems for someone else or yourself.
If you are importing the wrong modules, importing modules you don't use, or have a ton of imports because you have 10 classes in one file you should consider fixing the underlying issue(s). Not trying to hide it by messing with how modules are imported.

Related

package imports libraries without even intializing class

The doubt is the if import a class from a package inside another package like this :
from bar import foo
Does it initialize the class? and if the module has an import at the first line like :
import tensorflow
class foo:
def __init__(self):
# some things
Does it import the package even if we don't initialize the class from another file?
Does it initialize the class?
No, it just gives your program access to that class - ready to be instantiated to an object when you want to (then it will call the __init__ method).
Does it import the package even if we don't initialize the class from another file?
Yes. You can see this as if you were to just import bar, then you would be able to access the imported tensorflow module with bar.tensorflow, i.e. it is actually imported even if there is nothing else in the module.
In your specific case of just importing foo from bar, we can still access tensorflow via the inspect built-in package that will give us a reference to bar and thus .tensorflow from foo.
import inspect
from bar import foo
print(inspect.getmodule(foo).itertools) #<module 'itertools' (built-in)>
I'm not sure if there is an easier way to "get at" bar from foo without using inspect, but this is what I found for the purpose of explaining your case fully!

Importing in Python for multiple files

I am struggling to figure out how to handle importing dependencies that are used in multiple files.
Let's say I want to import an external API for example, and two classes depend on this import. Putting the import into the 'index' file, as an attempt to make it global does not work. I can import it in each class file fine, but that seems to be a violation of DRY, as well as setting myself up for failure later on.
So is there a way to import once, in a single file that is globally accessible? What I experimented with was creating an index.py, foo.py (for the foo class) and bar.py (for the bar class):
Index:
from example import API
import foo
import bar
foo()
bar()
foo.py:
class foo:
... (try to put the example API to use)
bar.py: (same as foo.py really, just here to make the case for using the same dependency in two different places)
This failed to work, as the classes appeared to not be able to access exampleAPI. What is the correct way to do this, or am I looking at it wrong? Thanks!
In general, you should import each module you need in each of your own modules that needs to use it. You don't need to worry about duplication, since each module has its own global namespace. Furthermore, modules are cached (in the sys.modules dictionary) so you don't need to worry about extra work being done to load the module multiple times.
That said, there can be some exceptions. For instance, if the specific source of an API is considered "private" information (e.g. because it's an implementation detail or because it might be configurable and not always come from the same place all the time), it might make sense to import it into some namespace where all other users will look for it.
On the other hand, your example suggests you may be splitting up your code more than you should. Unlike some other languages (such as Java), in Python it's neither required nor recommended for each class to live in its own file. Instead, you should divide your code up into modules dictated by how closely they interact with each other. Closely related classes should be part of the same module, while pieces that don't interact at all might make more sense in separate modules (especially if some other code might need one part but not the other). It may not be inappropriate for your whole program to be in a single module! Obviously, some of this is a matter of style and taste, so there's not a single best option for every programmer in every situation.
For your example code, if you want to keep separate modules, I'd suggest something like this:
index.py:
from foo import Foo # no need to import API here if you're not using it directly
from bar import Bar
foo = Foo() # create an instance of the foo class
result = foo.some_method() # call methods on it
bar = Bar(foo) # you can also pass your instances around to other classes
foo.py:
from example import API
class Foo:
def some_method(self):
return API.whatever() # use the API in some way
bar.py:
from example import API # don't worry about importing the API more than ocne
class Bar:
def __init__(self, foo):
self.foo = foo
def blah(self):
API.something_else(self.foo.some_method())
Note that I changed some names around. Python's convention is to use CapitalizedNames for classes, and lowercase_names_with_underscores (sometimes known as "snake case") for modules, variables and methods. Your original code seemed to have some confusion between the modules name foo and bar and the classes within them with the same names. Using different styles for the different names can help avoiding that confusion.

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.

Is it possible to detect way of import of a module in python?

Imagine you have module foo containing variable bar and thread baz that automagically updates bar:
from threading import Thread
import sys
bar = 0
class baz(Thread):
def run(self):
while True:
setattr(sys.modules[__name__], 'bar', getattr(sys.modules[__name__], 'bar')+1);
baz().start()
#Note: Globals is intentionally not used instead of getattr and setattr
Since this thread's updates won't be readable in __main__ (since ofcourse a copy is made in __main__ from the value in foo), would it be somehow possible to find out whether the module was imported with either from foo import * or import foo, and based on the result, change __name__ in setattr and getattr automatically to __main__? This topic's answer gives a way to detect it through code in __main__, but I want the module to detect it by itself. Is this somehow possible?
No. One reason is that a module can be imported many times, from many places. It could be imported with import foo in one place and from foo import * in another. Nothing will "happen" on the second import (the already-imported module in sys.modules will be used), so your module has no way of detecting it.

Does Python import instantiate a mystery class?

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.

Categories