Python 导入时传递变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3720740/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Pass Variable On Import
提问by Mark
Let's say you have some time-consuming work to do when a module/class is first imported. This functionality is dependent on a passed in variable. It only needs to be done when the module/class is loaded. All instances of the class can then use the result.
假设第一次导入模块/类时,您有一些耗时的工作要做。此功能取决于传入的变量。它只需要在加载模块/类时完成。然后该类的所有实例都可以使用结果。
For instance, I'm using rpy2:
例如,我正在使用 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))
Am I stuck creating a module level function that I call to do the work?
我是否一直在创建一个模块级函数来调用它来完成工作?
import someClass
someClass.sourceRStuff(PATH_TO_R_SOURCE)
x = someClass.SomeClass([1,2,3,4])
etc...
采纳答案by nmichaels
Having a module init function isn't unheard of. Pygame does it for the sdl initialization functions. So yes, your best bet is probably
具有模块初始化功能并非闻所未闻。Pygame 为 sdl 初始化函数做这件事。所以是的,你最好的选择可能是
import someModule
someModule.init(NECESSARY_DATA)
x = someModule.someClass(range(1, 5))
回答by aaronasterling
No you're not stuck with a module level function, it's just probably the best option. You could also use the builtin staticmethodor classmethoddecorators to make it a method on someSclassthat can be called before it is instantiated.
不,您不会被模块级功能所困扰,这可能是最好的选择。您还可以使用内置staticmethod或classmethod装饰器使其成为someSclass可以在实例化之前调用的方法。
This would make sense onlyif everything other than someClasswas usable without the initialization and I still think a module level function is better.
仅当所有内容都someClass可以在没有初始化的情况下使用并且我仍然认为模块级功能更好时,这才有意义。
回答by Escualo
Could you benefit from a Proxy which implements lazy loading?
你能从实现延迟加载的代理中受益吗?
Check out the Active State "Lazy Module Imports" recipe.
查看活动状态“延迟模块导入”配方。
回答by leoluk
There is no way to pass a variable at import.
无法在导入时传递变量。
Some ideas:
一些想法:
- make the module get the variable from the calling module using inspection; not very pythonic
- use an Init function for the module, this is the best way
- 使模块使用检查从调用模块获取变量;不是很pythonic
- 为模块使用 Init 函数,这是最好的方法
回答by tiho
Couple of other options that can achieve your goal (although a init() function is probably cleaner):
可以实现您的目标的其他几个选项(尽管 init() 函数可能更清晰):
- Use an environment variable
- Use a separate module M to hold this variable, that the importer would set. Then the imported module could either know where to find M, or could rely on sys.meta_path to obtain it.
- 使用环境变量
- 使用单独的模块 M 来保存此变量,导入器将设置该变量。然后导入的模块可以知道在哪里可以找到 M,或者可以依靠 sys.meta_path 来获取它。
回答by Aaron D
I had to do something similar for my project. If you don't want to rely on the calling script to run the initialization function, you can add your own Python builtin which is then available to all modules at runtime.
我必须为我的项目做类似的事情。如果您不想依赖调用脚本来运行初始化函数,您可以添加自己的 Python 内置函数,然后在运行时可用于所有模块。
Be careful to name your builtin something unique that is unlikely to cause a namespace collision (eg myapp_myvarname).
小心地为您的内置函数命名一些不太可能导致命名空间冲突的独特名称(例如myapp_myvarname)。
run.py
运行文件
import __builtin__
__builtin__.myapp_PATH_TO_R_SOURCE = 'path.to.r.source'
import someClass
someClass module .py
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)
...
This works well for variables that may have a default but you want to allow overriding at import time. If the __builtin__variable is not set, it will use a default value.
这适用于可能具有默认值但您希望允许在导入时覆盖的变量。如果__builtin__未设置该变量,它将使用默认值。
Edit:Some consider this an example of "Monkey patching". For a more elegant solution without monkey patch, see my other answer.
编辑:有些人认为这是“猴子修补”的一个例子。有关没有猴子补丁的更优雅的解决方案,请参阅我的其他答案。
回答by SarcasticSully
There are two solutions I can think of, both of which are very work-around-like solutions. The first is to ditch imports and run your script like this
我能想到两种解决方案,这两种解决方案都是非常类似变通的解决方案。第一个是放弃导入并像这样运行你的脚本
sys.argv[1] = "argument 1"
sys.argv[2] = "argument 2"
execfile("/path/to/dependency.py") #depreciated in python 3.x
The second is to put your arguments into an external temporary file, then read from that file in the dependency.
第二种是将您的参数放入外部临时文件中,然后从依赖项中的该文件中读取。
回答by Aaron D
If there is only one configuration item to set, then I have found overriding the python __builtin__to work just fine, but it is an example of "Monkey patching"which is frowned on by some.
如果只有一个配置项要设置,那么我发现覆盖 python__builtin__可以正常工作,但它是“猴子修补”的一个例子,有些人不赞成。
A cleaner way to do it which is very useful for multiple configuration items in your project is to create a separate Configuration module that is imported by your wrapping code first, and the items set at runtime, before your functional module imports it. This pattern is often used in other projects.
一种更简洁的方法,这对项目中的多个配置项非常有用,是创建一个单独的 Configuration 模块,该模块首先由您的包装代码导入,然后在功能模块导入它之前在运行时设置这些项。这种模式经常用于其他项目。
myconfig/__init__.py :
myconfig/__init__.py :
PATH_TO_R_SOURCE = '/default/R/source/path'
OTHER_CONFIG_ITEM = 'DEFAULT'
PI = 3.14
mymodule/__init__.py :
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
And you can change the behaviour of your module at runtime from the wrapper:
您可以在运行时从包装器更改模块的行为:
run.py :
运行.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
Output:
输出:
> Mymodule.two_pi = 6.28318
> Mymodule.version is 1.0

