1

クラスの属性を動的に更新したいのですが、setattrとgetattrの組み合わせが思い通りに動かないようです。

これが私のメインクラスです:

class Container(object):
    def __init__(self):
        pass
container = Container()
attributes = ['a', 'b', 'c', 'd']
values = [[1, 2, 3, 4, 5], [True, False], ['red', 'blue', 'green'], [0, 1, -1, -5, 99]]

この例では、属性とそれぞれの値のリストを明示的に作成したことに注意してください。ただし、このコードの実際のアプリケーションでは、事前に何も知りません。それらの番号、名前、値のいずれでもありません。これを動的に行う必要があります。

残りのコードは次のとおりです。

for key, value in zip(attributes, values):
    setattr(container, key, [])
    for val in value:
        setattr(container, key, getattr(container, key).append(val))

コードを実行すると、この部分は機能しません。getattr 部分を tmp 変数に保存してから、setattr を呼び出す前にリストの append メソッドを呼び出すこともできますが、可能であれば要約したいと思います。

なぜこれが機能しないのか、誰でも説明できますか? どのような代替手段がありますか?

ご協力いただきありがとうございます

4

2 に答える 2

3

インプレースでリストに追加しています。すべてのインプレースミューテーション関数と同様に、を.append()返すNoneので、最終行は次のようになります。

setattr(container, key, getattr(container, key).append(val))

最終的に次のように評価されます。

setattr(container, key, None)

クラスにリストのコピーを設定するだけです。

for key, value in zip(attributes, values):
    setattr(container, key, values[:])

ここで、は、ループすることなく、0から短縮表記でスライスすることによって[:]のコピーを作成します。valueslen(values)

キーと値を属性として提供するオブジェクトを作成するだけの場合(dictアイテムアクセスではなく属性アクセスを使用する場合と同様)、次を使用することもできます。

class Container(object):
    def __init__(self, names, values):
        self.__dict__.update(zip(names, values))

次に実行します:

Container(attributes, values)

setattr()これにより、ループで呼び出す必要がなくなります。

于 2013-03-08T11:37:25.813 に答える
1

各ステップの進行状況を見ることができれば、何が起こっているのかを理解するのに役立つかもしれません:

class Container(object):
    def __init__(self):
        pass
    def __str__(self):
        return '%s(%s)' % (self.__class__.__name__,
            ', '.join(['%s = %s' % (attr, getattr(self, attr))
                for attr in self.__dict__]))

できるようになりprint containerました。ネストされたループでこれを行うと、 (Martijn が指摘したように)setattrに格納されている元のリストを最初に試みた後に上書きされたことがわかります。container.a

for key, value in zip(attributes, values):
    setattr(container, key, [])
    for val in value:
        print 'before:', container
        setattr(container, key, getattr(container, key).append(val))
        print 'after:', container

before: Container(a = [])
after: Container(a = None)
before: Container(a = None)
Traceback (most recent call last): ...

containerこれを行うための「最善の」方法は、明らかに実際の問題によって異なります。縮小された問題を考えると、Martijn のバージョンは非常に適切ですが、最初のインスタンスを作成した後のある時点で、1 つの項目を追加するか、複数の項目で拡張する必要があるかもしれません。

于 2013-03-08T11:51:47.567 に答える