1

後でプログラムで必要になるすべての値を含む .ini のようなファイルを作成しました。以下を参照してください。

[debugging]
checkForAbort = 10
...

[official]
checkForAbort = 30
...

これらすべての項目を 1 つのクラスに読み込み、Python プロジェクトの他の部分からアクセスできるようにしたいと考えています。私がこれまでに持っているのは、以下のコードです:

from ConfigParser import SafeConfigParser
import glob

class ConfigurationParameters
    def __init__(self):
        self.checkForAbortDuringIdleTime = None     

    parser = SafeConfigParser()

    # making a list here in case we have multiple files in the future!
    candidatesConfiguration = ['my.cfg']
    foundCandidates = parser.read(candidatesConfiguration)
    missingCandidates = set(candidatesConfiguration) - set(found)
    if foundCandidates:
        print 'Found config files:', sorted(found)
    else
        print 'Missing files     :', sorted(missing)
        print "aborting..."


    # check for mandatory sections below
    for candidateSections in ['official', 'debugging']:
        if not parser.has_section(candidateSections)
            print "the mandatory section", candidateSections " is missing"
            print "aborting..."

    for sectionName in ['official', 'debugging']:
        for name, value in parser.items(section_name):
            self.name = value

私はPythonを初めて使用しますが、コードにはまだ多くの問題があります:

  • クラス ファイルの各項目に属性を追加する必要があります。構成ファイルとクラスを常に同期させます。
  • このクラスはシングルトンではないため、インポートされた場所から読み取り/解析が行われます!
  • 私のクラスで定義されていない設定ファイルに値が追加されると、おそらくクラッシュします!

代わりに、この問題をどのように解決すればよいですか? クラス属性を動的に作成できますか?

私のクラスは値から読み取るだけでよいので、構成ファイルへの書き込みは必要ありません!

4

3 に答える 3

12

JFセバスティアンが言ったこと。

また、 AlexMartelliが彼のBunchクラスで行うようにそれを行うことができます:

ファイルMyConfig.py

from ConfigParser import SafeConfigParser


section_names = 'official', 'debugging'


class MyConfiguration(object):

    def __init__(self, *file_names):
        parser = SafeConfigParser()
        parser.optionxform = str  # make option names case sensitive
        found = parser.read(file_names)
        if not found:
            raise ValueError('No config file found!')
        for name in section_names:
            self.__dict__.update(parser.items(name))  # <-- here the magic happens


config = MyConfiguration('my.cfg', 'other.cfg')

ファイルfoo.py

from MyConfig import config
# ...

ファイルMyProgram.py

from MyConfig import config

print config.checkForAbort

import foo

assert config is foo.config

Python言語リファレンスには、「インポートステートメントは2つのステップで実行されます。(1)モジュールを見つけ、必要に応じて初期化します。(2)ローカル名前空間(インポートステートメントが発生するスコープの)で1つまたは複数の名前を定義します。 。」

つまり、モジュールがインポートされると、1つ以上のローカル名がモジュールオブジェクトにバインドされ、Pythonプログラムの実行時に初めてインポートされたときにのみ初期化されます(つまり、ファイルから読み取られて実行されます)。 。

上記のコードでは、名前configはモジュールオブジェクトの属性を参照する単なるローカル名です。モジュールオブジェクトは、で(を介してfrom MyConfig import config)参照されたときにPythonインタープリターによって初期化されていますMyProgramMyProgramインポートするときfoo、それはすでに初期化されており、モジュール内のローカル名にバインドされておりfooMyProgramではそれをとして参照できますfoo.config。ただし、どちらの名前もまったく同じオブジェクトを参照しています。

于 2012-09-27T13:02:23.237 に答える
3

self.name = value期待どおりに動作しません。setattr(self, name, value)インスタンス属性を動的に作成するという意味かもしれません。

configシングルトンにするには、インスタンスを/settingsモジュールのグローバル変数にすることができます。loggingモジュールがルートロガーに対して行うように、プログラムの起動時に一度初期化しますlogging.config.fileConfig('logging.conf')

argparse.Namespaceコマンドラインオプションを運ぶなど、本質的にdictであるものに属性アクセスを使用することは一般的な要望です。

インポートすることで、後で構成にアクセスできfrom mypackage.config import configますmypackage/config.py

class Config(object):
    ...

config = Config() # empty or default config without any configuration

mypackage/__main__.py

from .config import config
...
# initialization code
config.update_from_file('mypackage.conf') # it might call `setattr()` inside

注:setattr()プロパティを設定しても正しく動作します。__dict__.update()この場合は壊れます:

class XValidatorMixin(object):
    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        if value < 0:
            raise ValueError
        self._x = value


class CUpdate(XValidatorMixin):
    def __init__(self, **options):
        self.__dict__.update(options)


class CSetAttr(XValidatorMixin):
    def __init__(self, **options):
        for name, value in options.items():
            setattr(self, name, value)

for C in [CUpdate, CSetAttr]:
    o = C(a=1, b=2) # non-property attributes work as expected
    assert o.a == 1 and o.b == 2

o = CSetAttr(x=1)
assert o.x == 1 # setattr also sets property

o = CUpdate(x=1)
try:
    o.x # .update() doesn't set property
except AttributeError:
    pass
else:
    assert 0


try:
    o = CSetAttr(x=-1)  # invokes property setter
except ValueError: # that correctly reject negative values
    pass
else:
    assert 0
于 2012-09-27T12:02:06.380 に答える