bugfix> python > 投稿

私は、このプロジェクト。ただし、そのプロジェクトでは、コードを実行する前に使用するバックエンドを決定するための環境変数が既に定義されていることが重要です。私が書いているコードには当てはまりません。

このシナリオで環境変数を使用する代替手段があるかどうかを知りたいので、実行時に変数の値に応じてバックエンドをロードできます。私のプロジェクトの一般的な構造は次のとおりです。

Pythonコードで直接環境変数を直接設定することを考えました( os.environ['NAME_OF_ENV_VARIABLE'] = 'BACKEND 1' )、しかしそれは潜在的に安全ではないと感じ、変数名が...一意であっても、私はそのアイデアを本当に嫌います。この必要性を考えると、異なるファイルにまたがる何らかの種類の変数を使用できるかどうかを知りたいので、モジュールをdoインポートするときに __init__.py  ファイルはバックエンド間で明確にすることができます。

PS:多分、私がやっていることは何の意味もありません。


[UPDATE]問題に関する追加情報を最小限の拡張子に減らしました。私のメインファイルはいくつかのデータを処理し、次のとおりです。

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

and

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

私が望むのは、この最後の環境変数を他のもので減らすことですが、何を使用できるかわかりません。

回答 1 件
  • @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)
    
    

    これを実行するもう1つの方法は、シングルエンドパターンを使用することです。この場合、バックエンド変数を1回設定します(広く利用したい他の設定)。

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

    これの欠点は、暗黙的であるということです。

あなたの答え