I am a newbie to python. Below is my module
mymath.py
pi = 3.142
def circle(radius):
return pi * radius * radius
In terminal, I run it following way:
>>import mymath
>>mymath.pi
>>3.142
When I change pi to a local variable and reload(mymath) and do import mymath, still I get value of mymath.pi as 3.142. However the result of mymath.circle(radius) does reflect the change in result.
def circle(radius):
pi = 3
return pi * radius * radius
>>import imp
>>imp.reload(mymath)
>>import mymath
>>mymath.pi
>>3.142
>>circle(3)
>>27
Can anyone tell me what might be the issue?
From the docs for imp.reload():
When a module is reloaded, its dictionary (containing the module’s global variables) is retained. Redefinitions of names will override the old definitions, so this is generally not a problem. If the new version of a module does not define a name that was defined by the old version, the old definition remains.
So when you do imp.reload(mymath), even though pi no longer exists as a global name in the module's code the old definition remains as a part of the updated module.
If you really want to start from scratch, use the following method:
import sys
del sys.modules['mymath']
import mymath
For example:
>>> import os
>>> os.system("echo 'pi = 3.142' > mymath.py")
0
>>> import mymath
>>> mymath.pi
3.142
>>> os.system("echo 'pass' > mymath.py")
0
>>> import sys
>>> del sys.modules['mymath']
>>> import mymath
>>> mymath.pi
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'pi'
Related
I'm using python version 3.6.
mystuff.py includes:
mystuff = {'donut': "SHE LOVES DONUTS!"}
mystuffTest.py includes this
import mystuff
print (mystuff['donut'])
The error that I receive when I run mystuffTest.py is as follows:
$ python3.6 mystuffTrythis.py
Traceback (most recent call last):
File "mystuffTrythis.py", line 3, in <module>
print (mystuff['donut'])
TypeError: 'module' object is not subscriptable
So far I haven't seen this exact error here on stackoverflow. Can anyone explain why I am getting this error?
import mystuff is importing the module mystuff, not the variable mystuff. To access the variable you'd need to use:
import mystuff
print(mystuff.mystuff['donut'])
EDIT: It's also possible to import the variable directly, using:
from mystuff import mystuff
print(mystuff['donut'])
I got this error because a later from __ import * statement imported a module which bound my variable to something else:
from stuff_a import d
from stuff_b import *
d['key']
In stuff_b.py, d was bound to a module, hence the error. Lesson learned: avoid importing * from modules.
Today I wrote an "alias import function" for myself, because I need to write a script to do variable value checks for different python files.
# filename: zen_basic.py
import importlib
def from_module_import_alias(module_name, var_name, alias):
""" equal to from module import a as b """
agent = importlib.import_module(module_name)
globals()[alias] = vars(agent)[var_name]
The weird thing is, if I start a Python interactive shell, I can't import things by using this function. But by using its content outside of the function, it works.
>>> from zen_basic import *
>>> module_name = 'autor'
>>> var_name = 'food'
>>> alias = 'fd'
>>> from_module_import_alias(moduele_name, var_name, alias)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'moduele_name' is not defined
>>> from_module_import_alias(module_name, var_name, alias)
>>> fd
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'fd' is not defined
>>> agent = importlib.import_module(module_name)
>>> globals()[alias] = vars(agent)[var_name]
>>> fd
'cake'
>>>
I did 3 more experiments after:
Do python -i test.py
import zen_basic in interactive shell
call from_module_import_alias function, failed.
Do python -i zen_basic.py
call from_module_import_alias function, success.
add code which import zen_basic and call the from_module_import_alias function to test.py
Do python -i test.py, success
What's the reason that directly using from_module_import_alias function in a Python interactive shell failed?
You are updating the wrong globals. You are updating the globals of your zen_basic module, not the __main__ module (the namespace for your script or the interactive interpreter). The globals() function always returns the globals of the module in which the code was defined, not the module that called your function.
You'd have to retrieve the globals of the calling frame. Note that it rarely is advisable to modify the globals of the calling frame, but if you must then you can retrieve the calling frame by using the sys._getframe() function:
import sys
def from_module_import_alias(module_name, var_name, alias):
""" equal to from module import a as b """
agent = importlib.import_module(module_name)
calling_globals = sys._getframe(1).f_globals
calling_globals[alias] = vars(agent)[var_name]
In your experiments, python -i zen_basic.py runs zen_basic as the main script entry, and thus globals() references the __main__ module.
I have Python package called just "package". In it I have empty __init__.py and two modules. One is called m1.py and contains just one line:
x = 3
The other one is called m2.py and contains this line:
x = 5
Now I try to use that modules. First I do something like that:
from package.m1 import x
print package.m1.x
Of course it does not work - I get such error:
NameError: name 'package' is not defined
And I understand why it does not work. But then I do something like that:
from package.m1 import x
import package.m2
print package.m1.x
And now it does work. Why? How? I did not import package.m1!
I have only one explanation for this:
from package.m1 import x loads the modules package and package.m1. m1 is added to the package module but package is not added to your globals.
import package.m2 now adds the package module to your globals. Since m1 is already part of package it is now accessible via package.m1.
Further testing:
>>> from package import m1
>>> package.m1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'package' is not defined
>>> import package.m2
>>> package.m1
<module 'package.m1' from 'package/m1.py'>
>>> from package import m3
>>> package.m3
<module 'package.m3' from 'package/m3.py'>
Testing continued:
>>> import package.m1
>>> del package
>>> import package
>>> package.m1
<module 'package.m1' from 'package/m1.py'>
The from x import y syntax import the whole module and then reference the specified object in the current namespace. It can be translated as:
import x
y = x.y
So, you're actually importing package.m1
import v_framework as framework
framework.loadModules(["Maintenance"])
framework.Maintenance.showPage()
In framework I have:
def loadModules(aModules):
d_utility = {"Maintenance":"COOl_M_PAGE"}
for module in a_aModules:
exec("import " + d_utility[module] + " as " + module)
When loadModules is executed, it imports the modules in the v_framework namespace. Since I am importing v_framework as framework, I think I should be able to use the imported module using framework.Maintenance. But it does not work that way.
Is there a way to do way to do what I'm trying to do? Alternatively, is there any way to import modules in a namespace other than the one where exec is executed?
There are libraries for importing modules dynamically. You could use importlib (and another one that might be useful is pkgutil). Now, for your case, I guess this would do the job:
import importlib
mods = {}
def loadModules(aModule):
global mods
mods[module] = importlib.import_module(d_utility[module])
# or maybe globals()[module] = ... would work also (exactly as you expect it to
UPDATE: exec modifies the function's local namespace, not the global one (I think).
Hope it helps. :)
When you import inside a function, the module is imported/executed as normal, but the name you import under is local to the function, just like any other variable assigned inside a function.
>>> def test_import():
... import os
... print os
...
>>> test_import()
<module 'os' from '/usr/lib/python2.7/os.pyc'>
>>> os
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
os has been imported though, and you can still access it through sys.modules:
>>> import sys
>>> sys.modules['os']
<module 'os' from '/usr/lib/python2.7/os.pyc'>
>>> os = sys.modules['os']
>>> os
<module 'os' from '/usr/lib/python2.7/os.pyc'>
A quick and dirty way to do what you want would be something like this; exec takes an optional mapping to be used as the local and global variables. So you could do
def loadModules(aModules):
d_utility = {"Maintenance":"COOl_M_PAGE"}
for module in aModules:
exec ('import %s as %s' % (d_utility[module], module)) in globals()
Though this is ugly and probably has security implications or something. As jadkik94 mentions, there are libraries that provide cleaner ways to deal with this.
Assume the following code structure:
#### 1/hhh/__init__.py: empty
#### 1/hhh/foo/__init__.py:
from hhh.foo.baz import *
#### 1/hhh/foo/bar.py:
xyzzy = 4
#### 1/hhh/foo/baz.py:
import hhh.foo.bar as bar
qux = bar.xyzzy + 10
I run python inside 1/ and do import hhh.foo.baz. It fails:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "hhh/foo/__init__.py", line 1, in <module>
from hhh.foo.baz import *
File "hhh/foo/baz.py", line 1, in <module>
import hhh.foo.bar as bar
AttributeError: 'module' object has no attribute 'foo'
Now I replace baz.py with:
# 1/hhh/foo/baz.py:
from hhh.foo.bar import xyzzy
qux = xyzzy + 10
and again do import hhh.foo.baz. Now it works, although I’m loading the same module, only binding a different name.
Does this mean that the distinction between import module and from module import name goes beyond just identifiers? What exactly is going on here?
(I know I can use relative imports to work around all this, but still I’d like to understand the mechanics. Plus I don’t like relative imports, and neither does PEP 8.)
When you write from hhh.foo.bar import xyzzy Python interpreter will try to load xyzzy from module hhh.foo.bar. But if you write import hhh.foo.bar as bar it will try first to find bar in hhh.foo module. So it evaluates hhh.foo, doing from hhh.foo.baz import *
. hhh.foo.baz tries to evaluate hhh.foo, hhh.footries to evaluate hhh.foo.baz, cyclic imports, exception.
in 1/hhh/foo/__init__.py you need to set the __all__ list with the names of what you want to export. i.e. __all__ = ["xyzzy"]
Why do you import from hhh.foo.bar in hhh.foo? import bar should suffice there.