我刚遇到一个棘手的问题。以下代码应该将单词拆分为长度为numOfChar
的块。该函数调用自身,这使得无法在函数内部生成结果列表(res
)。但是如果我把它作为全局变量保留在外面,那么每次后续调用具有不同输入值的函数都会导致错误的结果,因为res
没有被清除。
任何人都可以帮助我吗?
这是代码 (如果您有兴趣,这是problem 7-23 from PySchools.com):
res = []
def splitWord(word, numOfChar):
if len(word) > 0:
res.append(word[:numOfChar])
splitWord(word[numOfChar:], numOfChar)
return res
print splitWord('google', 2)
print splitWord('google', 3)
print splitWord('apple', 1)
print splitWord('apple', 4)
答案 0 :(得分:5)
纯递归函数不应该修改全局状态,这算作副作用。
不要追加和递归,而是试试这个:
def splitWord(word, numOfChar):
if len(word) > 0:
return [word[:numOfChar]] + splitWord(word[numOfChar:], numOfChar)
else:
return []
在这里,你将这个单词一次一块地切成碎片,然后在每次通话的同时下去,然后在上升时将这些碎片重建成一个列表。
这是一种名为tail recursion的常见模式。
P.S。正如@e-satis所述,递归不是在Python中执行此操作的有效方法。另请参阅@e-satis's answer以获得更精细的尾递归示例,以及使用生成器解决问题的更多Pythonic方法。
答案 1 :(得分:2)
这里完全不需要递归:
def splitWord(word, numOfChar):
return [word[i:i+numOfChar] for i in xrange(0, len(word), numOfChar)]
如果你坚持使用递归解决方案,那么最好避免使用全局变量(它们使得真的难以理解正在发生的事情)。这是一种方法:
def splitWord(word, numOfChar):
if len(word) > 0:
return [word[:numOfChar]] + splitWord(word[numOfChar:], numOfChar)
else:
return []
答案 2 :(得分:2)
详细说明@Helgi答案,这是一个更高效的递归实现。它更新列表而不是对两个列表求和(这导致每次都创建一个新对象)。
此模式强制您将列表对象作为第三个参数传递。
def split_word(word, num_of_chars, tail):
if len(word) > 0:
tail.append(word[:num_of_chars])
return split_word(word[num_of_chars:], num_of_chars, tail)
return tail
res = split_word('fdjskqmfjqdsklmfjm', 3, [])
这种形式的另一个优点是它允许尾递归优化。它在Python中没用,因为它不是一种执行这种优化的语言,但如果你把这段代码翻译成Erlang或Lisp,你就可以免费获得它。
请记住,在Python中,你受到递归堆栈的限制,并且没有办法解决它。这就是递归不是首选方法的原因。
您最有可能使用yield
和itertools
(一个模块来操纵生成器)来使用生成器。这是一个可以拆分任何可迭代块的函数的一个很好的例子:
from itertools import chain, islice
def chunk(seq, chunksize, process=iter):
it = iter(seq)
while True:
yield process(chain([it.next()], islice(it, chunksize - 1)))
如果你开始学习Python,现在有点复杂,所以我不希望你现在完全掌握它,但你可以看到它并且知道它存在是很好的。稍后你会再回过头来看看(我们都做过,Python迭代工具最初都是压倒性的。)
这种方法的好处是:
要获得与您的功能相同的结果,您可以:
In [17]: list(chunk('fdjskqmfjqdsklmfjm', 3, ''.join))
Out[17]: ['fdj', 'skq', 'mfj', 'qds', 'klm', 'fjm']