Python中带参数导入模块

32

在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中是否可以将参数传递给模块。


你是在询问 from a import * 吗? - BrenBarn
我认为他正在询问模块全局变量 - Jonathon Reinhart
将你的代码放进一个函数中,然后通过传递参数给该函数来运行! - Oleg Sklyar
@Oleg,我不想这样做,因为在这种情况下,像x、rv这样的变量将成为函数的局部变量,MCMC将无法从中采样。 - turing
这是一个不寻常的模式,但看起来这是在 pymc 中完成任务的方式...建议复制其中一个工作示例,然后进行修改以了解正在发生的事情。 - John Greenall
7个回答

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))

8

无法向模块传递参数。但是,您可以在第三个模块中使用全局变量来实现:

# a.py
parameter = None

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

# c.py
import a
# use a.parameter

当然,这仅适用于没有其他东西导入c的情况,因为模块只被导入一次。

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')

请注意,我不会在期望公开传播的模块上使用此功能。这更适用于我自己个人使用的单文件模块。

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()或类似的方法,以查看变量是否已定义。


0

我真的很惊讶没有人提到环境变量。这是我发现的最干净的方法:

a.py

import os
param = os.getenv('MY_PACKAGE_PARAM', None)
print(param)

b.py

import os
os.setenv('MY_PACKAGE_PARAM', 'Hello world!')
import a

-1

目前没有直接传递参数到模块的方法,但是您可以稍加修改代码,并从模块中导入参数作为全局参数。


欢迎来到SO!请阅读tour如何撰写好的答案? - Tomer Shetah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接