I'm developing a physical model using Python. I right now have four files (I suppose I can call them modules but I really am no Python expert) in one folder. Right now it works just fine but after reading a bit it turned out the way I do it could lead to errors when further expanding my model (by using from ... import* statement).
(1) initialize: Does nothing except for calling the plot() module with some information about what to plot. Here I would like to set some initial parameters which won't change during the computation and pass them to the compute module. Imports plot
(2) compute: Contains initial values (which I actually want to set in initialize module) and all the computation algorithm. During computation, functions which are stored in functions module are being called a lot. Imports functions
(3) functions: Contains actual physical functions.
(4) plot: Contains all the plots. Imports everything from compute (from compute import *)
Originally I only had the compute and the functions module. When I started plotting however, the compute module became too big (in my eyes) so I wanted to split. I realized I would need to pass all the variables I calculated in compute (quite a few) as arguments to the plot module. Or alternatively import the compute module with a prefix (e.g. import compute as com --> com.variable). I didn't like both options too much. So i decided to use the from compute import * statement, which allows me to use the same variable names as originally defined in compute. This looks a lot cleaner to me and makes it easier to read to variable names.
The problem is, when importing compute into my plot module (to get all the variable names) the code in compute is executed. But I would like to call compute from my initialize module to set up the initial parameters. However If i do so i would need to call compute twice, which takes a lot more time. Besides that, from ... import * apparently is not a good choice. I'm grateful for any suggestions.
CodePudding user response:
On the import statements
The main reason to avoid from my_model import *
statements is, that it obscures which variables are imported (and available in the scope after the importing) and where does the variables comes from. For example if you have:
from mod1 import *
from mod2 import *
...
print(my_var)
... it is not immediately clear if the my_var
comes from mod1
or mod2
. Furthermore, lets say, we define my_var
in mod1
and then during the development we define my_var
also in mod2
(for example even without exporting it at all), suddenly my_var
is something else which may lead to weird errors. And if you are using chained imports, it is really hard to keep track which import gets executed first and which last, so generally you need to make sure you never define variables with clashing names.
This problem is somewhat (personally, I still think it is worth avoiding just for that reason) mitigated with usage of modern IDEs which can point out clashing names, however it is still subject to overlooking. However, speaking of the IDEs... if you know a function you need is in a specific module -- if you imported the module as import my_mod
-- you can type my_mod.
and the IDE shows you the options, if you import it via from my_mod import *
its not so easy.
For these reason it is generally recommended to use plain import my_mod
or using aliases import my_mod as mm
which have none of these problems. I know you mentioned you don't like this approach but maybe it is worth reconsidering. Nevertheless, if you still don't like it there is a middle ground of from my_mod import var_1, var_2, func
. Then you don't have to write mm.
every time you need the variables. It has a drawback that every time you want to use a new variable defined in my_mod
you'll need to add it to the import
statement as well, however on the bright side, this approach would make you sure you don't import clashing variables (as while adding it to import
statement you can cross-check with other import
s, and also it will make sure that you don't end up importing some variables that you don't want to import.
Nonetheless, if you are building your own small project you might indeed end up using from my_mod import *
just be aware of the drawbacks mentioned above.
On the execution while import
ing
The fact that some (non-trivial) code gets executed during import
statement suggests bad code design. During the import
call, the only code that gets "executed" is the code written in the "top scope". That is, if there are some functions etc. these function (naturally) don't get executed, just... defined. However if you have some "direct" code in the "top scope", for example:
print(42)
this code will get executed (and prints 42
) when first encountered appropriate import
statement.
In most cases in this "top scope" should be just only class/function definitions and occasionally some global variables. All other code should be enclosed in some function or class or method... exactly for the reason, so it wouldn't be executed at the import
statement. So if you have some code, which you wish to execute at specific moment, wrap that part of the code in a function a call that function (from the other module), rather than relying on the import
statement to execute the code.
Note that there are some exceptions to aforementioned "rule". Most notably, if you want some code to gets executed when you call the file via python3 my_file.py
you need to put the code you wish to be executed in the "top level". However even in this case this code should be put within if __name__ == '__main__':
guard for this reason -- not to execute the code on import
(just when "calling the file" directly), additionally, it is a good practice to have a very short code within this guard (for example just calling some function)
CodePudding user response:
for namespace you can check python document and for module put command in terminal
pip install (module name)
example:-
pip install flask #the flask module is automatically download in your system