用Python编写手动pop函数

用Python编写手动pop函数,python,python-3.x,Python,Python 3.x,在我开始之前: import sys sys.ps1 = "<?>> " 导入系统 sys.ps1=“>” 嗯。 作为一名C程序员,我不能不以任何方式(用我选择的任何语言)保持敏锐,但要编写低级程序。今天,一个问题来自Python3中一个非常简单的例子 在将一个小pop()写入堆栈类时,我收到了一些奇怪的输出 class Stack(): def __init__(self, data): self.stack = [i for i in data

在我开始之前:

import sys
sys.ps1 = "<?>> "
导入系统 sys.ps1=“>” 嗯。 作为一名C程序员,我不能不以任何方式(用我选择的任何语言)保持敏锐,但要编写低级程序。今天,一个问题来自Python3中一个非常简单的例子

在将一个小pop()写入堆栈类时,我收到了一些奇怪的输出

class Stack():

    def __init__(self, data):
        self.stack = [i for i in data]
        self.size = int(len(self.stack))

    def pop(self):
        ch = self.stack[self.size - 1]
        del(self.stack[-1])
        self.size = self.size - 1
        return ch


msg = Stack("Hello!")
for i in msg.stack:
    print(m.pop(), end="")

<?>> !ol

for i in msg.stack:
    print(m.pop(), end="")

<?>> le

for i in msg.stack:
    print(m.pop(), end="")

<?>> H

print(msg.stack)

<?>> []
类堆栈():
定义初始化(自身,数据):
self.stack=[i代表数据中的i]
self.size=int(len(self.stack))
def pop(自我):
ch=自堆栈[self.size-1]
del(自堆栈[-1])
self.size=self.size-1
返回ch
msg=Stack(“你好!”)
对于msg.stack中的i:
打印(m.pop(),end=“”)
> !ol
对于msg.stack中的i:
打印(m.pop(),end=“”)
>乐
对于msg.stack中的i:
打印(m.pop(),end=“”)
>H
打印(msg.stack)
> []

如您所见,弹出并输出整个列表需要3个循环['H'、'e'、'l'、'l'、'o'];3个字符,然后2个,然后1个,但是列表会相应地耗尽吗?更长的输入需要更多的循环。这里起作用的抑制因素是什么?

问题的根本在于,在修改容器时,您正在对其进行迭代。这样考虑一下,在内部,
列表
迭代器只是不断推进索引,直到它碰到
索引器
。由于您修改了列表,在您从列表中删除3个元素后,它会点击索引器,因为它将尝试
my\u list[3]
,但
len(my\u list)==3
。有几种方法可以解决这个问题。首先,在这种情况下只需使用while循环:

In [4]: class Stack:
   ...:
   ...:     def __init__(self, data):
   ...:         self.stack = [i for i in data]
   ...:         self.size = int(len(self.stack))
   ...:
   ...:     def pop(self):
   ...:         ch = self.stack[self.size - 1]
   ...:         del(self.stack[-1])
   ...:         self.size = self.size - 1
   ...:         return ch
   ...:     def __len__(self):
   ...:         return self.size
   ...:

In [5]: stack = Stack("Hello!")

In [6]: while stack:
   ...:     print(stack.pop(), end='')
   ...:
!olleH
注意,我定义了一个
\uuu len\uu
方法,以便
while stack:
直接工作,而不是
while stack.size:

正如您所想,您还可以简单地在范围对象上循环:

In [7]: stack = Stack("Hello!")

In [8]: for _ in range(len(stack)):
   ...:     print(stack.pop(), end='')
   ...:
!olleH
更棘手的是:反向循环!由于从末尾弹出,因此不会得到
索引器
,因为
列表反转器
在到达
列表[0]
之前,从
列表[len(alist)-1]
开始索引。依赖这种行为我可能会感到不舒服,但它是有文档记录的,并且确实有效:

In [9]: stack = Stack("Hello!")

In [10]: for _ in reversed(stack.stack):
    ...:     print(stack.pop(), end='')
    ...:
!olleH
In [11]:
最后,经过验证的:在副本上循环:


如果我对范围内的I使用
(len(msg.stack))
,它不需要3个循环就可以工作,但这让我更加好奇为什么不这样做它就不能相应地工作。因为您正在对基础列表进行迭代,即msg.stack中的I使用
,但是for循环中的列表大小正在改变,相反,您可以使用while循环来实现所看到的行为(跳过元素):
while msg.size:msg.pop()
,或者在迭代过程中要小心(如果您正在迭代的容器发生变化,则总是很混乱),这似乎更像是一个需要注意的警告<代码>我没有遵循我认为在循环中会遵循的规则。至少我现在明白了,谢谢。这是一个多么深刻的回答啊+(如果可以的话)谢谢你。这个问题实际上是在我创建不同的反向迭代器时出现的。关于Python的神奇方法,我还有很多东西要学;您说过列表将继续迭代,直到到达IndexError。这与说
raisestopIteration
@基本上是类似的吗?问题是实际上有两个迭代器协议,一个涉及
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu涉及
\uuu getitem\uuu
索引器
,虽然这主要是为了不破坏旧代码,但它们的工作原理类似
In [11]: stack = Stack("Hello!")

In [12]: for _ in stack.stack[:]: #whole slice copies
    ...:     print(stack.pop(), end='')
    ...:
!olleH