在Python中导入带参数的模块

34 投票
7 回答
49190 浏览
提问于 2025-04-18 08:41

在Python中,是否可以带参数导入一个模块呢?

我说的参数是指在模块里有一个变量,这个变量在模块内部没有被初始化,但我还是想在这个模块里使用它。简单来说,我想要的效果像是一个函数,但不同于函数的是,我希望模块里的变量能在调用的代码中直接使用。

比如说有一个文件叫a.py

#lists like data, count, prob_distribution are constructed from training_pool (not initialized in this file)
x = pymc.Uniform('x', lower = 0, upper = 1)
rv = [ Multinomial("rv"+str(i), count[i], prob_distribution[i], value = data[i], observed=True) for i in xrange(0, len(count)) ]

还有一个文件叫b.py

import a  #I want some way tr pass value of training_pool
m = pymc.MCMC(a)

我希望a.py里的所有随机变量都能在MCMC中使用。我也愿意接受更好的解决方案,但我想知道在Python中,给模块传递参数是否可行。

7 个回答

4

模块级的全局变量通常能满足大多数需求,但如果遇到以下情况呢:

  • 参数需要在模块初始化时进行评估,或者
  • 你需要多个不同参数的模块版本

在最近的Python版本中,可以分两步加载模块,先加载模块的规格(spec),然后再执行(exec)。在这两步之间,你可以设置额外的变量。

import importlib
abstractModuleSpec=importlib.util.find_spec('myModule')
module4=importlib.util.module_from_spec(abstractModuleSpec)
module2=importlib.util.module_from_spec(abstractModuleSpec)
module2.parameter="you are version 2"
module4.parameter="you are version 4"
module4.__spec__.loader.exec_module(module4)
module2.__spec__.loader.exec_module(module2)

在模块中,你可以使用 dir() 或类似的命令,检查这个变量是否已经定义。

7

我发现定义全局变量很有用,并且可以通过一个初始化函数来设置这些变量。

def init(config_filename=CONFIG_FILENAME):
    config = configparser.ConfigParser(interpolation=configparser.ExtendedInterpolation())
    config.read(config_filename)

    global YEARS
    YEARS = config['DEFAULT']['YEARS']
    global FEATURES
    FEATURES = config['DEFAULT']['FEATURES']

这样,用户只需要记得在使用这些方法之前先初始化这个模块就可以了:

import module
module.init('config.ini')

需要注意的是,我不会在我希望公开分享的模块上使用这种方法。这种做法更适合我个人使用的单文件模块。

9

模块之间不能直接传递参数。不过,你可以在第三个模块中使用一个全局变量来实现这个目的:

# a.py
parameter = None

# b.py
import a
a.parameter = 4
import c

# c.py
import a
# use a.parameter

当然,这种方法只有在没有其他地方导入模块c的情况下才有效,因为模块只会被导入一次。

12

有很多方法可以做到这一点,这里介绍一个简单又傻乎乎的方法:

main.py

"""A silly example - main supplies a parameter
"""

import sys,os

print os.path.basename(__file__)+":Push it by: --myModuleParam "+str(123)
sys.argv.append('--myModuleParam')
sys.argv.append(123)
import module


print os.path.basename(__file__)+":Pushed my  param:"+str(module.displayMyParam)

module.py

"""A silly example - module consumes parameter
"""

import sys,os

displayMyParam = 'NotYetInitialized'

for px in sys.argv:
    if px == '--myModuleParam':
        idx = sys.argv.index(px)
        sys.argv.pop(idx) # remove option
        displayMyParam = sys.argv[idx]
        sys.argv.pop(idx) # remove value
        print os.path.basename(__file__)+":Got my param:"+str(displayMyParam)

#
# That's it...
#
11

正如@otus已经回答的那样,模块是无法传递参数的。

我觉得你可能在看一些PyMC2的入门示例,这些示例使用了一种模式,把贝叶斯模型中所有节点的代码都放在一个模块里。这种方法适合刚开始学习,但正如你发现的那样,当你想用不同的变体来运行模型时,这种方法会有些局限。

幸运的是,PyMC2可以从列表或字典中创建一个MCMC对象,也可以从模块中创建。在这种情况下,我建议你按照@oleg-s在评论中提到的做法:使用一个函数。你可以在函数的最后加上return locals(),这样就能得到一个包含模块中所有内容的字典,这个字典可以作为pymc.MCMC构造函数的输入。下面是一个例子:

# a.py
from pymc import *

count = [10, 10] # perhaps good to put this stuff in data.py
prob_distribution = [[.5, .5], [.1, .2, .7]]
data = [[2, 8], [2, 3, 5]]

def model(training_pool):
    x = Uniform('x', lower = 0, upper = 1)
    rv = [ Multinomial("rv"+str(i), count[i], prob_distribution[i], value = data[i], observed=True) for i in training_pool ]

    return locals()

# b.py
import pymc, a

training_pool = [0]
m = pymc.MCMC(a.model(training_pool))

撰写回答