@@ -272,3 +272,71 @@ True
272
272
列表推导式使用序列的接口约定增强了数据处理的范式,因为列表是一种序列数据类型。
273
273
274
274
** 扩展阅读。** Dive Into Python 3 的[ 推导式] ( http://diveintopython3.ep.io/comprehensions.html ) 一章包含了一些示例,展示了如何使用 Python 浏览计算机的文件系统。这一章介绍了` os ` 模块,它可以列出目录的内容。这个材料并不是这门课的一部分,但是推荐给任何想要增加 Python 知识和技巧的人。
275
+
276
+ ** 实现。** 列表是序列,就像元组一样。Python 语言并不提供给我们列表实现的直接方法,只提供序列抽象,和我们在这一节介绍的可变方法。为了克服这一语言层面的抽象界限,我们可以开发列表的函数式实现,再次使用递归表示。这一节也有第二个目的:加深我们对调度函数的理解。
277
+
278
+ 我们会将列表实现为函数,它将一个递归列表作为自己的局部状态。列表需要有一个身份,就像任何可变值那样。特别地,我们不能使用` None ` 来表示任何空的可变列表,因为两个空列表并不是相同的值(例如,向一个列表添加元素并不会添加到另一个),但是` None is None ` 。另一方面,两个不同的函数足以区分两个两个空列表,它们都将` empty_rlist ` 作为局部状态。
279
+
280
+ 我们的可变列表是个调度函数,就像我们偶对的函数式实现也是个调度函数。它检查输入“信息”是否为已知信息,并且对每个不同的输入执行相应的操作。我们的可变列表可响应五个不同的信息。前两个实现了序列抽象的行为。接下来的两个添加或删除列表的第一个元素。最后的信息返回整个列表内容的字符串表示。
281
+
282
+ ``` py
283
+ >> > def make_mutable_rlist ():
284
+ """ Return a functional implementation of a mutable recursive list."""
285
+ contents = empty_rlist
286
+ def dispatch (message , value = None ):
287
+ nonlocal contents
288
+ if message == ' len' :
289
+ return len_rlist(contents)
290
+ elif message == ' getitem' :
291
+ return getitem_rlist(contents, value)
292
+ elif message == ' push_first' :
293
+ contents = make_rlist(value, contents)
294
+ elif message == ' pop_first' :
295
+ f = first(contents)
296
+ contents = rest(contents)
297
+ return f
298
+ elif message == ' str' :
299
+ return str (contents)
300
+ return dispatch
301
+ ```
302
+
303
+ 我们也可以添加一个辅助函数,来从任何内建序列中构建函数式实现的递归列表。只需要以递归顺序添加每个元素。
304
+
305
+
306
+ ``` py
307
+ >> > def to_mutable_rlist (source ):
308
+ """ Return a functional list with the same contents as source."""
309
+ s = make_mutable_rlist()
310
+ for element in reversed (source):
311
+ s(' push_first' , element)
312
+ return s
313
+ ```
314
+
315
+ 在上面的定义中,函数` reversed ` 接受并返回可迭代值。它是使用序列的接口约定的另一个示例。
316
+
317
+ 这里,我们可以构造函数式实现的列表,要注意列表自身也是个函数。
318
+
319
+ ``` py
320
+ >> > s = to_mutable_rlist(suits)
321
+ >> > type (s)
322
+ < class ' function' >
323
+ >> > s(' str' )
324
+ " ('heart', ('diamond', ('spade', ('club', None))))"
325
+ ```
326
+
327
+ 另外,我们可以像列表` s ` 传递信息来修改它的内容,比如移除第一个元素。
328
+
329
+ ``` py
330
+ >> > s(' pop_first' )
331
+ ' heart'
332
+ >> > s(' str' )
333
+ " ('diamond', ('spade', ('club', None)))"
334
+ ```
335
+
336
+ 原则上,操作` push_first ` 和` pop_first ` 足以对列表做任意修改。我们总是可以清空整个列表,之后将它旧的内容替换为想要的结果。
337
+
338
+ ** 消息传递。** 给予一些时间,我们就能实现许多实用的 Python 列表可变操作,比如` extend ` 和` insert ` 。我们有一个选择:我们可以将它们全部实现为函数,这会使用现有的消息` pop_first ` 和` push_first ` 来实现所有的改变操作。作为代替,我们也可以向` dispatch ` 函数体添加额外的` elif ` 子句,每个子句检查一个消息(例如` 'extend' ` ),并且直接在` contents ` 上做出合适的改变。
339
+
340
+ 第二个途径叫做消息传递,它把数据值上面所有操作的逻辑封装在一个函数中,这个函数响应不同的消息。一个使用消息传递的程序定义了调度函数,每个函数都拥有局部状态,通过传递“消息”作为第一个参数给这些函数来组织计算。消息是对应特定行为的字符串。
341
+
342
+ 可以想象,在` dispatch ` 的函数体中通过名称来枚举所有这些消息非常无聊,并且易于出现错误。Python 的字典提供了一种数据类型,会帮助我们管理消息和操作之间的映射,它会在下一节中介绍。
0 commit comments