Why do these two Python imports work differently? - python

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.

Related

Using python function from other python file and subsequent class?

I have been learning working with classes in python after learning OOPs in c++.
I am working on a project, where I have a class defined in one file, and an important function to be used in the class in the seperate file.
I have to call the class in the first file, but I am getting the ImportError.
Great, if you could help.
try1.py
from try2 import prnt
class a:
def __init__(self):
print("started")
def func1(self):
print("func1")
prnt()
try2.py
from try1 import a
b = a()
b.func1()
def prnt():
b.func()
As for eg, in the above example, when I am running try1.py, I am getting an ImportError: cannot import name 'prnt'.
You absolutely need to redesign your project. Even if you did manage to get away with the cyclic imports (ie by moving the import to inside the function - but don't do it) you will still get a NameError: name 'b' is not defined since b is not define in prnt.
Unless prnt can't be defined in class a (why?), consider defining prnt in a third, "utils" file and import it in both try1.py and try2.py and pass an object to it so it can access all of its attributes.
Just run your code, read the error, and deduct something from it.
When you run it, here is the error message :
Traceback (most recent call last):
File "C:\Users\Kilian\Desktop\Code\Garbage\tmp.py", line 7, in <module>
from temp2 import prnt
File "C:\Users\Kilian\Desktop\Code\Garbage\temp2.py", line 1, in <module>
from tmp import a
File "C:\Users\Kilian\Desktop\Code\Garbage\tmp.py", line 7, in <module>
from temp2 import prnt
ImportError: cannot import name prnt
Your script is trying to import something it already has tried to import earlier on. Python is probably deducing that it can't import it. :)

How to import a module from sub directory

I failed to import a module from sub directory in python. Below is my project structure.
./main.py
./sub
./sub/__init__.py
./sub/aname.py
when I run python main.py, I got this error:
Traceback (most recent call last):
File "main.py", line 4, in <module>
import sub.aname
File "/Users/dev/python/demo/sub/__init__.py", line 1, in <module>
from aname import print_func
ModuleNotFoundError: No module named 'aname'
I don't know it failed to load the module aname. Below is the source code:
main.py:
#!/usr/bin/python
import sub.aname
print_func('zz')
sub/__init__.py:
from aname import print_func
sub/aname.py:
def print_func( par ):
print ("Hello : ", par)
return
I am using python 3.6.0 on MacOS
There are several mistakes in your Python scripts.
Relative import
First, to do relative import, you must use a leading dots (see Guido's Decision about Relative Imports syntax).
In sub/__init__.py, replace:
from aname import print_func
with:
from .aname import print_func
Importing a function
To import a function from a given module you can use the from ... import ... statement.
In main.py, replace:
import sub.aname
with:
from sub import print_func
from sub import aname
aname.print_func('zz')
Probably the most elegant solution is to use relative imports in your submodule sub:
sub.__init__.py
from .aname import print_func
But you also need to import the print_func in main.py otherwise you'll get a NameError when you try to execute print_func:
main.py
from sub import print_func # or: from sub.aname import print_func
print_func('zz')

How do I import symbols inside a Python package?

I have three database-related classes that I want to combine into a package, in the following structure:
adodb_pyodbc /
__init__.py # empty
PyConnection.py
PyRecordset.py
PyField.py
This package is in my Lib/site-packages folder.
In an earlier iteration of this attempt, I did not use the "Py" prefix, and I got an error complaining that module.__init__() takes only two arguments, and three were being passed into it. Someone suggested that the name "Recordset" might be conflicting with something else, so I changed it.
The classes work when the files are in the same folder as the project that is using them. In that case, I can just use:
PyRecordset.py:
from PyConnection import PyConnection
from PyField import PyField
class PyRecordset: pass
DerivedSet.py
from PyRecordset import PyRecordset
class DerivedRecordset(PyRecordset): pass
But the same files don't work when they are located inside a package. My test program begins with this line:
from adodb_pyodbc import PyConnection as Connection
And when I run it I get this error message:
C:\Python35\python.exe "C:/Customers/Nucor Crawfordsville/Scripts/64 bit/Testing/cpsa_simulator.py"
Traceback (most recent call last):
File "C:/Customers/Nucor Crawfordsville/Scripts/64 bit/Testing/cpsa_simulator.py", line 8, in <module>
from Level3_CoilsSet import Level3_CoilsSet
File "C:\Customers\Nucor Crawfordsville\Scripts\64 bit\Testing\Level3_CoilsSet.py", line 1, in <module>
from adodb_pyodbc import PyRecordset as Recordset
File "C:\Python35\lib\site-packages\adodb_pyodbc\PyRecordset.py", line 9, in <module>
from PyConnection import PyConnection
ImportError: No module named 'PyConnection'
But when editing PyRecordset.py inside PyCharm, it appears to be able to find the PyConnection.py file.
I tried using relative addressing inside PyConnection.py:
from . import PyConnection
from . import PyField
But that puts me back to the __init__() error:
C:\Python35\python.exe "C:/Customers/Nucor Crawfordsville/Scripts/64 bit/Testing/cpsa_simulator.py"
Traceback (most recent call last):
File "C:/Customers/Nucor Crawfordsville/Scripts/64 bit/Testing/cpsa_simulator.py", line 8, in <module>
from Level3_CoilsSet import Level3_CoilsSet
File "C:\Customers\Nucor Crawfordsville\Scripts\64 bit\Testing\Level3_CoilsSet.py", line 3, in <module>
class Level3_CoilsSet(Recordset):
TypeError: module.__init__() takes at most 2 arguments (3 given)
How am I supposed to do this?
Thanks very much for your help. In the meantime, I'm going to take those files out of the package and put them back in my test project. I've wasted far too much time on this question.
When you one to use PyConnection from outside of the package you have to either import it from the module where it was defined:
from adodb_pyodbc.PyConnection import PyConnection as Connection
Or, more conveniently, import it in the package init file adodb_pyodbc/__init__.py:
from .PyConnection import PyConnection
And then, from the outside, you can just do:
from adodb_pyodbc import PyConnection as Connection

strange behaviour while importing modules

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

Python Wildcard Import Vs Named Import

Ok, I have some rather odd behavior in one of my Projects and I'm hoping someone can tell me why. My file structure looks like this:
MainApp.py
res/
__init__.py
elements/
__init__.py
MainFrame.py
Inside of MainFrame.py I've defined a class named RPMWindow which extends wx.Frame.
In MainApp.py this works:
from res.elements.MainFrame import *
And this does not:
from res.elements.MainFrame import RPMWindow
I realize that the wild card import won't hurt anything, but I'm more interested in understanding why the named import is failing when the wild card succeeds.
When using the class name I get this traceback:
Traceback (most recent call last):
File "C:\myApps\eclipse\plugins\org.python.pydev.debug_1.5.6.2010033101\pysrc\pydevd.py", line 953, in <module>
debugger.run(setup['file'], None, None)
File "C:\myApps\eclipse\plugins\org.python.pydev.debug_1.5.6.2010033101\pysrc\pydevd.py", line 780, in run
execfile(file, globals, locals) #execute the script
File "C:\Documents and Settings\Daniel\workspace\RPM UI - V2\src\MainApp.py", line 2, in <module>
from res.elements.MainFrame import RPMWindow
File "C:\Documents and Settings\Daniel\workspace\RPM UI - V2\src\res\elements\MainFrame.py", line 2, in <module>
from res.elements.MenuBar import MenuBarBuilder
File "C:\Documents and Settings\Daniel\workspace\RPM UI - V2\src\res\elements\MenuBar.py", line 2, in <module>
from MainApp import _, DataCache
File "C:\Documents and Settings\Daniel\workspace\RPM UI - V2\src\MainApp.py", line 2, in <module>
from res.elements.MainFrame import RPMWindow
ImportError: cannot import name RPMWindow
When using the wild card import I don't receive a traceback and my application opens.
You have circular imports:
MainFrame.py is indirectly importing MainApp.py, and MainApp.py is importing MainFrame.py. As a result, when MainApp.py is importing MainFrame.py, the RPMWindow class hasn't been defined yet and you get the ImportError.
i don't have time to look into why the wildcard is working for you, but what i can say about your failure with the direct name import is that you have an import cycle in your code:
you are trying to import res.elements.MainFrame, but part of that code is trying to import res.elements.MenuBar which tries to import res.elements.MainFrame again. IOW, your first attempt to import res.elements.MainFrame has not completed yet before you try it again.
You have circular imports in your code: the same module is both required by and requires the use of a certain other module, which when you think of it like that, it clearly precarious. Most of the problems can be cleared up by using import a and later referring to a.b instead of from a import b or from a import *.
In particular, never use from a import *. Wildcard imports clutter your namespace and makes your code less maintainable, readable, sane, and predictable. The difference between import a and from a import * is the difference between dragging a box into a room and pouring its contents all over the floor.
It would be better if you could move shared code off to its own module or somehow refactor out the need for a circular import. Circular imports always indicate a design problem.

Categories

Resources