有没有干净的方法实现一种“__tuple__”方法?

4 投票
2 回答
507 浏览
提问于 2025-04-18 00:39

假设有一个类A的对象a,它有一个属性叫做“.my_tuple”。我想通过某种方式来获取这个属性。

tuple(a)

我找到的最简单的方法是这样定义类A:

class A():
    # other things
    def __iter__(self):
        return self.my_tuple.__iter__()

不过这看起来有点不太干净:我理解的是,“tuple(a)”会遍历self.my_tuple来创建它的一个副本,而我其实只想要一个指向它的引用……内置的“tuple”在处理这种情况时是否经过优化?如果没有,是否有更好的方法来做到这一点(并保持“pythonic”,在我的情况下,将A类型转换为元组是有意义的)。

2 个回答

2

根据你问题引发的各种评论,我的建议是可以从一个对象的属性中获取一个元组:

>>> class Tupleable(object):
    def __iter__(self):
        return (v for v in self.__dict__.itervalues())

>>> class A(Tupleable):
    def __init__(self, a, b):
        self.a = a
        self.b = b

>>> a = A(2, 'e')
>>> tuple(a)
(2, 'e')

这里会显示所有的属性,所以如果你想排除某些属性,这个方法就不太合适,但它可能还是能满足你的需求。

4

内置的 tuple() 函数并不是为了让你可以自定义你的类而设计的。根据我所知道的,没有办法直接定制将你的对象转换为元组的过程。

所以你使用了一个可以自定义的点,那就是内置的 iter() 函数和相应的 __iter__ 方法。这么做是可以的,但它的效果有些超出你的需求,也有些不足:

  • 不足之处在于,虽然 tuple 能识别它的参数是一个元组,但它并不能识别从 __iter__ 返回的是一个元组迭代器的情况。因此,正如你所看到的,它会复制这个元组。
  • 而超出你需求的地方在于,它允许任何人都能遍历你的对象,而不仅仅是通过 tuple()

因为没有办法直接定制将你的对象传递给 tuple() 的效果(这和 iter()len() 或其他许多函数不同),所以你基本上不能通过 tuple() 函数来访问 self.my_tuple。你能做的只是让它返回一个副本。

根据你的评论:

我有几个属性,比如 a.b、a.c、a.d,我希望能通过 tuple(a) 得到 (b, c, d)

你或许可以考虑使用 collections.namedtuple

class A(collections.namedtuple('A', 'b c d')):
    # whatever methods you need

当然,这意味着 A 的那些属性是不可变的,所以如果这不是你想要的,那就没什么帮助了。

撰写回答