I have the following project and module setup:
class2.py:
from mod1.class1 import Class1
class Class2(object):
def __init__(self, c1: Class1):
self.c1 = c1
class2.py:
from mod2.class2 import Class2
class Class1(object):
def __init__(self):
self.c2 = Class2(self)
main.py:
from mod1.class1 import Class1
from mod2.class2 import Class2
c1 = Class1()
c2 = Class2(c1)
The idea is that when a parent class initializing a child class, it introduces itself to the child class. This way the child class can call parent class methods.
This pattern works fine in strongly typed languages like C#.
When I run main.py, I get the following error:
Traceback (most recent call last):
File "C:\Projects.Personal\exp02\main.py", line 2, in <module>
from mod2.class2 import Class2
File "C:\Projects.Personal\exp02\mod2\class2.py", line 2, in <module>
from mod1.class1 import Class1
File "C:\Projects.Personal\exp02\mod1\class1.py", line 1, in <module>
from mod2.class2 import Class2
ImportError: cannot import name 'Class2' from partially initialized module 'mod2.class2' (most likely due to a circular import) (C:\Projects.Personal\exp02\mod2\class2.py)
Process finished with exit code 1
I just need to let Class2 know about the type of Class1.
Why am I getting such error?
What is the proper pattern to do this in Python?
Update #1
I understand that this is a circular import as it is specifically stated in the error message.
The idea explained in this article (https://stackabuse.com/python-circular-imports/) is not applicable here. Here I have Classes not module functions. I just need to annotate a variable. My code sample is very much simplified. The actual classes code is large. I don't want to combine them in one file.
IMO, This is a valid pattern and I can do it in Java or C#.
How can I implement the idea in Python?
Update #2: TYPE_CHECKING did not work
Per #RedKnite, I updated the class2.py to the following code:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from mod2.class2 import Class2
class Class1(object):
def __init__(self):
self.c2 = Class2(self)
I am getting the the following error:
Traceback (most recent call last):
File "C:\Projects.Personal\exp02\main.py", line 6, in <module>
c1 = Class1()
File "C:\Projects.Personal\exp02\mod1\class1.py", line 8, in __init__
self.c2 = Class2(self)
NameError: name 'Class2' is not defined. Did you mean: 'Class1'?
Use the TYPE_CHECKING flag from typing and make the class a string.
At runtime TYPE_CHECKING is False so the import will not execute, but a type checker should find this acceptable.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from mod1.class1 import Class1
class Class2(object):
def __init__(self, c1: "Class1"):
self.c1 = c1
You have a circular import. Your Class1 and Class2 files are attempting to import each other- i'd suggest using one file that imports both classes.
Related
EDIT: Turns out the inheritance is circular. Read on!
I am using Python 3.6. I tried to produce a minimal code sample to debug an import error I was having in a code project which was caused by the way I have set up inheritance. I suspect that I have done something wrong, but I don't understand what principle of coding I have violated.
The file structure looks like this:
temp
|-- __init__.py
|-- superclass_file.py
|-- subclass_file.py
|-- tests
|-- __init__.py
|-- test_subclass_file.py
These are the contents of the Python scripts:
# temp/__init__.py
from .subclass_file import *
from .superclass_file import *
# temp/superclass_file.py
class Parent:
def __init__(self):
print('I exist.')
# temp/subclass_file.py
from temp import Parent
class Child(Parent):
def __init__(self):
super().__init__()
print('And I exist because of it.')
def print_something(self):
print('Yes, I\'m here.')
if __name__ == '__main__':
Child()
# temp/tests/__init__.py
from .test_subclass_file import *
# temp/tests/test_subclass_file.py
from unittest import TestCase
from temp import Child
class TestChild(TestCase):
def check_inheritance(self):
c = Child()
c.print_something()
When I run check_inheritance(), it fails and throws this error:
/usr/local/bin/python3.6 ~/temp/subclass_file.py
Traceback (most recent call last):
File "~/temp/subclass_file.py", line 1, in <module>
from temp import Parent
File "~/temp/__init__.py", line 1, in <module>
from .subclass_file import *
File "~/temp/subclass_file.py", line 1, in <module>
from temp import Parent
ImportError: cannot import name 'Parent'
I obtain a similar error when I run the main() method in subclass_file.py.
However, the error disappears completely when I change the import of Parent in subclass_file.py from from temp import Parent to from temp.superclass_file import Parent.
Why does this happen? Why can't I use the same import signature I would use anywhere else—from temp import Parent—in the case of inheritance? Have I configured the __init__.py file incorrectly?
Right now you are importing subclass_file.py before superclass_file.py.
So when you try to do from temp import Parent, because subclass_file.py was imported before, it doesn't know what Parent is. Furthermore, you may create a circular import issue.
The best way should be to use from temp.superclass_file import Parent
If you really want / need to use the other way, then you must import superclass_file.py before subclass_file.py
I'm new to python, but skilled on java. Now I'm facing a annoying question when training on python3.5, I have such a src structure:
/project-root
--main.py
--ModelImpl.py #subclass of BaseModel
--ActionImpl.py #subclass of BaseAction
--/base
----BaseModel.py #base class of all
----BaseAction.py #subclass of BaseModel
----modulescript.py
in main.py:
from ModelImpl import ModelImpl
from ActionImpl import ActionImpl
modelImpl = ModelImpl()
actionImpl = ActionImpl()
in modulescript.py:
from BaseAction import BaseAction
baseAction = BaseAction()
in BaseModel.py:
class BaseModel:
def __init__(self):
print("BaseModel")
in BaseAction.py:
from .BaseModel import BaseModel
class BaseAction(BaseModel):
def __init__(self):
super().__init__()
print("BaseAction")
in ModelImpl.py:
from base.BaseModel import BaseModel
class ModelImpl(BaseModel):
def __init__(self):
super().__init__()
print("ModelImpl")
in ActionImpl.py:
from base.BaseAction import BaseAction
class ActionImpl(BaseAction):
def __init__(self):
super().__init__()
print("ActionImpl")
Now when I input python3 main.py in terminal, I got printed result:
BaseModel
ModelImpl
BaseModel
BaseAction
ActionImpl
but if I input python3 module function.py, I got error:
Traceback (most recent call last):
File "modulescript.py", line 1, in (module) from BaseAction import BaseAction
File "/home/jerry/projects/test/python/base/BaseAction.py", line 1, in (module) from .BaseModel import BaseModel SystemError: Parent module '' not loaded, cannot perform relative import
I found that It's cause by import statement in BaseAction.py:
from .BaseModel import BaseModel
If I change to from BaseModel import BaseModel, the modulescript.py runs ok, but the main.py will got a error:
File "main.py", line 225, in (module) from ActionImpl import ActionImpl
File "/home/jerry/projects/test/python/ActionImpl.py", line 1, in (module) from base.BaseAction import BaseAction
File "/home/jerry/projects/test/python/base/BaseAction.py", line 1, in (module) from BaseModel import BaseModel
ImportError: No module named 'BaseModel'
Oops. annoying!
In java, you can import any Class from any where if you provide the right path of the class like import com.domain.MyClass;
so, what's the right way to import in python?
This is Python, not Java, you group modules related to eachother in a single package, which is a folder.
To be able to import from a package, you must do a few things first.
Create __init__.py in your package to let interpreter know that it's a package. If there's no such file in a folder, it won't even budge whether you want to import from there or not, it's not a package to it and that's all.
Additionally, if you want (and you should when you're creating a package for others to use) import classes functions and etc in your __init__.py to allow to import them from the package itself directly.
I made a simple example:
project tree:
/root
test.py
/examplepkg
__init__.py
somemodule.py
EDIT: if you want examplepkg to have a "nested" package, as in, package it depends on in some way, you create another folder, and put another __init__.py in it and do the same thing, then in __init__.py of examplepkg you can further "export" it for the top level modules to see. How you do it is up to you, just be consistent.
somemodule.py:
class SomeClass:
def __init__(self):
print("New Instance of SomeClass!")
__init__.py:
from .somemodule import SomeClass # you could see it as exporting
test.py:
from examplepkg import SomeClass
SomeClass()
For more information, read this.
I got the same error but the error got fixed when I changed
from .BaseModel import BaseModel
to
from base.BaseModel import BaseModel
I'm writing a python package (python 3.6) and have the following directory structure:
package/
| __init__.py
| fileA.py
| fileB.py
| tests/
| | __init__.py
| | test_classA.py
| | test_classB.py
Setup
My files have the following contents:
# package/fileA.py
from package import ClassB
def ClassA:
def __init__(self):
self.my_ClassB = ClassB()
-
# package/fileB.py
def ClassB:
def __init__(self):
self.foo = "bar"
-
# package/tests/test_classB.py
from package import ClassB
# <performs some unit tests here>
-
# package/tests/test_classA.py
from package import ClassA
# <performs some unit tests here>
-
# package/__init__.py
from .fileA import ClassA
from .fileB import ClassB
Circular importing
When I ran python test_classB.py, I get the following traceback error showing that I have circular import statements, which are not allowed by python. Note - the package is not literally called package and I have edited the Traceback to match the toy example above.
Traceback (most recent call last):
File "package/tests/test_classB.py", line 2, in <module>
from package import ClassB
File "/anaconda/lib/python3.5/site-packages/package/__init__.py", line 2, in <module>
from .fileA import ClassA
File "/anaconda/lib/python3.5/site-packages/package/merparse.py", line 2, in <module>
from package import ClassB
ImportError: cannot import name 'ClassB'
Correcting the error
However, when I remove those two lines in my package/__init__.py file:
# package/__init__.py
from .fileA import ClassA
from .fileB import ClassB
...and I change the import method for package/fileA.py:
# package/fileA.py
from package.fileB import ClassB
def ClassA:
def __init__(self):
self.my_ClassB = ClassB()
... package/tests/test_classB.py runs correctly.
My Question
My question is: How can I keep the one file: one class structure in my files and import with from package import ClassA instead of having to import with from package.fileA import ClassA?
In my package I would like to import classes from other files, but don't know how to get around circular importing.
Edit: Solution
Thanks to #mirandak and #martin-kalcok below for their help.
The only file that I had to edit was fileA.py to not refer to the package name in the import statement.
# package/fileA.py
from .fileB import ClassB
def ClassA:
def __init__(self):
self.my_ClassB = ClassB()
The package/__init__.py file still contains import statements in case I want to import the package from other scripts in the future that I don't couple with the package.
# package/__init__.py
from .fileA import ClassA
from .fileB import ClassB
The problem is with package/fileA.py. It's both a part of package and calling the __init__.py file of package as it's imported - creating a circular dependency.
Can you change fileA.py to look like this?
# package/fileA.py
from .fileB import ClassB
def ClassA:
def __init__(self):
self.my_ClassB = ClassB()
First of all, renaming your package to literary "package" really confuses this whole situation, but here's my take on it :D.
I don't think you are dealing with circular dependency, python just states that it cannot import classB from package and that is because there is no file named classB in package directory. Changing import statement to
from package.fileB import ClassB
works because there is directory package which contains file fileB which contains object ClassB.
To answer your question whether you can import classes with statement
from package import ClassB
you can't, unless your package is file and classB is object inside this file. However i don't see how this different import statement would be a dealbraker
Side Note: Your objects ClassB and ClassA are not classes, they are functions. Python uses keyword class to create classes and def to define functions.
Side note 2: Are you sure your __init__.py file needs to hold any code at all?
Personal Note: I know that keeping 1 File / 1 Class structure is matter of personal preferences, it is not required in python and I myself find it much more comfortable to group multiple related classes and functions into one file
I have a class JCheq, with a static var named 'logger'.
JCheq imports module printing_systems, but I need to use JCheq.logger from printing_systems.
My code does not compile after I put import JCheq in printing_systems.py.
jcheq.py
from printing_systems import printing_systems
from logger import logger
class JCheq:
logger = logger.Logger('logs/jcheq.log', loglevel=logger.Logger.INFO)
def __init__(self):
pass
...
printing_systems/printing_systems.py
from jcheq import JCheq
class WinLPR:
def __init__(self):
pass
#staticmethod
def send(spool, params):
temp_dir = tempfile.mkdtemp()
try:
JCheq.logger.log('Creando archivo temporal en dir: ' + temp_dir, logger.Logger.TRACE)
Error trace:
Traceback (most recent call last):
File "/home/jsivil/Desktop/Proyectos/UNPAZ/jcheq/jcheq/jcheq.py", line 12, in <module>
from printing_systems import printing_systems
File "/home/jsivil/Desktop/Proyectos/UNPAZ/jcheq/jcheq/printing_systems/printing_systems.py", line 7, in <module>
from jcheq import JCheq
File "/home/jsivil/Desktop/Proyectos/UNPAZ/jcheq/jcheq/jcheq.py", line 12, in <module>
from printing_systems import printing_systems
ImportError: cannot import name 'printing_systems'
Moving the import statement in the function is commonly used to solve circular imports. It is handy in cases when restructuring your application would be too costly (if useful at all).
Another solution would be to move JCheq.logger into its own module that both jcheq.py and printing_systems/printing_systems.py would import.
Or, you could make logger.Logger a factory function backed by some registry (or simply memoize it) so that it returns the same logger when the same arguments are given. This way, printing_system.py would simple import logger instead of importing jcheq.
I've run into some behavior from Python 2.6.1 that I didn't expect. Here is some trivial code to reproduce the problem:
---- ControlPointValue.py ------
class ControlPointValue:
def __init__(self):
pass
---- ControlPointValueSet.py ----
import ControlPointValue
---- main.py --------------------
from ControlPointValue import *
from ControlPointValueSet import *
val = ControlPointValue()
.... here is the error I get when I run main.py (under OS/X Snow Leopard, if it matters):
jeremy-friesners-mac-pro-3:~ jaf$ python main.py
Traceback (most recent call last):
File "main.py", line 4, in <module>
val = ControlPointValue()
TypeError: 'module' object is not callable
Can someone explain what is going on here? Is Python getting confused because the class name is the same as the file name? If so, what is the best way to fix the problem? (I'd prefer to have my python files named after the classes that are defined in them)
Thanks,
Jeremy
I don't think it's unexpected. What you are basically doing is:
1) the first import in main.py imports the contents of ControlPointValue module into the global namespace. this produces a class bound to that name.
2) the second import in main.py imports the contents of ControlPointValueSet module into the global namespace. This module imports ControlPointValue module. This overwrites the binding in the global namespace, replacing the binding for that name from the class to the module.
To solve, I would suggest you not to import *, ever. Always keep the last module prefix. For example, if you have foo/bar/baz/bruf.py containing a class Frobniz, do
from foo.bar.baz import bruf
and then use bruf.Frobniz()
In addition to the other suggestions about star imports, don't name your module and your class the same. Follow pep8's suggestions and give your modules short all lower case names and name your classes LikeThis. E.g.
---- controlpoints.py ------
class ControlPointValue:
def __init__(self):
pass
---- valuesets.py ----
from controlpoints import ControlPointValue
---- main.py --------------------
from controlpoints import ControlPointValue
from valuesets import *
val = ControlPointValue()