1

動的オブジェクトを作成して、構成をその場で検証し、結果をオブジェクトとして提示しようとしました。私はそのようなクラスを作成することでこれを達成しようとしました:

class SubConfig(object):
    def __init__(self, config, key_types):
        self.__config = config
        self.__values = {}
        self.__key_types = key_types

    def __getattr__(self, item):
        if item in self.__key_types:
            return self.__values[item] or None
        else:
            raise ValueError("No such item to get from config")

    def __setattr__(self, item, value):
        if self.__config._blocked:
            raise ValueError("Can't change values after service has started")

        if item in self.__key_types:
            if type(value) in self.__key_types[item]:
                self.__values[item] = value
            else:
                raise ValueError("Can't assing value in different type then declared!")
        else:
            raise ValueError("No such item to set in config")

SubConfig は、構成ファイル内のセクションのラッパーです。構成には、プログラムの開始後に値を変更する可能性を殺すためのスイッチがあります (値は初期化時にのみ変更できます)。

問題は、getattr の無限ループで値を設定するときです。私が読ん__getattr__だように、そのように振る舞うべきではありません(最初に既存の attr を取得してから を呼び出します__getattr__)。コードを利用可能な例と比較していましたが、何も得られません。

すべての問題がコンストラクターによって生成されることに気付きました。

4

2 に答える 2

3

問題は、オブジェクトを初期化する際のコンストラクターが を呼び出し、プライベート メンバーがまだ初期化されていないために__setattr__呼び出されることです。__getattr____

これを回避するには、次の 2 つの方法が考えられます。

1 つのオプションは、 を呼び出して、または同等の in での使用をobject.__setattr__回避することです。値を直接設定することもできます。ここでの問題は、二重アンダースコアを使用しているため、属性名を手動でマングルする必要があることです (したがって、 になります)。__setattr__super(SubConfig, self).__setattr__(...)__init__self.__dict__'__config''_SubConfig__config'

def __init__(self, config, key_types):
    super(SubConfig, self).__setattr__('_SubConfig__config', config)
    super(SubConfig, self).__setattr__('_SubConfig__values', {})
    super(SubConfig, self).__setattr__('_SubConfig__key_types', key_types)

別の方法として、 ie__setattr__で始まる属性名へのアクセスを検出してパススルーする方法があります。_

if item.startswith('_')
    return super(SubConfig, self).__setattr__(item, value)

これは、誰かがオブジェクトの内部にアクセスする正当な理由がある場合、それらを停止しようとする理由がないという点で、より Pythonic です。

于 2012-06-26T11:50:45.060 に答える
2

根本原因に対する ecatmur の回答を__setattr__参照してください。これは対称的ではないことを覚えておいて__getattr__ください。オブジェクトの属性をバインドしようとするたびに、無条件に呼び出されます。オーバーライド__setattr__はトリッキーであり、長所と短所を明確に理解していない場合は行うべきではありません。

ユースケースに対する簡単で実用的な解決策として、setattr呼び出しをトリガーしないように初期化子を書き直します。

class SubConfig(object):
    def __init__(self, config, key_types):
        self.__dict__.update(
            _SubConfig__config=config,
            _SubConfig__values={},
            _SubConfig__key_types=key_types
            )

属性の名前を変更して、先頭の二重アンダースコアの命名スキームを使用するときに発生する名前マングリングをエミュレートしたことに注意してください。

于 2012-06-26T12:19:25.593 に答える