导入时传递变量

Mar*_*ark 32 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))
Run Code Online (Sandbox Code Playgroud)

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

import someClass
someClass.sourceRStuff(PATH_TO_R_SOURCE)
x = someClass.SomeClass([1,2,3,4])
etc...
Run Code Online (Sandbox Code Playgroud)

nmi*_*els 27

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

import someModule
someModule.init(NECESSARY_DATA)
x = someModule.someClass(range(1, 5))
Run Code Online (Sandbox Code Playgroud)

  • 这不像`__init __.py`文件.示例中的init函数只是一个初始化模块中全局状态的普通函数. (6认同)

Aar*_*n D 15

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

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

run.py

import __builtin__
__builtin__.myapp_PATH_TO_R_SOURCE = 'path.to.r.source'
import someClass
Run Code Online (Sandbox Code Playgroud)

someClass模块.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)

...
Run Code Online (Sandbox Code Playgroud)

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

编辑:有些人认为这是"猴子修补"的一个例子.对于没有猴子补丁的更优雅的解决方案,请参阅我的其他答案.

  • 谢谢!这对于在导入期间执行代码**的模块很有用,并且您想要设置执行该代码所需的变量。在这种情况下,“ init”函数没有帮助,因为只能在导入完成后调用“ init”。 (2认同)

Aar*_*n D 7

如果只有一个配置项要设置,那么我发现覆盖python __builtin__工作得很好,但它是一个"猴子修补"的例子,有些人不赞成.

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

myconfig/__ init__.py:

PATH_TO_R_SOURCE   = '/default/R/source/path'
OTHER_CONFIG_ITEM  = 'DEFAULT'
PI                 = 3.14
Run Code Online (Sandbox Code Playgroud)

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 Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

输出:

> Mymodule.two_pi = 6.28318
> Mymodule.version is 1.0
Run Code Online (Sandbox Code Playgroud)

  • 我想补充一点,您可以简单地创建名为“myconfig.py”和“mymodule.py”的文件。这将在降低复杂性的情况下工作相同。**有趣的事实:** 你可以让 `myconfig.py` 完全空白。要检查是否设置了变量,您还可以将 `try` 与 `except AttributeError` 一起使用(除非您不喜欢使用 try-except 那种事情)。 (2认同)

tih*_*iho 5

还有几个其他选项可以实现您的目标(尽管 init() 函数可能更干净):

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