
练习17:使用用户定义的方法实现栈
我们将继续上个练习中的栈主题。但这个练习中我们将自己实现append和pop函数。这个练习的目的有两个:一方面,我们将用实际生活中的一个例子实现这个栈,这个例子还涉及字符串方法的知识,因此可以作为上一章内容和活动的重温;另一方面,它将向我们展示Python的一个微妙特性,以及它如何将列表变量传递给函数,并将带我们进入下一个练习,函数编程。
1.首先定义两个函数:stack_push和stack_pop。我们对它们进行了重命名,这样就不会发生名称空间之间的冲突。另外,创建一个名为url_stack的栈供以后使用:

2.第一个函数获取已经存在的栈,并在其末尾添加值。
说明
注意value周围的方括号,为了+操作,它将其转换为只有一个元素的列表。
3.第二个函数读取当前位于栈的-1索引处的值,然后使用del运算符删除该索引,最后返回先前读取的值。
4.现在我们有一串包含几个URL的字符串。我们的工作是分析该字符串,以便在遇到栈中的URL时逐个推送它们,最后使用for循环逐个弹出它们。让我们从维基百科中关于数据科学的文章开始:

5.为了简化这个练习,我们将目标单词之外的链接用方括号括了起来。
6.查找字符串的长度:

输出如下:

7.使用字符串中的split方法将此字符串转换为列表,然后计算其长度:

输出如下:

8.使用for循环遍历每个单词并检查它是否是URL。为此,我们将使用字符串中的startswith方法,如果它是URL,则将其推入栈:

9.输出url_stack中的值:

输出如下:

10.迭代列表并使用stack_pop函数逐个打印URL:

输出如图2-2所示。

图2-2 使用栈输出的URL
11.再次打印以确保在for循环之后栈为空:

输出如下:

我们注意到stack_pop方法中有一个奇怪的现象。我们在这里传递了列表变量,并在函数内部使用了del运算符,但是每次调用函数时,它都会删除最后一个索引,从而改变了原始变量。如果你熟悉C语言、C++语言和Java语言,那么这是一个完全出乎意料的行为。在这些语言中,只有当我们通过引用传递变量时这些行为才会发生,而且它能在Python代码中引起微小的错误,所以要小心。通常,在函数内部改变一个变量的值并不是一个好主意。传递给函数的任何变量都应该被认为是不可变的,这接近于函数式编程的原理。Python中的Lambda表达式是一种构造单行无名称函数的方法,这些函数按照约定是无副作用的。