【问题标题】:__next__ and next with arguments__next__ 和 next 带参数
【发布时间】:2017-02-01 20:04:09
【问题描述】:

我正在编写双向链表的实现。为了遍历列表,我使用了类似的东西:

class Node:
    """ A node in our linked list """
    def __init__(self, value: Any, next: Union['Node', None] =None,
            previous: Union['Node', None] =None) -> None:
        self.value = value
        self.next = next
        self.previous = previous

    ...

    def __next__(self, direction: int =1) -> Union['Node', None]:
        if direction == 1:
            return self.get_next()
        else:
            return self.get_previous()

    ...

其中get_nextget_previous 只是self.nextself.previous 的吸气剂。

但是,PyCharm 对我大喊大叫,因为我试图将 next 称为 next(some_node, direction=-1)。这样做的正确方法是什么?

【问题讨论】:

  • 你不能随便给魔法方法添加任意参数,你需要匹配数据模型定义。如果你想以另一种方式提供迭代器,那就是__reversed__

标签: python python-3.x iterator


【解决方案1】:

除了__iter__,还有__reversed__。两者都必须返回iterators__next__ 方法应该在 iterators 上实现(而不是在节点类上)。请注意,所有魔术方法(当被 next 之类的函数调用而不是直接调用时)都需要实现 预期参数,而不是更多 - 而不是更少。

例如,双向链表可以只实现__iter____reversed__ 并依赖节点的nextprevious 属性:

class Node(object):
    def __init__(self, val, nxt, prv):
        self.val = val
        self.nxt = nxt
        self.prv = prv


class DoublyLinkedList(object):
    def __init__(self, base=None, last=None):
        self.base = base
        self.last = last

    def prepend(self, val):
        new = Node(val, self.base, None)
        if self.base is None:
            self.base = new
            self.last = new
        else:
            self.base.prv = new
            self.base = new

    def append(self, val):
        new = Node(val, None, self.last)
        if self.last is None:
            self.base = new
            self.last = new
        else:
            self.last.nxt = new
            self.last = new

    def __iter__(self):
        current = self.base
        while current is not None:
            yield current
            current = current.nxt

    def __reversed__(self):
        current = self.last
        while current is not None:
            yield current
            current = current.prv

例如:

dl = DoublyLinkedList()
dl.prepend(10)
dl.prepend(20)
dl.prepend(30)

for i in dl:
    print(i.val)

给予:

30
20
10

reversed 类似:

for i in reversed(dl):
    print(i.val)

# prints:
10
20
30

【讨论】:

  • 谢谢,这真的很有帮助。
【解决方案2】:

__next__iterator protocol 的一部分,应该按照上述协议中的说明使用,否则只会对其余 python 产生问题。

在您的情况下,只需将函数重命名为简单的next 并用作some_node.next(-1),尽管我会将direction 参数更改为布尔值,因为这就是您使用它的方式,也是它的名称。比如这样

class None: 
    ...

    def next(self, forward:bool=True) -> Union['Node', None]:
        if forward:
            return self.get_next()
        else:
            return self.get_previous()

并用作some_node.next()some_node.next(False) 甚至some_node.next(0)(使用 0 代替 False 以获得相同的效果)

【讨论】:

    【解决方案3】:

    next 的额外参数是默认值,__next__ 不接受任何额外参数。 Python 没有任何类型的双向迭代器。如果你的界面和for i in obj:不完全一样,那么你应该自己写。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-05
      • 2019-02-02
      • 2011-03-27
      • 2020-10-17
      • 2017-06-19
      • 2019-11-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多