使用包装器在 Python/Javascript 中模仿引用传递 - 好的做法?
Mimicking Pass-By-Reference in Python/Javascript Using Wrappers - Good Practice?
假设我想修改函数内部的数字或其他原语。例如,像这样的东西(注意:伪代码):
// 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)
不过,我最近在网上搜索了这是否是一种常见模式,但找不到太多关于它的信息。具体来说,我想知道三件事:
- 这是常见模式吗?
- 这是好的做法吗?
- 如果没有,还有其他选择吗?
它 可以 那样做,但是它会增加 "sideeffects" 你的功能,大多数编码人员会建议尽可能减少。相反,您可以为它使用函数的 return 值。然后,您的代码仍会将 "previous"(或 "start")值作为原始值传递,但会传递 return 结果。
这是它在 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 也允许将其扩展到需要设置多个原始值的情况:函数可以 return arrays/lists/tuples/objects,然后可以由unpacking/destructuring 将它们分成单独的变量。
假设我想修改函数内部的数字或其他原语。例如,像这样的东西(注意:伪代码):
// 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)
不过,我最近在网上搜索了这是否是一种常见模式,但找不到太多关于它的信息。具体来说,我想知道三件事:
- 这是常见模式吗?
- 这是好的做法吗?
- 如果没有,还有其他选择吗?
它 可以 那样做,但是它会增加 "sideeffects" 你的功能,大多数编码人员会建议尽可能减少。相反,您可以为它使用函数的 return 值。然后,您的代码仍会将 "previous"(或 "start")值作为原始值传递,但会传递 return 结果。
这是它在 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 也允许将其扩展到需要设置多个原始值的情况:函数可以 return arrays/lists/tuples/objects,然后可以由unpacking/destructuring 将它们分成单独的变量。