Python:我可以在可变对象上编写多态交换吗?
(目前)缔约国: 对于语言是否支持引用传递语义,有一个简单的“石蕊测试”: 你能用这种语言写一个传统的交换(a,b)方法/函数吗 传统的交换方法或函数接受两个参数并交换它们,以便传递到函数中的变量在函数外部更改 AFAIK,在Python中,不可变对象上的“传统交换函数”是不允许的。但是可变对象呢?出于好奇,我编写了以下测试:Python:我可以在可变对象上编写多态交换吗?,python,parameter-passing,pass-by-reference,swap,mutable,Python,Parameter Passing,Pass By Reference,Swap,Mutable,(目前)缔约国: 对于语言是否支持引用传递语义,有一个简单的“石蕊测试”: 你能用这种语言写一个传统的交换(a,b)方法/函数吗 传统的交换方法或函数接受两个参数并交换它们,以便传递到函数中的变量在函数外部更改 AFAIK,在Python中,不可变对象上的“传统交换函数”是不允许的。但是可变对象呢?出于好奇,我编写了以下测试: # Pythonic way to swap variables (l1, l2) = ([1], [2]) (l1, l2) = (l2, l1) assert (l
# Pythonic way to swap variables
(l1, l2) = ([1], [2])
(l1, l2) = (l2, l1)
assert (l1, l2) == ([2], [1])
# This doesn't work inside a function,
# since new bindings are created and discarded
def failed_swap(a, b):
(a, b) = (b, a)
(l1, l2) = ([1], [2])
failed_swap(l1, l2)
assert (l1, l2) == ([1], [2])
# Working swap function (procedure) on lists
def swap_lists(a, b):
aux = a[:]
a[:] = b[:]
b[:] = aux[:]
(l1, l2) = ([1], [2])
swap_lists(l1, l2)
assert (l1, l2) == ([2], [1])
# The same thing on dicts and sets, thanks to duck typing
def swap_dicts_or_sets(a, b):
aux = a.copy()
a.clear()
a.update(b)
b.clear()
b.update(aux)
(s1, s2) = ({1}, {2})
swap_dicts_or_sets(s1, s2)
assert (s1, s2) == ({2}, {1})
(d1, d2) = ({"foo": 1}, {"bar": 2})
swap_dicts_or_sets(d1, d2)
assert (d1, d2) == ({"bar": 2}, {"foo": 1})
所以,我似乎可以在至少一些可变类型上编写一些专门的“传统掉期”
对1的回答类似于“Python总是通过对对象的常量引用来使用传递参数” 第2个问题的答案是:不,您不能用一般的方法来做,要找到一些反例,假设您想交换树中的2个节点:
r
/ \
a b
/
c
并且说
c
知道它的父对象是a
;在你做了“泛型交换”之后,代码> C <代码>仍然认为对象<代码> a < /代码>是它的父,但是<代码> a <代码>会认为它没有子和<代码> b>代码>考虑<代码> c>代码>为子。< 1 >回答“Python总是使用常数引用对象的传递参数”。
第2个问题的答案是:不,您不能用一般的方法来做,要找到一些反例,假设您想交换树中的2个节点:
r
/ \
a b
/
c
并且说
c
知道它的父对象是a
;在你做了“泛型交换”之后,代码> C <代码>仍然认为对象<代码> a < /代码>是它的父,但是<代码> a <代码>会认为它没有子和<代码> b>代码>考虑<代码> c>代码>为子。< 1 >回答“Python总是使用常数引用对象的传递参数”。
第2个问题的答案是:不,您不能用一般的方法来做,要找到一些反例,假设您想交换树中的2个节点:
r
/ \
a b
/
c
并且说
c
知道它的父对象是a
;在你做了“泛型交换”之后,代码> C <代码>仍然认为对象<代码> a < /代码>是它的父,但是<代码> a <代码>会认为它没有子和<代码> b>代码>考虑<代码> c>代码>为子。< 1 >回答“Python总是使用常数引用对象的传递参数”。
第2个问题的答案是:不,您不能用一般的方法来做,要找到一些反例,假设您想交换树中的2个节点:
r
/ \
a b
/
c
并且说
c
知道它的父对象是a
;在你做了“泛型交换”之后,代码> C >代码>仍然认为对象<代码> a <代码>是它的父,但是<代码> a <代码>会认为它没有子和<代码> b>代码>考虑<代码> c>代码>作为它的子。你正在做的是交换这些对象的内容。该函数之外的变量仍然引用它们以前引用的相同对象。只需在调用swap函数之前和之后对这些变量中的任何一个调用id
。所以不,没有“传统交换”。你在那里做的是交换那些对象的内容。该函数之外的变量仍然引用它们以前引用的相同对象。只需在调用swap函数之前和之后对这些变量中的任何一个调用id
。所以不,没有“传统交换”。你在那里做的是交换那些对象的内容。该函数之外的变量仍然引用它们以前引用的相同对象。只需在调用swap函数之前和之后对这些变量中的任何一个调用id
。所以不,没有“传统交换”。你在那里做的是交换那些对象的内容。该函数之外的变量仍然引用它们以前引用的相同对象。只需在调用swap函数之前和之后对这些变量中的任何一个调用id
。所以没有,没有“传统交换”。