为什么迭代器在Python文档中被认为是函数式的?

时间:2016-03-17 15:20:21

标签: python iterator scheme

我试图理解迭代器。我注意到Python documentation认为迭代器是一个功能样式的构造。我真的不明白。

迭代器内部是否有状态是不是真的。所以当你调用it.__next__()时,你会改变迭代器的状态。据我所知,对象的变异状态不被认为是功能性的,因为函数式编程强调对象/闭包的不变性和组合能力。

实际上,问题出现了,因为我想编写一个Scheme过程/函数来获取标记并返回一个迭代器。

(define tokens->iterator
  (lambda ls
    (lambda ()
      (if (null? ls)
          '*eoi*
          (let ((tok (car ls)))
            (set! ls (cdr ls))
            tok)))))

注意我必须使用set!来改变ls,这就是我提出这个问题的方法。

要使用它,

(define it (tokens->iterator 1 '+ 2))

要测试它,

scheme@(guile-user)> (it)
$2 = 1
scheme@(guile-user)> (it)
$3 = +
scheme@(guile-user)> (it)
$4 = 2
scheme@(guile-user)> (it)
$5 = *eoi*
scheme@(guile-user)> (it)
$6 = *eoi*

为了好玩,我还将其翻译成Python:

def tokens_to_iterator(*tup):
    ls = list(tup)
    def iterator():
        if not ls:
            return "*eoi*"
        else:
            tok = ls.pop(0)
            return tok
    return iterator

类似地,pop()方法通过改变列表来删除并返回第一个元素。

要使用它,

it = tokens_to_iterator(1, "+", 2)

要测试它,

>>> it()
1
>>> it()
'+'
>>> it()
2
>>> it()
'*eoi*'
>>> it()
'*eoi*'

有人可以澄清一下吗?顺便说一句,我正在使用Python 3和Guile Scheme,以防任何人有兴趣尝试这些例子。

2 个答案:

答案 0 :(得分:8)

你有一个很好的观点。迭代器肯定不是"纯功能,"该术语通常用于描述完全不使用突变的习语。更广泛的术语"功能性,"但是,更宽松的定义是指示使用相对较少的突变的程序,使用高阶和一等函数,或许最广泛的,"使用看起来不像的奇怪的抽象C"

坦率地说,我认为我调用迭代器功能。那就是:我同意你的看法。

答案 1 :(得分:3)

功能样式用于处理整个数据列表,而不是可以随心所欲地更改的值集合。例如,如果您有一个数字列表,并且想要更改第三个元素,那么非功能性方法是直接更改它:

>>> lst = ["a", "b", "c", "d", "e"]
>>> lst[3] = "Z"
>>> lst
["a", "b", "c", "Z", "e"]

功能方法是编写一个函数,该函数接受原始序列并返回一个包含所做更改的新列表,使原始序列保持不变。

>>> lst = ["a", "b", "c", "d", "e"]
>>> new_lst = [x if i != 3 else "Z" for (i, x) in enumerate(lst)]
>>> lst
["a", "b", "c", "d", "e"]
>>> new_lst
["a", "b", "c", "Z", "e"]

你的两个迭代器都没有纯粹的功能,因为它们确实保持了可变状态,虽然它们被视为一个黑盒子,你可以在功能上使用它们,因为迭代器的 user 不能直接影响那个状态。

纯函数迭代器将是一个函数,它将列表作为输入作为当前状态,并返回一个值一个新状态传递给下一个调用函数。

>>> state = 0
>>> def it(lst, state):
...   if state is None:
...       return None
...   return lst[state], state + 1
...
>>> lst = ["a", "b", "c", "d", "e"]
>>> value, new_state = it(lst, state)
>>> value
'a'
>>> state, new_state
(0, 1)
>>> it(lst, new_state)
('b', 2)
>>> state, new_state
(0, 1)