Python使用可变模块名称调用包子模块

时间:2014-06-25 16:11:43

标签: python data-structures scalability packages

如何调用公共子模块(存在于各种模块中),从值中选择正确的模块?

示例:

假设我有这个文件夹结构:

myprogram/
          myprogram.py          #main program
          colors/               #colors package
                 __init__.py    #contains __all__
                 blue/          #blue module
                      paint.py  #submodule
                 red/           #red module
                      paint.py  #submodule

paint子模块在每个模块中都有相同的名称,但每个模块都有不同的代码。

在myprogram.py中我想做这样的事情:

import colors   #import all the colors modules

my_shape = circle()   
my_color = "blue"     #define the module to call by his name
if my_color in colors:
  colors.my_color.paint(my_shape)    #calls the submodule from the right mosule

我希望“colors”包可以扩展,所以我可以轻松地从一个部署中删除一种颜色,而且只需要很少的工作量。

(我可以制作一个带有内部情况的paint.py模块,但它不容易扩展)

问题是:

  • 是否可以执行if my_module in package事情?
  • 如果是这样,我可以使用变量package.my_module_variable.function()来调用包的模块吗?

我正在尝试解决这个storing functions into dicts,我是否以正确的方式?

2 个答案:

答案 0 :(得分:1)

您应该能够将颜色子模块视为属性。子模块在其directorys中需要__init__.py个文件(例如blue/__init__.py)以及paint.py模块。然后你可以做这样的事情:

my_color = "blue"
if hasattr(colors, my_color):
    getattr(colors, my_color).paint(my_shape)

但请注意,在您的示例中,paint是一个模块,因此您无法调用该模块。如果paint模块中有paint函数,那么您可以执行以下操作:

getattr(colors, my_color).paint.paint(my_shape)

编辑:我应该像其他人一样提到,对于您所展示的示例而言,这似乎有些过分。如果您的真实代码/情况比这更复杂,那就去吧。否则一个不错的选择可能是让一个带有字典的绘图模块用于各种操作。因此像colors/paint.py这样的文件可以包含:

def paint_blue(shape):
    print("BLUE!")

def paint_red(shape):
    print("RED!")

paint_funcs = {
    "blue": paint_blue,
    "red": paint_red,
}

def paint(color, shape):
    return paint_funcs[color](shape)

编辑2

颜色目录中的__init__.py文件需要将它们视为子包,否则您无法导入它们。除非主包知道子模块,否则我使用这样的属性的初始方法将无法工作。例如:

import colors
# colors doesn't know it has submodules 'blue' and 'red'
from colors import *
# if the colors __init__ has an __all__ declaration now it does know about them
hasattr(colors, "blue") # will work

或者您可以导入颜色__init__.py模块

中的颜色
# in colors/__init__.py
import blue
import red

或者你可以做别人对动态导入所说的话。

答案 1 :(得分:0)

如果您知道模块文件的路径,可以使用imp模块动态加载模块:

import imp

my_color = "blue"
paint = imp.load_source('paint', 'colors/'+my_color+'/paint.py')

paint可以用作常规模块,就像导入时使用:

from colors import blue.paint as paint