使用包装程序在Python / Javascript中模仿按引用传递-良好做法?

时间:2018-11-15 05:15:55

标签: javascript python pass-by-value

说我想在函数内部修改数字或其他一些原语。例如,如下所示(注意:伪代码):

// apply fn to every value in a tree, in-order traversal
function treeReduce (tree, fn, result):
    if (tree == undefined) return
    treeReduce(tree.left, fn, result)
    result = fn(result, tree.value)
    treeReduce(tree.right, fn, result)

sum = 0
treeReduce(myTree, +, sum)

显然这是行不通的,因为result仅被重新分配,而传入的sum将看不到修改。因此,我解决此问题的通用方法(在任何传递值的语言(如Python或Javascript)中都使用包装器:

// apply fn to every value in a tree, in-order traversal
function treeReduce (tree, fn, result):
    if (tree == undefined) return
    treeReduce(tree.left, fn, result)
    result[0] = fn(result[0], tree.value)
    treeReduce(tree.right, fn, result)

sumWrapper = [0]
treeReduce(myTree, +, sumWrapper)

但是,我最近在互联网上搜索了这是否是一种常见模式,并且找不到太多有关此模式的信息。具体来说,我想知道三件事:

  1. 这是常见的模式吗?
  2. 这是好习惯吗?
  3. 如果没有,还有其他选择吗?

1 个答案:

答案 0 :(得分:2)

可以像这样完成 ,但是它会增加"sideeffects"的功能,大多数编码人员建议尽量减少这些功能。相反,您可以为其使用函数的 return 值。然后,您的代码仍将传递“ previous”(或“ start”)值作为原始值,但返回结果。

这是它在JS中的外观(我花了一些平凡的fn来演示它执行了有序执行):

// apply fn to every value in a tree, in-order traversal
function treeReduce (tree, fn, start) {
    if (tree === undefined) return start
    let result = treeReduce(tree.left, fn, start)
    result = fn(result, tree.value)
    result = treeReduce(tree.right, fn, result)
    return result
}

let myTree = { value: 1, left: { value: 2 }, right: { value: 3 } }

let result = treeReduce(myTree, (a,b) => a*a+b, 0)
console.log(result)

请注意,以上内容现在可以写得更简洁:

// apply fn to every value in a tree, in-order traversal
function treeReduce (tree, fn, start) {
    return !tree ? start
        : treeReduce(tree.right, fn, fn(treeReduce(tree.left, fn, start), tree.value))
}

let myTree = { value: 1, left: { value: 2 }, right: { value: 3 } }

let result = treeReduce(myTree, (a,b) => a*a+b, 0)
console.log(result)

在Python中:

import collections
Tree = collections.namedtuple('Tree', ['value', 'left', 'right'])

# apply fn to every value in a tree, in-order traversal
def treeReduce (tree, fn, start):
    return start if not tree else ( 
        treeReduce(tree.right, fn, fn(treeReduce(tree.left, fn, start), tree.value))
    )

myTree = Tree(1, Tree(2,None,None), Tree(3,None,None))

result = treeReduce(myTree, lambda a,b: a*a+b, 0)

print(result)

JS和Python都允许将其扩展到需要设置多个原始值的情况:函数可以返回数组/列表/元组/对象,然后可以通过将它们解压缩/分解为单独的变量来进行赋值。