少ない記述量で、コンストラクタで指定するフィールドを増減させる(Python)
子クラスが独自に持つフィールドをtupleで指定すると、自動的にコンストラクタで指定できるフィールドに変化するパターンを紹介します。tupleで指定するというのは、このような感じのことです。
class Child(Parent): fields = ('child_field1', 'child_field2')
今回紹介する手法を使った場合、Parentクラスのフィールドがparent_field1だけだったとすると、Childクラスのコンストラクタは__init__(self, parent_field1, child_field1, child_field2)のようになります。fieldの名前に重複は許さないことにすると、実装は次のようになります。
#python2.6 def test_add_fields_from_tuple(self): class MyType(type): def __new__(cls, name, bases, d): strage = [] strage.extend(getattr(bases[0], 'fields', ()))# fields comming from base class strage.extend(d.get('fields', ()))# fields comming from current class assert len(strage) == len(set(strage)), 'layout conflict' d['fields'] = tuple(strage) return type.__new__(cls, name, bases, d) class A(object): __metaclass__ = MyType fields = ('one',) def __init__(self, *fields): if len(self.fields) is not len(fields): raise TypeError('%s takes %d arguments' % (self.__class__.__name__, len(self.fields)) ) for name, value in itertools.izip(self.fields, fields): setattr(self, name, value) self.assertRaises(TypeError, A,) a = A(1) self.assertEquals(1, a.one) class B(A): fields = ('two',) self.assertRaises(TypeError, B, 1) b = B(1,2) self.assertEquals(1, b.one) self.assertEquals(2, b.two) try: class C(A): fields = ('one', 'two') except AssertionError: self.assertEqual('layout conflict', str(sys.exc_info()[1])) return self.fail()