Python 有没有办法通过collections.namedtuple支持weakrefs?

Python 有没有办法通过collections.namedtuple支持weakrefs?,python,python-2.7,weak-references,Python,Python 2.7,Weak References,我想对namedtuple使用弱引用,但失败了: >>> import collections >>> import weakref >>> >>> Foo = collections.namedtuple('Foo','a b c') >>> weakref.ref(Foo(1,2,3)) Traceback (most recent call last): File "<stdin>",

我想对namedtuple使用弱引用,但失败了:

>>> import collections
>>> import weakref
>>>
>>> Foo = collections.namedtuple('Foo','a b c')
>>> weakref.ref(Foo(1,2,3))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot create weak reference to 'Foo' object
有解决办法吗?

简短回答 不幸的是,非空的\uuuu插槽\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

变通 您所能做的最好的事情就是拥有一个不从元组继承的类

我为你写了一封信(见下文)。它是这样使用的:

from __future__ import print_function
from altnamedtuple import AltNamedTuple
from weakref import proxy

class Point(AltNamedTuple):
    __slots__ = ('x', 'y', '__weakref__')
    def __init__(self, x, y):
        self.x = x
        self.y = y

# Now, exercise the capabilities of the named tuple alternative
p = Point(10, 20)
r = proxy(p)
print(len(r))               # sizeable
print(r[0])                 # indexed access
print(r.y)                  # attribute access
print(list(r))              # iterable
x, y = r                    # unpackable
print(x, y)
print(20 in r)              # membership testing
print(tuple(reversed(p)))   # reversible
print(r == (10, 20))        # equality
print(r != (30, 40))        # inequality
print(hash(p))              # hashable
print(r)                    # nice repr
print(r._asdict())          # conversion to a dict
print(r._replace(y=2))
t = (11, 22)
print(r.count(10))
print(r.index(20))
print(Point._make(t))       # alternative constructor
注意,weakrefs代理不会传递对uuu散列或uuu反向的调用。这是任何类都无法克服的固有限制

AltNamedTuple的源代码 以下是完成所有工作的课程:

class AltNamedTuple(object):
    "Subclasser needs to define:  __slots__ and __init__"
    __slots__ = ()
    def __getattr__(self, attr):
        if attr != '_fields': raise AttributeError(attr)
        if '__weakref__' in self.__slots__:
            return self.__slots__[:-1]
        return self.__slots__
    def __len__(self):
        return len(self._fields)
    def __getitem__(self, index):
        attr = self._fields[index]
        return getattr(self, attr)
    def __iter__(self):
        for attr in self._fields:
            yield getattr(self, attr)
    def __reversed__(self):
        return iter(reversed(tuple(self)))
    def __eq__(self, other):
        return tuple(self) == tuple(other)
    def __ne__(self, other):
        return tuple(self) != tuple(other)
    def __hash__(self):
        return hash(tuple(self))
    def __repr__(self):
        pairs = ['%s=%r' % (a, getattr(self, a)) for a in self._fields]
        return ('%s(%s)' % (self.__class__.__name__, ', '.join(pairs)))
    @classmethod
    def _make(cls, iterable):
        return cls(*iterable)
    def _asdict(self):
        return dict(zip(self._fields, self))
    def _replace(_self, **kwds):
        d = _self._asdict()
        d.update(kwds)
        return _self.__class__(**d)
    def count(self, value):
        return tuple(self).count(value)
    def index(self, value):
        return tuple(self).index(value)
class AltNamedTuple(object):
    "Subclasser needs to define:  __slots__ and __init__"
    __slots__ = ()
    def __getattr__(self, attr):
        if attr != '_fields': raise AttributeError(attr)
        if '__weakref__' in self.__slots__:
            return self.__slots__[:-1]
        return self.__slots__
    def __len__(self):
        return len(self._fields)
    def __getitem__(self, index):
        attr = self._fields[index]
        return getattr(self, attr)
    def __iter__(self):
        for attr in self._fields:
            yield getattr(self, attr)
    def __reversed__(self):
        return iter(reversed(tuple(self)))
    def __eq__(self, other):
        return tuple(self) == tuple(other)
    def __ne__(self, other):
        return tuple(self) != tuple(other)
    def __hash__(self):
        return hash(tuple(self))
    def __repr__(self):
        pairs = ['%s=%r' % (a, getattr(self, a)) for a in self._fields]
        return ('%s(%s)' % (self.__class__.__name__, ', '.join(pairs)))
    @classmethod
    def _make(cls, iterable):
        return cls(*iterable)
    def _asdict(self):
        return dict(zip(self._fields, self))
    def _replace(_self, **kwds):
        d = _self._asdict()
        d.update(kwds)
        return _self.__class__(**d)
    def count(self, value):
        return tuple(self).count(value)
    def index(self, value):
        return tuple(self).index(value)