导入时传递变量

时间:2010-09-15 18:46:09

标签: python import

假设您在首次导入模块/类时需要花费一些时间。此功能取决于传入的变量。只需在加载模块/类时完成。然后,该类的所有实例都可以使用结果。

例如,我正在使用rpy2:

import rpy2.robjects as robjects

PATH_TO_R_SOURCE = ## I need to pass this
robjects.r.source(PATH_TO_R_SOURCE, chdir = True) ## this takes time

class SomeClass:
  def __init__(self, aCurve):
    self._curve = aCurve

  def processCurve(self):
    robjects.r['someRFunc'](robjects.FloatVector(self._curve))

我是否一直在创建一个模块级功能,我打电话来做这项工作?

import someClass
someClass.sourceRStuff(PATH_TO_R_SOURCE)
x = someClass.SomeClass([1,2,3,4])
etc...

8 个答案:

答案 0 :(得分:25)

拥有模块初始化功能并非闻所未闻。 Pygame为sdl初始化函数做了这件事。所以是的,你最好的选择可能是

import someModule
someModule.init(NECESSARY_DATA)
x = someModule.someClass(range(1, 5))

答案 1 :(得分:12)

我必须为我的项目做类似的事情。如果您不想依赖调用脚本来运行初始化函数,您可以添加自己的Python内置函数,然后在运行时可供所有模块使用。

小心将内置命名为不可能导致命名空间冲突的唯一内容(例如myapp_myvarname)。

run.py

import __builtin__
__builtin__.myapp_PATH_TO_R_SOURCE = 'path.to.r.source'
import someClass

someClass module .py

import rpy2.robjects as robjects
import __builtin__

if hasattr(__builtin__, "myapp_PATH_TO_R_SOURCE"):
    PATH_TO_R_SOURCE = __builtin__.myapp_PATH_TO_R_SOURCE
else:
    PATH_TO_R_SOURCE = ## Some default value or Null for Exception handling
robjects.r.source(PATH_TO_R_SOURCE, chdir = True)

...

这适用于可能具有默认值但您希望在导入时允许覆盖的变量。如果未设置__builtin__变量,则将使用默认值。

编辑:有些人认为这是" Monkey补丁"的一个例子。对于没有猴子补丁的更优雅的解决方案,see my other answer

答案 2 :(得分:7)

如果只有一个配置项要设置,那么我发现覆盖python __builtin__才能正常工作,但这是一个"Monkey patching"的例子,有些人不赞成。

对项目中的多个配置项非常有用的一种更简洁的方法是创建一个单独的配置模块,首先由包装代码导入,并在功能模块导入之前在运行时设置这些项。此模式通常用于其他项目。

myconfig / __ init__.py:

PATH_TO_R_SOURCE   = '/default/R/source/path'
OTHER_CONFIG_ITEM  = 'DEFAULT'
PI                 = 3.14

mymodule / __ init__.py:

import myconfig

PATH_TO_R_SOURCE = myconfig.PATH_TO_R_SOURCE
robjects.r.source(PATH_TO_R_SOURCE, chdir = True) ## this takes time

class SomeClass:
  def __init__(self, aCurve):
    self._curve = aCurve

if myconfig.VERSION is not None:
  version = myconfig.VERSION
else:
  version = "UNDEFINED"

two_pi = myconfig.PI * 2

您可以在运行时从包装器更改模块的行为:

run.py:

import myconfig

myconfig.PATH_TO_R_SOURCE = 'actual/path/to/R/source'
myconfig.PI = 3.14159
# we can even add a new configuration item that isn't present in the original myconfig:
myconfig.VERSION="1.0"

import mymodule
print "Mymodule.two_pi = %r" % mymodule.two_pi
print "Mymodule.version is %s" % mymodule.version

<强>输出:

> Mymodule.two_pi = 6.28318
> Mymodule.version is 1.0

答案 3 :(得分:4)

导入时无法传递变量。

一些想法:

  • 使用检查使模块从调用模块获取变量;不是非常pythonic
  • 对模块使用Init函数,这是最好的方法

答案 4 :(得分:3)

可以实现目标的其他几个选项(尽管init()函数可能更清晰):

  • 使用环境变量
  • 使用单独的模块M来保存此变量,导入器将设置该变量。然后导入的模块可以知道在哪里找到M,也可以依靠sys.meta_path来获取它。

答案 5 :(得分:2)

不,你没有坚持使用模块级功能,它可能是最好的选择。您还可以使用内置staticmethodclassmethod装饰器使其成为someSclass上的一个方法,可以在实例化之前调用该方法。

如果someClass以外的所有内容在没有初始化的情况下可以使用,那么是有意义的,我仍然认为模块级功能更好。

答案 6 :(得分:1)

我能想到两种解决方案,这两种解决方案都是非常类似于解决方案的解决方案。首先是抛弃导入并像这样运行你的脚本

sys.argv[1] = "argument 1"
sys.argv[2] = "argument 2"
execfile("/path/to/dependency.py")  #depreciated in python 3.x

第二种方法是将您的参数放入外部临时文件中,然后从依赖项中的该文件中读取。

答案 7 :(得分:0)

您是否可以从实现延迟加载的代理服务器中受益?

查看活动状态“Lazy Module Imports”食谱。