24

Is it possible to import a module with some parameter in python ?

All I mean by parameter is that there exists a variable in the module which is not initialized in that module, still I am using that variable in that module. In short, I want behavior similar to a function but unlike function, I want the variables of module to be exposed in the calling code.

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

I want all random variables in a.py to be exposed to MCMC. I am open to a better approach for my problem at hand, but I would also like to know whether passing arguments to modules is possible in python or not.

Lord Elrond
  • 9,016
  • 3
  • 20
  • 50
turing
  • 497
  • 1
  • 3
  • 11
  • Are you asking for `from a import *`? – BrenBarn Jun 05 '14 at 07:27
  • I think he's asking for [module-wide globals](http://stackoverflow.com/questions/1977362/how-to-create-module-wide-variables-in-python). – Jonathon Reinhart Jun 05 '14 at 07:27
  • Wrap your code in a.py into a function and pass parameters to that function instead! – Oleg Sklyar Jun 05 '14 at 07:31
  • @Oleg, I don't want to do that as in that case, these vaiables like x, rv will become local variables of the function, and MCMC won't be able to sample from them – turing Jun 05 '14 at 07:47
  • This is an unusual pattern to be using but looks like it is the way things are done in pymc... Suggest copying one of their working examples then modifying that to get an understanding of what's going on – John Greenall Jun 05 '14 at 10:29

6 Answers6

10

As @otus already answered, there is no way to pass parameters to modules.

I think you are following some of the introductory examples for PyMC2, which use a pattern where a module wraps all the code for the nodes in a Bayesian model. This approach is good for getting started, but, as you have found, can be limiting, when you want to run your model with a range of variations.

Fortunately, PyMC2 can create an MCMC object from a list or a dictionary as well as a module. What I recommend in this case is just what @oleg-s suggested in the comments: use a function. You can end the function with return locals() to get a dictionary of everything that would have been in the module, and this is suitable input to the pymc.MCMC constructor. Here is an example:

# 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))
Abraham D Flaxman
  • 2,814
  • 19
  • 39
5

there are various approaches to do so, here is just a silly and simple one:

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...
#
acue
  • 311
  • 2
  • 5
5

I found it helpful to define global variables, and allow these to be set by an init function.

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

Then all the user has to do is remember to initialize the module before using these methods:

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

Note, I would NOT use this on a module that I expect to spread publicly. This is more for single-file modules for my own personal use.

Josiah Yoder
  • 2,380
  • 4
  • 29
  • 46
4

There is no way to pass parameters to modules. However, you could use a global in a third module for this:

# a.py
parameter = None

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

# c.py
import a
# use a.parameter

Of course, this only works if nothing else imports c, because modules only get imported once.

otus
  • 4,957
  • 29
  • 46
1

Module-wide globals should be indeed enough for most uses, but what if

  • the parameter needs to be evaluated during module initialization, or
  • you need multiple versions of the module with different parameters

In recent versions of python, it is possible to load in two steps, first the spec, then exec. In the middle, you can set up extra variables.

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

In the module you can check dir() or similar, to see if the variable is defined.

arivero
  • 781
  • 1
  • 9
  • 23
0

There is no such way to pass parameters to the module, however you can revamp your code a bit and import the parameters from a module as global parameters.

  • Welcome to SO! Please read the [tour](https://stackoverflow.com/tour), and [How do I write a good answer?](https://stackoverflow.com/help/how-to-answer) – Tomer Shetah Oct 13 '20 at 10:08