是否有效扩展collections.namedtuple?

时间:2017-01-23 23:27:12

标签: python python-2.7 oop

我想使用类似collections.namedtuple的东西,它可以很好地强制实现不变性并促进一个简单的值类,但它不允许子类化;例如,我想做类似以下to add extra read-only properties的事情:

from collections import namedtuple

class Foo(namedtuple('Foo','foo')):
   @property
   def antifoo(self):
     return -self.foo

class Bar(Foo):
   """ ARGH: somehow we add a 'bar' field """
   @property
   def inversebar(self):
     return 1.0/bar

唯一的问题是没有添加其他属性的机制。所以我查看了collections.namedtuple('Test','foo bar baz', verbose=True)的结果,并根据自己的目的进行了调整:

from collections import OrderedDict
from operator import itemgetter as _itemgetter

class Foo(tuple):
    __slots__ = ()
    _fields = ('foo',)
    _nargs = 1
    _repr_format = '(foo=%r)'
    foo = property(_itemgetter(0), doc='Alias for field number 0')

    def __new__(_cls, foo):
        return tuple.__new__(_cls, (foo,))
    @classmethod
    def _make(cls, iterable, new=tuple.__new__, len=len):
        'Make a new Foo object from a sequence or iterable'
        result = new(cls, iterable)
        if len(result) != cls._nargs:
            raise TypeError('Expected 1 argument, got %d' % len(result))
        return result

    def _replace(self, **kwds):
        'Return a new {typename} object replacing specified fields with new values'
        result = self._make(map(kwds.pop, self._fields, self))
        if kwds:
            raise ValueError('Got unexpected field names: %r' % kwds.keys())
        return result

    def __repr__(self):
        'Return a nicely formatted representation string'
        return self.__class__.__name__ + self._repr_format % self

    def _asdict(self):
        'Return a new OrderedDict which maps field names to their values.'
        return OrderedDict(zip(self._fields, self))

    __dict__ = property(_asdict)

    def __getstate__(self):
        'Exclude the OrderedDict from pickling'
        pass

    @property
    def antifoo(self):
        return -self.foo

class Bar(Foo):
    _fields = ('foo','bar')
    _nargs = 2
    _repr_format = '(foo=%r, bar=%r)'
    bar = property(_itemgetter(1), doc='Alias for field number 1')

    def __new__(_cls, foo, bar):
        return tuple.__new__(_cls, (foo, bar))

    @property
    def inversebar(self):
        return 1.0/self.bar

这个似乎正常工作,但是没关系,还是我犯了一个严重的错误?

0 个答案:

没有答案