Python:我可以在可变对象上编写多态交换吗?

时间:2015-03-22 08:31:47

标签: python parameter-passing pass-by-reference swap mutable

This blog post(目前discussed on Hacker News)声明:

  

对于语言是否支持传递引用语义,有一个简单的“试金石”:

     

你能用语言写一个传统的swap(a,b)方法/函数吗?

     

传统的交换方法或函数接受两个参数并交换它们,以便传递给函数的变量在函数外部更改。

AFAIK,在Python中,对不可变对象的“传统交换函数”是禁忌。但是可变对象呢?出于好奇,我写了以下测试:

# 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. 如果是这样,我可以编写一个与任何可变对象一起使用的通用“传统交换”吗?

1 个答案:

答案 0 :(得分:3)

对1的回答类似于“Python总是使用通过常量引用传递参数”。

对2的回答是:不,你不能以通用的方式去做,找一些反例,假设你想在树中交换2个节点:

    r
   / \
  a   b
 /
c

并说c知道其父级是a;在您执行“通用互换”后,c仍会认为对象a是其父级,但a会认为它没有子级而b认为c 1}}作为它的孩子。