I am not sure if the title was clear (I am a bit new here), so let me elaborate... Imagine I have the following simple project structure:
test/
|-- __init__.py
|-- windows.py
|-- elements.py
|-- test.py
windows.py is as follows:
from elements import Container
class WindowTypes:
TYPE_1 = 1
TYPE_2 = 2
class Window:
def __init__(self):
self.container1 = Container(WindowTypes.TYPE_1)
On the other hand, elements.py:
from windows import WindowTypes
class Container:
def __init__(self, win_type):
if win_type is WindowTypes.TYPE_1:
print('Loading stuff specific for windows of type 1')
else:
print('Doing something else')
If in test.py I make an instance of the Window class:
from windows import Window
Window()
I am aware that I will run into a circular import error. However I need a descriptive variable to describe the types of objects I can create from the Window class. How is this situation treated in Python?
PD: For this case I can create another file to hold the types, but my project is much larger than the represented, is it still good?
There are two ways I can think to deal with this:
Instead of importing specific names from a module with from ... import ..., just import the module itself. For example, in windows.py, instead of writing
from elements import Container
just write
import elements
and then when you want to create a Container, do it like this:
self.container1 = elements.Container(WindowTypes.TYPE_1)
The advantage of this approach is that you don't actually force the elements module to have anything in it named Container at the time the module is imported, and that way you solve your circular import problem.
I won't get too far into the details of why this works (unless you're interested, I can edit), but the gist is that the first step in the import process involves marking the module as already being imported, so that any further import statements referring to the same module won't result in loading the file all over again. So if you import A which imports B which imports A again, the second time that import A is encountered, it doesn't do anything and doesn't continue the loop. You can take advantage of this to allow what would otherwise be circular imports in many cases, though there are times it doesn't work.
Or you can just move the window types to a separate module. The type enumeration is something that can exist independently of the Window class, and it's not a bad idea to have it completely separate so that code which wants to use the types doesn't have to bring in the full windows module. I see why you'd want to keep the types together with the Window implementation, since the type isn't really used for anything else, but I don't think that's so necessary that it should keep you from moving the enumeration to a separate module. The implementation of windows could definitely span several modules. You could even make it a subpackage if you like, i.e. have a structure like
test/
|-- __init__.py
|-- windows/
|-- __init__.py
|-- types.py
|-- window.py
|-- elements.py
|-- test.py
(adjust as needed for your purposes).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With