1

次のコードがあります。

class X(object):
    items = []

class Y(X):
    pass

class Z(X):
    pass

Y の「アイテム」リストにのみオブジェクトを追加するデコレータを作成しようとしています。したがって、次のコード、

@addItems
class Y(X):
    pass

Y.items に何か (たとえば、整数 1 としましょう) を追加する必要がありますが、X.items、Z.items、または X の他のサブクラスを変更しないでくださいitems = [1]。 .items の両方が必要items = []です。これは、その目標を達成するために作成したデコレーター関数の定義です。

def addItems(cls):
    cls.items.append(1)
    return cls

ただし、これは機能しません。デコレータを使用すると、X および X の他のすべてのサブクラスの「アイテム」リストが変更されます。Python のクラス属性が X のすべてのインスタンスで共有されていることは知っていますが、サブクラスが影響を受けることは知りませんでした。おそらく、この動作は変更可能な属性に対してのみ発生しますか?

私の目標を達成するための正しい方法は何ですか?

4

1 に答える 1

2

問題はデコレータではありません。items属性が どこにどのように保存されているかについて誤解があります。独自の属性を持っYていません。むしろ、属性は 1 つだけです。で定義した場合(または)、サブクラスで属性が見つからないため、スーパークラスで動的に検索されます。実行すると、True と評価されることがわかります ---リストは 1 つしかありません。つまり、変更すると、すべてのクラスが変更を認識します。ZitemsitemsXY.itemsZ.itemsX.items is Y.itemsitems

items各クラスに独自のリストを与えたい場合は、各クラスに独自のリストを与える必要がありますitems

class X(object):
    items  = []

class Y(object):
    items  = []

class Z(object):
    items  = []

Python は、指示しない限り、何もコピーしません。属性を持つクラスから継承するサブクラスを定義したからといって、Python がサブクラスの属性の新しいコピーを作成するわけではありません。スーパークラスから同じオブジェクトを再利用するだけです。

各クラスに独自の items 属性を「魔法のように」与えたい場合は、デコレータ内で行うことができます。

def addItems(cls):
    cls.items = []
    cls.items.append(1)
    return cls

これにより、最初にクラスがitems空のリストに設定されます。これは実際には、サブクラスやスーパークラスではなく、操作対象の特定のクラスに属性を設定します。これでアクセスすると、期待どおりに動作します。

于 2013-03-07T06:15:48.487 に答える