1

バックグラウンド

に似た型が必要でしたnamedtupleが、変更可能なフィールドがありました。は次のnamedlistように動作する必要があります。

Something = namedlist('Something', ['a', 'b'])
st = Something(123, 456)
print st                 # Something(a=123, b=456)
a, b = st
print a, b, st.a, st.b   # 123 456 123 456

st.a = 777
print st                 # Something(a=777, b=456)
st.b = 888
print st                 # Something(a=777, b=888)

あちこちで記述子について少し学んだ後、上記のように次のコードが機能するようになりました。

class IndexAccessor(object):
    def __init__(self, index):
        self.index = index
    def __get__(self, instance, owner):
        return list.__getitem__(instance, self.index)
    def __set__(self, instance, value):
        list.__setitem__(instance, self.index, value)

def namedlist(classname, fields):
    def init(self, *args):
        list.__init__(self, args)
    def repr(self):
        return '%s(%s)' % (self.__class__.__name__, ', '.join(['%s=%s' % (k,list.__getitem__(self, i)) for i, k in enumerate(self._fields)]))
    attrs = {'_fields': tuple(fields),
             '__init__': init,
             '__repr__': repr
             }        
    for index, field in enumerate(fields):
        attrs[field] = IndexAccessor(index)
    return type(classname, (list,), attrs)

質問

このIndexAccessorクラスは私には定型句のように感じられるので、それを避けるためにコードを改善できるかどうか疑問に思っています。

for index, field in enumerate(fields)ループをこれに置き換えてみました

for index, field in enumerate(fields):
    def get(self): 
        return list.__getitem__(self, index)
    def set(self, v):
        list.__setitem__(self, index, v)
    attrs[field] = property(get, set, None, 'Property "%s" mapped to item %d' % (field, index))

...しかし、それによりprint a, b, st.a, st.bステートメントがの123 456 456 456代わりに生成されました。123 456 123 456これは、必要に応じて機能しないことに関係があると思わindexれます。

次のように、コンストラクターで名前ベースの割り当てを可能にする簡潔なコードも提供できる回答のボーナスポイント

Something = namedlist('Something', ['a', 'b'])
st = Something(a=123, b=456)
4

2 に答える 2