为什么这个Python脚本偶尔会递归?

时间:2012-11-16 17:39:34

标签: python infinite-loop

我正在教自己Python,并写了一个小脚本来交换圣诞礼物(这不是作业)。我的家人喜欢每个人给同一性别的一个人送一份礼物。以下脚本大部分时间都在工作,但有时会因无限递归而失败。我不知道为什么,因为我认为基本情况最终会得到满足。

import random

family = {'Joe': 'm', 'Jane': 'f', 'John': 'm', 'Jill': 'f', 'James': 'm', 'Jade': 'f'}
receivers = family.copy()
givers = family.copy()

def match(giver):
    index = random.randrange(len(receivers))
    giverGender = givers[giver]
    receiver = receivers.keys()[index]
    receiverGender = receivers.values()[index]

    if giver != receiver and giverGender == receiverGender:
        del receivers[receiver]
        return giver + ' to ' + receiver
    else:
        return match(giver)

# main program
for i in givers:
    print match(i)

这是错误(编辑添加完整错误):

Traceback (most recent call last):
  File "C:\...\christmasGifts.py", line 22, in <module>
    print match(i)
  File "C:\...\christmasGifts.py", line 18, in match
    return match(giver)

  ...

  File "C:\...\christmasGifts.py", line 18, in match
    return match(giver)
  File "C:\...\christmasGifts.py", line 9, in match
  index = random.randrange(len(receivers))
  File "C:\Python27\lib\random.py", line 184, in randrange
istart = int(start)
RuntimeError: maximum recursion depth exceeded while calling a Python object

感谢您的帮助。

5 个答案:

答案 0 :(得分:6)

首先让我们考虑女性。如果您的程序运行并且将Jane与Jill匹配,那么将Jill与Jane匹配,Jane是唯一的女性,因为她无法匹配自己,您的程序无限期地运行而没有匹配。

让我提出一种解决问题的替代方法。随机地改变你的送礼者/收据的顺序,并让每个人在列表中给下面的人送礼物,并让列表中的最后一个人送给第一个人。这看起来像这样:

from random import shuffle
women = ['Jane', 'Jill', 'Jade']
shuffle(women)
print women[-1] + ' to ' + women[0]
for i in range(len(women) - 1):
    print women[i] + ' to ' + women[i+1]

答案 1 :(得分:2)

Jane对Jill和Jill对Jane

Jade是谁给的?

答案 2 :(得分:0)

以下是脚本的简单迭代变体。它运作得很好。

作为一个假设我认为,基于概率论,有时你只需要调用匹配函数太多次,因此它会导致程序达到递归限制

import random

family = {'Joe': 'm', 'Jane': 'f', 'John': 'm', 'Jill': 'f', 'James': 'm', 'Jade': 'f'}
receivers = family.copy()
givers = family.copy()

def match(giver):
    giverGender = givers[giver]

    Found = False
    while not Found:
        index = random.randrange(len(receivers))
        receiver = receivers.keys()[index]
        receiverGender = receivers.values()[index]
        if giver != receiver and giverGender == receiverGender:
            Found = True
            del receivers[receiver]
    return giver + ' to ' + receiver


# main program
if __name__=='__main__':
    for i in givers:
        print match(i)

答案 3 :(得分:0)

有一种稍微容易理解的方法:

from itertools import izip_longest
from random import shuffle

family = {
    'Joe': 'm',
    'Jane': 'f',
    'John': 'm',
    'Jill': 'f',
    'James': 'm',
    'Jade': 'f'
}

females = [k for k, v in family.iteritems() if v == 'f']
for num in range(5):
    shuffle(females) # muck up the order a bit
    print list(izip_longest(females, females[1:], fillvalue=females[0]))

[('Jade', 'Jill'), ('Jill', 'Jane'), ('Jane', 'Jade')]
[('Jane', 'Jill'), ('Jill', 'Jade'), ('Jade', 'Jane')]
[('Jade', 'Jane'), ('Jane', 'Jill'), ('Jill', 'Jade')]
[('Jade', 'Jane'), ('Jane', 'Jill'), ('Jill', 'Jade')]
[('Jill', 'Jane'), ('Jane', 'Jade'), ('Jade', 'Jill')]

答案 4 :(得分:0)

下面的版本实际上允许更多的选择可能性。

from random import randint

giver = ['Jane', 'Jill', 'Jade', 'Nicole', 'Charlotte']

receiver = [i for i in giver]

def match(giver, receiver):
    for i in giver:

        #get random receiver
        rec = receiver[randint(0,len(receiver)-1)]

        #check to see if only two remain, so person doesn't pick self in loop.
        if len(receiver) == 2:
            rec = receiver[1]

        #make sure person doesn't select themself.
        while i == rec:
            rec = receiver[randint(0,len(receiver)-1)]

        print i + " gives to " + rec
        #reduce receiver pool
        receiver.remove(rec)

编辑:我不知何故认为这会破坏在感恩节时从帽子上画画的乐趣....:)