是否可以通过collections.namedtuple支持弱引用?

问题描述 投票:2回答:1

我想使用对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

我尝试使用__slots__ = ('__weakref__',)修复此问题,但这也失败了:

>>> class Foo(collections.namedtuple('Foo','a b c')):
...     __slots__ = ('__weakref__',)
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
    nonempty __slots__ not supported for subtype of 'Foo'

是否有解决方法?

python python-2.7 weak-references
1个回答
0
投票

简短回答

不幸的是,非空的__ slots __完全不适用于任何类型的tuple,而不仅是namedtuple()

解决

您能做的最好的事情就是拥有一个不继承自tuple的类。

我为您写了一个(见下文)。它的用法是这样的:

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代理不会通过调用__ hash ____ reversed __传递。这是一个固有的限制,任何类都无法解决。

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)
© www.soinside.com 2019 - 2024. All rights reserved.