这是我的Stack实现。
class Stack:
def __init__(self):
self.head = None
self.size = 0
def push(self, item):
node = Node(item)
if not self.head:
self.head = node
else:
node.next = self.head
self.head = node
self.size += 1
def pop(self):
if self.size == 0:
raise ValueError('Popping off an empty stack!')
item = self.head.val
self.head = self.head.next
return item
def peek(self):
if self.size == 0:
raise ValueError('Peeking into an empty stack!')
return self.head.val
def __iter__(self):
return self
def __next__(self):
if self.head:
curr = self.head
else:
raise StopIteration()
self.head = self.head.next
return curr.val
class Node:
def __init__(self, val):
self.val = val
self.next = None
if __name__ == '__main__':
stack = Stack()
stack.push(12)
stack.push(13)
stack.push(9)
for item in stack:
print(item)
print(stack.peek())
这个问题就是迭代。迭代是破坏性的,因此在迭代结束时调用窥视会引发错误。
return self.head.val
AttributeError: 'NoneType' object has no attribute 'val'
如何使迭代非破坏性?
答案 0 :(得分:2)
因为在同一个堆栈上可以有多个迭代器,__iter__
必须返回迭代堆栈的迭代器对象:
class Stack:
def __init__(self):
self.head = None
self.size = 0
def push(self, item):
node = Node(item)
if self.head:
node.next = self.head
self.head = node
self.size += 1
def pop(self):
if self.size == 0:
raise ValueError('Popping off an empty stack!')
item = self.head.val
self.head = self.head.next
return item
def peek(self):
if self.size == 0:
raise ValueError('Peeking into an empty stack!')
return self.head.val
def __iter__(self):
return StackIterator(self.head)
class StackIterator:
def __init__(self, head):
self.head = head
def __iter__(self):
return self
def __next__(self):
if not self.head:
raise StopIteration()
item = self.head.val
self.head = self.head.next
return item
答案 1 :(得分:2)
问题是你在 iterable Stack本身和__iter__
应该返回的迭代器之间没有区别。应该在所述迭代器上调用__next__
,而不是Stack
本身。
我提出以下解决方案:
class StackIterator:
def __init__(self, stack):
self.head = stack.head
def __iter__(self):
return self
def __next__(self):
if not self.head:
raise StopIteration
current = self.head
self.head = self.head.next
return current.val
摆脱__next__
中的Stack
并将__iter__
调整为:
def __iter__(self):
return StackIterator(self)
演示:
>>> stack = Stack()
>>> stack.push(12)
>>> stack.push(13)
>>> stack.push(9)
>>>
>>> for x in stack:
... print(x)
...
9
13
12
>>> stack.peek()
9
答案 2 :(得分:2)
一种简单的方法,可以为Stack提供一个可用于迭代的替代头。我还添加了一个__len__
方法来返回Stack的大小。
class Stack:
def __init__(self):
self.head = None
self.size = 0
def __len__(self):
return self.size
def push(self, item):
node = Node(item)
if not self.head:
self.head = node
else:
node.next = self.head
self.head = node
self.size += 1
def pop(self):
if self.size == 0:
raise ValueError('Popping off an empty stack!')
item = self.head.val
self.head = self.head.next
return item
def peek(self):
if self.size == 0:
raise ValueError('Peeking into an empty stack!')
return self.head.val
def __iter__(self):
self.top = self.head
return self
def __next__(self):
if self.top:
curr = self.top
else:
raise StopIteration()
self.top = self.top.next
return curr.val
class Node:
def __init__(self, val):
self.val = val
self.next = None
if __name__ == '__main__':
stack = Stack()
stack.push(12)
stack.push(13)
stack.push(9)
print('Size', len(stack))
for item in stack:
print(item)
print(stack.peek())
stack.push(42)
print('Size', len(stack))
for item in stack:
print(item)
<强>输出强>
Size 3
9
13
12
9
Size 4
42
9
13
12
将self.top = None
添加到__init__
可能是一个好主意,尽管并非绝对必要。您可能希望将其标记为带有前导下划线的私人名称:self._top
。
正如timgeb在评论中所暗示的那样,这种方法有点脆弱,因为我们只能在堆栈上一次执行一次迭代,因为我们只有一个self.top
。
顺便说一句,您可以稍微优化push
方法:
def push(self, item):
node = Node(item)
if self.head:
node.next = self.head
self.head = node
self.size += 1