Python与C#中的递归行为 - 奇怪的结果

时间:2017-12-11 23:53:30

标签: c# python recursion

我是一位经验丰富的程序员但不熟悉Python,所以我不知道我在这里看到的是我特有的Python行为,而我并不知道。我通常使用C ++和C#编程,因此我在两种语言中都包含了代码示例以演示不同的结果。

我正在做的是运行递归搜索功能,使用状态结构来记录结果。在C#中它的行为与预期的一样,但在Python中它似乎(据我所知),不区分当前/最后一次递归调用中存在的状态。我知道Python通过引用管理对象(如在C#中) - 我在对对象进行深入复制之前将其进一步传递给搜索函数。

首先提供C#版本和结果:

class SimState
{
    public List<string> stateDescriptions = new List<string>();
    public SimState Clone()
    {
        return new SimState() {
            stateDescriptions = new List<string>(this.stateDescriptions)
        };            
    }
}
class Program
{
    public void search_recursive(SimState state,int move,int recurseDepth)
    {
        if (recurseDepth > 2)
            return;
        state.stateDescriptions.Add(move.ToString());
        Console.WriteLine(String.Format("{0}: {1}", 
            recurseDepth,
            String.Join(",", state.stateDescriptions)));
        for(int n = 0;n < 2;n++)
        {
            var newState = state.Clone();
            this.search_recursive(newState, n + 1, recurseDepth + 1);
        }
    }
    static void Main(string[] args)
    {
        var initialState = new SimState();
        new Program().search_recursive(initialState, 0, 0);
        Console.ReadKey();
    }
}

结果:这就是我期望发生的事情。它将所有组合搜索到最大值。深度为2:

0: 0
1: 0,1
2: 0,1,1
2: 0,1,2  
1: 0,2
2: 0,2,1
2: 0,2,2

到目前为止一切顺利。现在,我认为是一个等效的Python程序:

import copy

class SimState:
    stateDescriptions = []

def search_recursive(state: SimState, move, recurseDepth):
    if(recurseDepth > 2):
        return
    state.stateDescriptions.append('{0}'.format(move))
    print('{0}: '.format(recurseDepth) +  ','.join(state.stateDescriptions))
    for n in range(2):
        newState = copy.deepcopy(state)
        search_recursive(newState,n + 1,recurseDepth + 1)

initialState = SimState()
search_recursive(initialState,0,0)

结果:

0: 0
1: 0,1
2: 0,1,1
2: 0,1,1,2
1: 0,1,1,2,2
2: 0,1,1,2,2,1
2: 0,1,1,2,2,1,2

似乎Python没有意识到我传入一个全新的状态(通过新的深度复制&#39; newState&#39;),而是更新现有的&# 39;状态&#39;来自之前的递归调用。我很清楚SO&#34; "Least Astonishment" and the Mutable Default Argument&#34;)上的帖子,但这似乎是指默认参数,这里没有使用。

我在Visual Studio 2017中使用Python 3.6。

我错过了一些明显的东西吗?感谢

1 个答案:

答案 0 :(得分:3)

问题是你的班级定义。您在Python中编写的内容创建了一个类变量,可能来自C#背景,可以说它会创建一个&#34;静态属性&#34;。无论如何,您需要一个实例属性,如下所示:

In [2]: import copy
   ...:
   ...: class SimState:
   ...:     def __init__(self):
   ...:         self.stateDescriptions = []
   ...:
   ...: def search_recursive(state: SimState, move, recurseDepth):
   ...:     if(recurseDepth > 2):
   ...:         return
   ...:     state.stateDescriptions.append('{0}'.format(move))
   ...:     print('{0}: '.format(recurseDepth) +  ','.join(state.stateDescriptions))
   ...:     for n in range(2):
   ...:         newState = copy.deepcopy(state)
   ...:         search_recursive(newState,n + 1,recurseDepth + 1)
   ...:
   ...: initialState = SimState()
   ...: search_recursive(initialState,0,0)
   ...:
0: 0
1: 0,1
2: 0,1,1
2: 0,1,2
1: 0,2
2: 0,2,1
2: 0,2,2

另外,我不确定你的意思&#34; python通过引用管理对象&#34;,但Python 不支持call-by-reference 语义。它的语义类似于Java - 除了Python是一种纯OOP语言,没有原始类型,一切都是一个对象(所以,它就像Java,除了一切是一个引用类型) 。此策略在技术上称为call by object sharing