简体   繁体   中英

How to call a function from a variable module in Python?

I am having an issue trying to call a function from a variable module.

I have several scripts under a "scripts/" folder, and from outside this folder, I would like to call the main() function of one of my scripts/module inside, but this module name is variable.

Basically, I would like to do this (but this isn't possible in Python apparently):

scripts.{myModuleName}.main()
  1. The exec command isn't fitting in my case, as it doesn't wait for the called script to finish properly:

     exec("scripts." + myModuleName + ".main()")
  2. The command subprocess.run isn't fitting as well because this is calling the full script and not the specific main() function I want. And if __name__ == __main__ isn't preventing it.

     my_command = "python scripts\\" + myModuleName subprocess.run(my_command, shell=True, check=True)

Any ideas?

--

EDIT: Thank you Gino, working well with importlib. Here is my code in case it could help someone:

import importlib
import os

#We will get, display and import all the scripts dropped into the 'scripts' folder
moduleList = []
for incr, myScript in enumerate(os.listdir('.\\scripts')):
    if ".py" in myScript:
        moduleList.append(importlib.import_module(f"scripts.{myScript.replace('.py','')}"))
        print(f"{incr+1} - {myScript}")

#Ask the user which script he wants to execute
userChoice = input("Choose the number of the script you want to execute: ")

#Execute the main of the desired script
try:
    moduleList[int(userChoice)-1].main()
except (IndexError, ValueError) as e:
    print("Error, you need to enter a number displayed above.")

You can use the built-in importlib 's import_module(name) function to import a module by name as a string :

Import a module. The name argument specifies what module to import in absolute or relative terms (eg either pkg.mod or ..mod ).

module = importlib.import_module(f'scripts.{module_name}')
module.main()

In this way, the module name can be a variable and it can be dynamically defined or set in your program/script. Then, once you've got the module, you can just call its main() function (or any other function or variable on that module).

If we have this directory structure (similar to what you said " I have several scripts under a "scripts/" folder ".):

$ tree .
.
├── outside.py
└── scripts
    ├── module1.py
    ├── module2.py
    └── module3.py

And each moduleN.py has a main like this:

def main():
    print('Called main from module3')

Then to do " from outside this folder, I would like to call the main() function of one of my script/module inside ", you can have outside.py receive the name of the module like this:

import importlib
import sys

module_name = sys.argv[1]
print(f'Calling "main" from {module_name}')

module = importlib.import_module(f'scripts.{module_name}')
module.main()
$ python outside.py module1
Calling "main" from module1
Called main from module1

$ python outside.py module2
Calling "main" from module2
Called main from module2

$ python outside.py module3
Calling "main" from module3
Called main from module3

Do take note that import_module(name) works much the same way as the standard import module_name , such that it depends on from where you are running this import code. Meaning, import_module('scripts.module1') will work if import scripts.module1 works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM