python - 进行变量导入时避免使用环境变量
问题描述
我一直在处理一个项目,我可以选择使用两个后端(假设是后端 1 和 2,让我们说)按照他们在这个项目中所做的事情。但是,该项目依靠已经定义的环境变量来决定在执行代码之前使用哪个后端。我正在编写的代码并非如此。
我想知道在这种情况下是否有任何替代方法可以使用环境变量,以便在执行时,我可以根据变量的值加载一个或另一个后端。我的项目的一般结构如下:
我曾想过直接在 python 代码中直接设置环境变量os.environ['NAME_OF_ENV_VARIABLE'] = 'BACKEND 1'
(鉴于这种需要,我想知道是否可以有某种变量跨越不同的文件,以便在我导入模块时,文件可以在后端之间消除歧义。__init__.py
PS:也许我正在做的事情毫无意义。
[更新]有关该问题的更多信息,已简化为最小扩展。我的主文件处理一些数据,如下所示:
from argparse import ArgumentParser
from utils.loader import load_data
from utils.do import do_stuff
def main(config):
data = load_data(config)
do_stuff(config, data)
if __name__ == '__main__':
# Retrieve input data
parser = ArgumentParser()
parser.add_argument('--backend', type=str, default='backend 1', help='backend to use')
inputs = parser.parse_args()
config = "backend 1" if inputs.backend == "1" else "backend 2"
# Call main function
main(config)
我猜数据加载器load_data(config)
对此并不重要。然后,包含的文件do_stuff(data)
如下:
import backend
def do_stuff(config, data):
# Do some really important stuff that is coded in backend 1 and backend 2
a = backend.do_something(data)
print(a)
它只是加载后端(!!!)并做一些事情。该do_stuff(data)
函数本身在后端 1 或后端 2 中执行一些编码:
def do_something(data):
data.values = "Value obtained through functions of 'BACKEND 1' (same function names and inputs, different backends used)"
和
def do_something(data):
data.values = "Value obtained through functions of 'BACKEND 2' (same function names and inputs, different backends used)"
最后,后端模块本身具有以下__init__.py
文件:
from .load_backend import do_something
从文件中加载,它只是在给定环境变量的load_backend.py
情况下消除后端的歧义:
from __future__ import absolute_import
from __future__ import print_function
import os
import sys
# Default backend: backend 1
if 'ENVIRONMENT_VARIABLE' in os.environ:
_BACKEND = os.environ['ENVIRONMENT_VARIABLE']
else:
_BACKEND = 'backend 1'
# Import backend functions.
if _BACKEND == "backend 1":
sys.stderr.write('Using backend 1\n')
from .backend_1 import *
elif _BACKEND == "backend 2":
sys.stderr.write('Using backend 2\n')
from .backend_2 import *
else:
raise ValueError('Unable to import backend : ' + str(_BACKEND))
def backend():
"""Publicly accessible method
for determining the current backend.
# Returns
String, the name of the backend
# Example
```python
>>> backend.backend()
'backend 1'
```
"""
return _BACKEND
我想要的是用其他任何东西来减少最后一个环境变量,但我不知道我可以使用什么。
解决方案
就像@DanielRoseman 问的那样,我只会传递后端参数。例如load_backend
,在尽可能少地更改代码的同时:
from __future__ import absolute_import
from __future__ import print_function
import os
import sys
def backend(backend):
"""Returns the wanted backend module"""
# Import backend functions.
if backend == "backend 1":
sys.stderr.write('Using backend 1\n')
from . import backend_1 as backend_module
elif backend == "backend 2":
sys.stderr.write('Using backend 2\n')
from . import backend_2 as backend_module
else:
raise ValueError('Unable to import backend : ' + str(_BACKEND))
return backend_module
一个改进可能是用于importlib
动态导入后端并将魔术字符串移动到一个常量:
...
import importlib
BACKENDS = {
"backend 1": "backend_1",
"backend 2": "backend_2"
}
def load_backend(backend):
try:
module = importlib.import_module(
BACKENDS[backend]
)
except KeyError:
raise ImportError('Unable to import backend : %s' % backend)
sys.stderr.write('Using %s\n' % backend)
return module
因此,您可以在do_stuff
文件中执行此操作:
import load_backend
def do_stuff(config, data):
# Do some really important stuff that is coded in backend 1 and backend 2
backend = load_backend.backend(config)
a = backend.do_something(data)
print(a)
另一种解决方法是使用单例模式,您可以在其中设置一次后端变量(以及您希望广泛使用的其他设置):
在一个settings.py
或任何地方:
class SettingSingleton(object):
_backend = None
def __new__(cls, backend=None, *args, **kwargs):
cls._backend = cls._backend or backend
return super(SettingsSingleton, cls).__new__(cls, *args, **kwargs)
@property
def backend(self):
return self._backend
您可以在主中初始化它。
from argparse import ArgumentParser
from utils.loader import load_data
from utils.do import do_stuff
from settings import SettingSingleton
def main(config):
SettingsSingleton(backend=config)
data = load_data(config)
do_stuff(config, data)
...
现在您可以执行以下操作:
from __future__ import absolute_import
from __future__ import print_function
import os
import sys
from settings import SettingsSingleton
_BACKEND = SettingsSingleton().backend
# Import backend functions.
if _BACKEND == "backend 1":
sys.stderr.write('Using backend 1\n')
from .backend_1 import *
elif _BACKEND == "backend 2":
sys.stderr.write('Using backend 2\n')
from .backend_2 import *
else:
raise ValueError('Unable to import backend : ' + str(_BACKEND))
这样做的缺点是它有点隐含。
推荐阅读
- mysql - MySql中只有输入标记时如何解析单词?
- javascript - QlikSense Field selectValues API - 当字段名称是混搭应用程序中的日期数据类型时不起作用
- json - React Native - NSNumber 类型的 JSON 值“1311”无法转换为 NSDictionary
- google-apps-script - 我无法在具有编辑权限的 Google 表格上创建脚本
- python - TensorFlow:没有名为 Pandas 的模块(我已经有了 Pandas)
- azure - Azure Cosmos DB SQL API
- c# - RSA-SHA256 签名不匹配
- flutter - Flutter 和 GetX - 当我更新我的 RxObject 时,小部件不会重绘
- javascript - antd 图片上传需要将基于类的组件转换成react -hooks,无法增加图片的宽高
- clang - 如何构建clang-tools?“make clang-tools”什么都不做