Python: Is it a good practice to rely on import to execute code?

Viewed 377

In Python, is it a good practice to rely on import to execute code, like in the example below?

The code in mod.py is supposed to load some config, and needs to be executed once only. It can use more complex logic, but its purpose is to establish values of some parameters, later used as configuration by main.py.

# --- mod.py ---
param1 = 'abc'
param2 = 'def'
# ...


# --- main.py ---
import mod

p1 = mod.param1
p2 = mod.param2
# (then calls functions from other components, which use p1, p2, ... as arguments)
4 Answers

Defining things in an additional module is perfectly fine - variables, classes, functions etc.

When the module is imported, as long as you don't use from ... import * your namespace does not get cluttered and you can extract a standalone and/or repeated fragments to have cleaner code.

It's pretty much an intended use for modules.

What is not so good, is having code with side-effects that gets executed on import. This here gives a nice example why it's not a good idea: Say “no” to import side‐effects in Python

code in mod.py is supposed to load some config, and needs to be executed once only.

Using import statement leads to

  1. find a module, loading and initializing it if necessary
  2. define a name or names in the local namespace for the scope where the import statement occurs.

therefore even numerous usage of import mod will lead to execution of code in it just once, consider following toy example, let mod.py content be

print("I am mod.py")

and main.py content be

import mod
import mod
import mod

then output of python main.py will be

I am mod.py

It's always better to import only what's necessary and if possible, write the code in a function and use:

if __name__ == '__main__':
    call_function()

at the end of the code, so that when you go back and change your code (add new variables/manipulate older variables), they won't create a problem.

It's always a good practice to callthe function yourself after that, instead of relying on the import to run it. In your other file, you can import call_function() and then run it yourself.

TL;DR: for loading configs, I would save configs in a YAML file then read it by PyYAML (import yaml). I would write a loader in some util.py and call the loader in main.py. Also, according to the Zen of Python:

Explicit is better than implicit
Flat is better than nested.


e.g. Facebook AI Research's Detectron2 use detectron2/tools/train_net.py to train a neural network with parameters loaded from a config file. Like this:

$ ./tools/train_net.py --num-gpus 8 \
  --config-file ./configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.yaml

Here the the main() in train_net.py calls setup() first which runs get_cfg() imported from detectron2.config:

from detectron2.config import get_cfg

BTW a yaml config file looks like:

_BASE_: "../Base-RCNN-FPN.yaml"
MODEL:
  # WEIGHTS: "detectron2://ImageNetPretrained/MSRA/R-50.pkl"
  # For better, more stable performance initialize from COCO
  WEIGHTS: "detectron2://COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x/137849600/model_final_f10217.pkl"
  MASK_ON: True
  ROI_HEADS:
    NUM_CLASSES: 8
  ...
  ...
  IMS_PER_BATCH: 8
TEST:
  EVAL_PERIOD: 8000

The documentation of PyYAML.

Related