0

プログラム全体でハードコードされた値を最小化するために、次のような定数のセットを定義しましたConstants.py

FOO = 42
HOSTNAME=socket.gethostname()
BAR = 777

これらの定数を使用したいすべてのモジュールは、単に実行してすぐimport Constantsに使用します。Constants.FOO

現在、これらの定数の一部は、プログラムが実行されている実際のホストに依存する場合があります。したがって、アプリケーションが実行されている実際の環境に基づいて、それらのいくつかを選択的にオーバーライドしたいと思います。最初の大まかな試みは次のようになりましたConstants.py

FOO = 42
HOSTNAME=socket.gethostname()
if HOSTNAME == 'pudel':
   BAR = 999
elif HOSTNAME == 'knork'
   BAR = 888
else:
   BAR = 777

これは問題なく動作しますが、ファイルが特殊なケースで乱雑になるので、避けたいと思います。

シェルスクリプトを実行している場合は、次のようなものを使用しますConstants.sh

 FOO = 42
 HOSTNAME=$(hostname)
 BAR = 777

 # load host-specific constants
 if [ -e Constants_${HOSTNAME}.sh ]; then
   . Constants_${HOSTNAME}.sh
 fi

およびオプションConstants_pudel.shで、次のようになります。

BAR = 999

これにより、共通の定数が一緒に保持され、別々のファイルでそれらを簡単にオーバーライドできます。

私はシェルスクリプトではなくPythonプログラムを書いているので、同じ結果を得る方法を考えていました。

無駄に私は次のようなことを試みました:

FOO = 42
HOSTNAME=socket.gethostname()
BAR = 777
try:
  __import__('Constants_'+HOSTNAME)
except ImportError:
  pass

次のようにConstants_poodle.pyなります。

import Constants
Constants.BAR = 999

これは、内で問題なく動作しますが、別のpythonファイルでConstants_poodle試してみると、元のファイルが取得されます。import ConstantsConstants.BAR

まったく機能しないことは別として、使用__import__()は非常に醜いように思われるので、特定のセットアップに対してエクスポートされた定数をオーバーライドする適切な方法があると思いますか?

4

2 に答える 2

1

PythonレシピのActivestateConstantsから派生した、次のようなことを行うことができます。

import os as _os
import socket as _socket

class _constants(object):
    def __init__(self):
        self.FOO = 42
        self.HOSTNAME = _socket.gethostname()
        self.BAR = 777

        # load host-specific constants
        hostconst = 'Constants_{}'.format(self.HOSTNAME)
        if _os.path.exists(hostconst):
            localdict = {}
            execdict = self.__dict__.copy()
            execdict['__builtins__'] = None
            execfile(hostconst, execdict, localdict)
            self.__dict__.update(localdict) # add/override attributes defined

    def __setattr__(self, name, value):
        self.__dict__[name] = value

# replace module entry in sys.modules[__name__] with instance of _constants
# (and create additional reference to module so it's not deleted --
# see Stack Overflow question: http://bit.ly/ff94g6)
import sys
_ref, sys.modules[__name__] = sys.modules[__name__], _constants()

if __name__ == '__main__':
    import constants

    print constants.FOO
    print constants.HOSTNAME
    print constants.BAR

したがって、たとえば_socket.gethostname()「pudel」が返され、Constants_pudel次の行を含むファイルが存在する場合:

BAR = 999
FOO += 1

次に、printステートメントからの出力は次のようになります。

43   
pudel
999  
于 2013-02-13T21:20:30.877 に答える
1

ソリューションにはいくつかの問題があります。まず、importは、インポートされたモジュールを現在の名前空間に追加しません。python 3.xについてはよくわかりませんが、python2.xでは次のようなことができます。

FOO = 42
BAR = 777
HOSTNAME=socket.gethostname()
try:
    _imp = __import__('Constants_'+HOSTNAME)
    _locals = locals()
    for _name in dir(_imp):
        if not _name.startswith('_'):
            _locals[_name] = getattr(_imp, _name)
    del _imp, _locals, _name
except ImportError:
    pass

しかし、次の問題は、すべてのconstants_xxx.pyファイルがpythonパスになければならないということです。

私があなたにとってよりうまくいくと思う別の解決策は、ユーザーディレクトリの.iniファイルに構成を置き、ConfigParser(または好みに応じてyamlまたはxml)を使用することです。

于 2013-02-13T20:17:40.243 に答える