Import module, that import another module. Python - python

I was curious what happens when we import a module that in turn imports another module. So I create two modules: module1 and module2.
module1:
import random
print(random.randint(0,10))
print("module1 work")
module2:
import module1
print("module2 work")
When I run module2 it give me this output:
1
module1 work
module2 work
So, I decided that I did indeed import random, when I imported module1. But when I type in the Shell print(random.randint(0,10))it throws a NameError: name 'random' is not defined. So random wasn't imported from module1. But in this case why did module2 print 1, and didn't throw the same error as the Shell?

Each module has its own scope (or namespace, if that terminology is more familiar to you). If you want to access random from module2, you need to import it in module2. The interpreter shares the scope of the module you execute, so only variables declared in the global namespace of that module will be accessible. If you want to access random from the interpreter having only imported module2, you'll need to specify module1.random.
Alternatively, you can replace import module1 with from module1 import *. That will copy over everything, including the reference to random. So random will be accessible globally.

It is because you are not actually importing random into the shell, instead just the file that contains the module.
We can use an existing module as an example, for example tkinter which opens with:
import enum
import sys
They import into the Tkinter module but when you import Tkinter they don't come with it.
To put it is as simply as possible your module1 has random imported, but imporing module1 will not also import random

Related

Form A import B and import A causes troubles

I have a following problem. I have this folder structure:
folder
├──script.py
├──utils.py
└──venv
I would like to import functions from utils.py into script.py. When I try this from utils import function_a, function_b everything works. But when I try import utils I got an error NameError: name 'function_a' is not defined.
Whats the difference between from utils import function_a, function_b and import utils in this case? And how can I fix it, please?
import module : Nice when you are using many bits from the module. Drawback is that you'll need to qualify each reference with the module name.
from module import ... : Nice that imported items are usable directly without module name prefix. The drawback is that you must list each thing you use, and that it's not clear in code where something came from.
If you are importing the module itself, then you have to specify what you want to use from the module with the . operator:
import utils
utils.function_a()
utils.function_b()

Import a module function and required dependencies for it

How do I import and run a Python function and have all the dependencies it uses use the imports from the main Python file?
Main Python file:
from im import er
import time
er()
Python file with function to be imported:
def er():
time.sleep(1)
print('hi')
This doesn't work because the time module is not imported in the im.py. How can I make this work without importing the modules it needs each time I run the function?
You have to import the function in the main, and required module for the function in the function file.
Main Python file:
from im import er
er()
Imported module :
from time import sleep
def er():
sleep(1)
print('hi')
This behave this way because Python run the imported module when you import it. Then, depending of your import statement, it will do:
import <module>: create a module object named <module> with attributes allowing you to access global scope of this module. If a function is in the global scope of the module, you access it with <module>.<function_name>.
from <module> import *: add to the global scope of the current module the global scope of the imported module (not exactly, but if you need more informations about it, look for wildcard import behaviour). As a good rule of thumb with this import: don't use this.
from <module> import <symbol>: add the symbol of the imported module to the global scope of the current module.
More info about imports:
https://stackoverflow.com/a/10501768/6251742
https://docs.python.org/3/reference/import.html

How to import modules that import other modules without using import *

Inside the parent class basehandler.py, there are several import statements, a constant, and a class:
import os
import sys
import cgi
import json
JINJA_ENVIRONMENT = jinja2.Environment(foobar)
class BaseHandler(webapp2.RequestHandler):
pass
Another module, main.py then imports this parent module with from basehandler import *
If we use from basehandler import BaseHandler or import basehandler so as to avoid the from foo import * statement, then the modules that the parent class imports are not received and the program throws an exception.
How do I avoid from foo import * while still correctly importing the parent module with the modules that it imports?
then the modules that the parent class imports are not received and the program throws an exception.
If your program uses a module then you should import it in the module itself, not in some other module e.g., use import os in your program instead of from foo import * where foo module imports os inside.
To answer the question in the title: to make all imported modules from another module available without a wild-card import:
import inspect
import foo # your other module
# get all modules from `foo` and make the names available
globals().update(inspect.getmembers(foo, inspect.ismodule)) #XXX don't do it
It is like from foo import * that imports only modules. The same warnings against wild-card imports are applicable here.
Referencing this answer, you can define a function in basehandler.py that yields all imported modules:
import os,sys,cgi,json
import types
def get_imports():
for name, val in globals().items():
if isinstance(val, types.ModuleType):
yield val.__name__
...and then import that function in main.py and use exec to import the relevant modules:
from basehandler import BaseHandler, get_imports
for i in get_imports():
exec "import %s" % i
print os.getcwd() #this will work
Sort of a gnarly way of doing it though, is there a specific reason you're not just re-importing the list of modules in main.py?
I say there is something else wrong there -
Importing your "basehandler" module from elsewhere should just work:
the names, modules, classes and objects it needs are bound to its own namespace,
and are present in the globals dictionary of any code defined in that module -
regardless of you getting it with a from basehandler import BaseHandler statement.
Please, post your full traceback so that people can find out what is actually happening there.

How to reload python module imported using `from module import *`

I saw in this useful Q&A that one can use reload(whatever_module) or, in Python 3, imp.reload(whatever_module).
My question is, what if I had said from whatever_module import * to import? Then I have no whatever_module to refer to when I use reload(). Are you guys gonna yell at me for throwing a whole module into the global namespace? :)
I agree with the "don't do this generally" consensus, but...
The correct answer is:
from importlib import reload
import X
reload(X)
from X import Y # or * for that matter
Never use import *; it destroys readability.
Also, be aware that reloading modules is almost never useful. You can't predict what state your program will end up in after reloading a module, so it's a great way to get incomprehensible, unreproduceable bugs.
A cleaner answer is a mix of Catskul's good answer and Ohad Cohen's use of sys.modules and direct redefinition:
import sys
Y = reload(sys.modules["X"]).Y # reload() returns the new module
In fact, doing import X creates a new symbol (X) that might be redefined in the code that follows, which is unnecessary (whereas sys is a common module, so this should not happen).
The interesting point here is that from X import Y does not add X to the namespace, but adds module X to the list of known modules (sys.modules), which allows the module to be reloaded (and its new contents accessed).
More generally, if multiple imported symbols need to be updated, it is then more convenient to import them like this:
import sys
reload(sys.modules["X"]) # No X symbol created!
from X import Y, Z, T
A
from module import *
takes all “exported” objects from module and binds them to module-level (or whatever-your-scope-was-level) names. You can reload the module as:
reload(sys.modules['module'])
but that won't do you any good: the whatever-your-scope-was-level names still point at the old objects.
I've found another way to deal with reloading a module when importing like:
from directory.module import my_func
It's nice to know how do modules are being imported generally.
The module is searched in sys.modules dictionary. If it already exists in sys.modules - the module will not be imported again.
So if we would like to reload our module, we can just remove it from sys.modules and import again:
import sys
from directory.module import my_func
my_func('spam')
# output: 'spam'
# here I have edited my_func in module.py
my_func('spam') # same result as above
#output: 'spam'
del sys.modules[my_func.__module__]
from directory.module import my_func
my_func('spam') # new result
#output: 'spam spam spam spam spam'
If You would like to get reloaded module when running whole script, you could use exception handler:
try:
del sys.modules[my_func.__module__]
except NameError as e:
print("""Can't remove module that haven't been imported.
Error: {}""".format(e))
from utils.module import my_func
..........
# code of the script here
When importing using from whatever_module import whatever, whatever is counted as part of the importing module, so to reload it - you should reload your module. But just reloading your module you will still get the old whatever - from the already-imported whatever_module, so you need to reload(whatever_module), and than reload your module:
# reload(whatever_module), if you imported it
reload(sys.modules['whatever_module'])
reload(sys.modules[__name__])
if you used from whatever_module import whatever you can also consider
whatever=reload(sys.modules['whatever_module']).whatever
or
whatever=reload(whatever_module).whatever
import re
for mod in sys.modules.values():
if re.search('name', str(mod)):
reload(mod)
for python 3.7 :
from importlib import reload #import function "reload"
import YourModule #import your any modules
reload(YourModule) #reload your module
Reload function can be called from your own function
def yourFunc():
reload(YourModule)

In Python, how can I access the namespace of the main module from an imported module?

Specifically, I need to get at some objects and globals from the main module in an imported module. I know how to find those things when the parent module wants some particular thing from a child module, but I can't figure out how to go in the other direction.
import __main__
But don't do this.
The answer you're looking for is:
import __main__
main_global1= __main__.global1
However, whenever a module module1 needs stuff from the __main__ module, then:
either the __main__ module should provide all necessary data as parameters to a module1 function/class,
or you should put everything that needs to be shared in another module, and import it as import module2 in both __main__ and module1.
I think this would work:
import sys
main_mod = sys.modules['__main__']
Not sure if it is a good practice but maybe you could pass the objects and variables you need as parameters to the methods or classes you call in the imported module.

Categories