Python `__init __. Py` and initialization of objects in the code

I read the documentation for __init__.py files and some interesting questions here on SO, but I'm still confused about the correct use.

Context

I have code with many packages and subpackages. I have defined many classes, some of which I need to create one (and only one) instance for the entire user session. These new objects are then used in different parts of the code, so that every time I (or the user) update the data / information in these objects, it will be used in the entire code without changing anything else. To be more clear, let me show you the basic outline of what I'm talking about.

The code has a simplified structure, for example:

 root/ __init__.py tools/ __init__.py ... (some modules) aliases.py (which defines the class Aliases) physics/ __init__.py ... (some modules) constants/ ... (some modules) constants.py (which defines the class Ctes) units.py (which defines the class Units) 

In the code, I need to manage aliases, units and constants. The way I found this is to create one instance of each and use it throughout the code. Using this method, I am sure, for example, that if an alias is added while the code is still running, it can be used anywhere in the code, because there is only one common instance of the aliases. This is what I need (the same thing applies to units and to constants).

Current state

So far, how I do it, I think, is not the best. In fact, I instantiate, say, aliases, right after the class declaration in the same file:

in root/tools/aliases.py

 import ... (stuff class Aliases(object): """The Aliases manager""" ... ALIASES = Aliases() 

And then, in any file I need to use Aliase, I do:

in any_file.py (anywhere in the code)

 from root.tools.aliases import ALIASES ALIASES.method1() # possibly in functions or other classes ALIASES.method2() # ... etc 

And for some other classes, I even use the __init__.py file in the root of the code:

in root/__init__.py

 # CTES is the instance of Ctes() created in root/physics/constants/constants.py from root.physics.constants.constants import CTES CTES.add(...) # add a new constant that needs to be known 

(of course, CTES does not just save some constants, I define some methods for using them, so it makes sense to have them in this class, and not just define them like regular python constants in a module)

Questions

I am wondering if I am doing this correctly (maybe not). It might be better to use __init__.py files and initiate shared instances in it. But then it causes some problems (e.g. dependency cycles or increased memory usage ...)? Also, how do you use instantiated instances elsewhere in the code? Like this?:

in root/tools/__init__.py

 import root.tools.aliases as Al ALIASES = Al.Aliases() # should I delete the imported module: del Al ?? 

and then in any_file.py

 from root.tools import ALIASES ALIASES.method(...) 

Or should all of these instances be better included in a file (e.g. root/shared.py ) that I import into root/__init__.py so that I am sure that it is triggered?

I have read many times that it is better to leave __init__.py files empty (which is the case right now in my code, except, of course, for root/__init__.py ). What do you think?

I lost a little (you probably could see this because I am not very clear). Any help / advice is more than welcome. I would like to avoid any non-pythonic solutions, or solutions that can confuse the user, or make things unsafe.

+4
source share
2 answers

What you do when you create a single instance inside your module is FINE. There is nothing wrong with using global variables (except when they are not suitable, but this applies to any language function). The only potential drawback is that you import this module without using it, and the waste resources that initialize this class. If your class does not do something really hard during creation, which I highly doubt, this effect is negligible. The only thing I would suggest is that you customize your name. Your class should probably begin with an underscore so that users of your module know that they don’t touch it, and your instance should be lowercase. The method you use will not cause any bad side effects.

Nobody says there that you need to put all your classes in your own file or that you should use classes in general. Maybe the alias module with functions in it and the "private" state in the global glossaries makes more sense to you. Since you do not use the object system to obtain multiple instances with independent state, the only reason to create a class is how you prefer to organize your code and your API. The most important thing here is that you are happy with how your code is organized and how your modules will be used. You will most likely confuse users using object-oriented methods too much than too few imo. Just make sure you create the class when you really need it.

There are many other approaches to singleons. This is the first thing I heard about the “Borg model,” and it sounds wasteful and silly to me, but I think it at least works technically, and the waste is at least insignificant. You can write a function that creates an instance of the class on the first call, saves it globally and returns global in subsequent calls (but then you need to worry about streaming, which is not a problem, as you already do This). You can create a class, the __init__ method raises a TypeError so that it cannot be created at all, and do everything using class methods or staticmethods, preserving all the state you need in the class itself. You can even create a class that returns the same instance every time. The result of all this is that you get an object from your module, which you then use in your code, and the way you use it after that will look the same.

I think you just need to create an instance of your built-in class in one of your modules, as in the code that you published, because it works, this is a general template, it is reasonable and makes sense for you.

There is no reason to remove the module that you imported. It does not save anything. A module exists forever after import (if you are not actively doing some strange things to get rid of it), and global variables are not some valuable resource that you need to save.

You do not introduce a circular dependency by importing your modules inside __init__.py, if you reference your modules inside yourself with a relative name (that is, aliases instead of root.tools.aliases). Circular dependencies are a real problem, so be careful. So far, your modules only import things that are deeper in the tree, and what you consider to be the “lower level” (which means that lower level modules will not import higher level things that can use them), you should be fine. I would advise against introducing any significant code into __init__.py, but I think that instantiating your classes is fine if you want the instances to live.

+1
source

Use the Borg pattern to implement all your common classes throughout the code, and then store them in your own modules (or bundled together) wherever you think might be appropriate.

Then simply import them where necessary and create an instance of the class. All of them will have the same context, and you can even fine-tune the behavior of instances per instance.

If they are isolated in their own module (s), then you will not have any circular dependencies, and you will minimize the parsing time of the interpreter during import. Best of all, you will not pollute the namespace by importing global variables elsewhere. Since your function is out of scope, the instance will be marked for deletion, but the state will be saved with the class definition.

+1
source

Source: https://habr.com/ru/post/1399709/


All Articles