美文网首页我的Python之旅程序员生活不易 我用python
一则算法题引出的关于Python函数参数和变量的思考

一则算法题引出的关于Python函数参数和变量的思考

作者: resolvewang | 来源:发表于2017-05-10 13:35 被阅读136次

在逛segmentfault的时候,看到一个比较有意思的算法题:python怎么获得二叉树根到所有叶子的路径?

然后题主贴出了自己的代码,大概就是这样子的

class TreeNode:
    def __init__(self, val):
        self.val = val
        self.left, self.right = None, None
def dfs(node, result, tmp):
    if node == None:
        return 
    tmp.append(node)
    if node.left == None and node.right == None:
        result.append([i.val for i in tmp])
        return
    dfs(node.left, result, tmp)
    dfs(node.right, result, tmp)

问题提得还是很规矩,该告知的信息都告知了,所以忍不住想回答一下。

初看这段代码,不知道大家是否能立刻察觉到这段代码有一些很值得注意的地方。嗯,就是他在函数传参的时候使用了列表。在初学Python的时候,无论是书上还是大神的博客上,都告诉我们,不要使用可变参数作为函数参数,否则参数会保持上一次被改变的状态。现在回过头来看看上面给出的代码,tmpresult在每次递归调用后,它们的状态都会被改变。result的改变是我们可以预见并且也是期望的,但是tmp却不好控制。如果我们在遍历左子树的时候把tmp当成参数传到下一次的递归调用中,然后当我们遍历右子树的时候,其添加了左子树的状态还在,所以会出现『tmp数组会保留之前遍历完左子树的状态』这个问题,知道了问题,那么剩下的就是找方法解决这个问题了。

由于左子树和右子树遍历不能互相影响,所以光用一个tmp是不行的,需要一份它的拷贝,注意,这里的拷贝如果只是简单的tmp1 = tmp赋值的话,你会发现效果还是和前面的一样,因为tmp1tmp指向了同一块地址。对于tmp1和tmp任意一个的修改都会影响对方。正确的做法是使用copy模块的copy或者deepcopy,也就是常说的浅拷贝和深拷贝。两者也是有一些区别的,浅拷贝会把原来的内容都做一份拷贝,如果原来的内容中有可变对象,它会持有该对象的引用,无论是原来的变量或者拷贝的对象对可变对象的改动都会影响到另外一个,而深拷贝不会存在这个问题,它会把所有内容的值都拷贝一份,包括可变对象。比如

>>>a = [1, 2, [3, 4]]
>>>import copy
>>>b = copy.copy(a)
>>>b
[1, 2, [3, 4]]
>>> b[1] = 5
>>>b
[1, 5, [3, 4]]  # 修改后的b
>>> a
[1, 2, [3, 4]]  # 改变不可变对象,那么原对象不受影响
>>>b[2].append(5)
>>>b
[1, 5, [3, 4, 5]] # 当前b的值
>>>a
[1, 2, [3, 4, 5]]  # a 被b的操作影响了,浅拷贝『共享可变对象』

而如果是deepcopy,可以看看同样的操作产生的结果

>>>a = [1, 2, [3, 4]]
>>>b = copy.deepcopy(a)
>>>b
[1, 2, [3, 4]]
>>>b[2].append(5)
>>>b
[1, 2, [3, 4, 5]]  # b当前的值
>>>a
[1, 2, [3, 4]]    # a当前的值并不会受到影响,深拷贝不会共享可变对象

最后贴上改正过后的代码,『遍历获取二叉树的所有可达路径』

import copy


class TreeNode:
    def __init__(self, val):
        self.val = val
        self.left, self.right = None, None


def dfs(node, result, tmp=list()):
    if node is None:
        return

    tmp.append(node)
    tmp1 = copy.copy(tmp)

    if node.left is None and node.right is None:
        result.append([i.val for i in tmp])
        return

    if node.left is not None:
        dfs(node.left, result, tmp)
    if node.right is not None:
        dfs(node.right, result, tmp1)

相关文章

  • 一则算法题引出的关于Python函数参数和变量的思考

    在逛segmentfault的时候,看到一个比较有意思的算法题:python怎么获得二叉树根到所有叶子的路径? 然...

  • 由闭包引出的垃圾回收

    由闭包引出的垃圾回收 闭包的特性 函数嵌套函数 函数内部可以引用外部的参数和变量 参数和变量不会被垃圾回收机制回收...

  • 第5天-python基础-函数与模块

    定义函数 Python中每个函数都有自己的名字、自变量和因变量。我们通常把Python中函数的自变量称为函数的参数...

  • 高阶函数(Python)

    什么是高阶函数(Python)? 高阶函数:能接收函数做参数的函数 变量可以指向函数 函数的参数可以接受变量 一个...

  • 17、关于python中必须掌握的知识点记忆

    1、 关于python中带下划线的变量和函数的意义参考文档 关于python中带下划线的变量和函数的意义 http...

  • 07:函数之函数的参数和返回值

    python学习day_6: 函数之函数的参数和返回值: 1、函数的参数: 参数:其实就是一种变量 是一种特殊的变...

  • Python实战:函数

    Python中函数的声明格式: 例如: 函数的调用: 关于位置参数、关键字参数、可变参数和不可变参数 位置参数:参...

  • Python名词以及对应解释

    高阶函数 python的变量可以指向函数,函数的变量可以接受参数,那么一个函数就可以接受另一个函数作为参数传入,这...

  • python编程(三级)5、核心函数

    python3内置函数表 对象操作函数 dir()不带参数时返回当前范围内的变量,方法和定义的类型列表,带参数时返...

  • 变量理解

    01. 变量的引用 变量 和 数据 都是保存在 内存 中的在 Python 中 函数 的 参数传递 以及 返回值 ...

网友评论

    本文标题:一则算法题引出的关于Python函数参数和变量的思考

    本文链接:https://www.haomeiwen.com/subject/jevwtxtx.html