使用Python增量赋值时的发现~~那些易被忽略的细节

为了不因为一上来就是一大堆概念导致看不下去,我还是先举个栗子吧:

代码源自 http://www.python.org/doc/essays/graphs/

'''http://www.python.org/doc/essays/graphs/'''
graph = {'A': ['B', 'C'],
         'B': ['C', 'D'],
         'C': ['D'],
         'D': ['C'],
         'E': ['F'],
         'F': ['C']   
         }

def find_all_paths(graph, start, end, path=[]):
    path = path + [start]
    if start == end:
        return [path]
    if not graph.has_key(start):
        return []
    paths = []
    for node in graph[start]:
        if node not in path:
            newpaths = find_all_paths(graph, node, end, path)
            for newpath in newpaths:
                paths.append(newpath)
    return paths

print find_all_paths(graph, 'A', 'D')

程序输出为:

>>>[['A', 'B', 'C', 'D'], ['A', 'B', 'D'], ['A', 'C', 'D']]
但是如果我把find_all_paths函数的第一行
path = path + [start]
换成
path += [start]
再运行程序,输出为:
>>>[['A', 'B', 'C', 'D']]
啊咧~说好的正确答案呢。

其实发现这个问题是在学习设计模式时遇到的,出问题的代码是这里:http://www.pythontip.com/pythonPatterns/detail/graph_search

正上方链接的例子里其实还有一点问题:self.start,self.end,self.path这样写真的大丈夫?self.xxx是实例属性,在方法中给其赋值,会改变他的值,而且此处的方法还是个递归方法,当某一层的递归返回时,它的上一层方法里的对象属性self.xxx却被修改了,出错是必须的,以上。好的,继续说这个+=的问题。

为什么会出现+=的结果出错呢,这里让我引经据典一下(具体内容来自《Python核心编程(第二版)》第42~43页):

P42“在Python语言中,对象是通过引用传递的,在赋值时,不管这个对象是新创建的,还是一个已经存在的,都是将该对象的引用(并不是值)赋值给变量。”

P43“增量赋值相对普通赋值不仅是写法上的改变,最有意义的变化是第一个对象仅被处理一次。可变对象会被就地修改(无修拷贝引用)[注:无修是神马,推测可能是想说无需。。],不可变对象则和A=A+B的结果一样(分配一个新对象),...”

也就是说 例:A=[1];A+=[2];那么A还是那个A(也就是id(A)没变)

而A=[1];A = A+[2];此时A不是以前的那个A了,而是一个新分配的对象(id(A)变了)

很坑爹对不对,对不对,竟然还有这样的小细节,说起来真得感谢http://www.pythontip.com这个网站的朋友(非嘲讽,真心感谢)。

回到find_all_paths这个函数,传入参数时,函数参数是否可变的问题。

1.若传入不可变类型,比如int类型,那么在函数中对该int类型进行+=操作也会生成新的int对象(参见上方P43的引用)

2若是传入可变类型就是另一回事了。因为path是可变类型list,所以作为函数参数传入后,如果使用path = path + xxx,那么新的path对象产生,一切OK;但是若使用path+=xxx,那么直接修改了该path对象的值(让我想起了以前与C指针战斗的日子,多么怀念。。。)

第一次写博文,不知道有没有讲清楚,反正先就这样吧。:)

你可能感兴趣的:(python,赋值,增量赋值)