简体   繁体   中英

Python: can I write a polymorphic swap on mutable objects?

This blog post (currently discussed on Hacker News ) states:

There's a simple "litmus test" for whether a language supports pass-by-reference semantics:

Can you write a traditional swap(a,b) method/function in the language?

A traditional swap method or function takes two arguments and swaps them such that variables passed into the function are changed outside the function.

AFAIK, in Python, a "traditional swap function" on immutable objects is a no-no. But what about mutable objects? Out of curiosity, I wrote the following tests:

# 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})

So, it seems that I could write some specialized "traditional swaps" on at least some mutable types.

  1. Terminology: does this mean that Python supports pass-by-reference semantics on any mutable object?
  2. If so, can I write a generic "traditional swap" working with any mutable objects?

Answer to 1 is something like "Python always uses pass arguments by constant reference to objects ".

Answer to 2 is: no, you cannot do it in a generic way, to find some counter-examples, suppose that you want to swap 2 nodes in a tree:

    r
   / \
  a   b
 /
c

and say that c knows its parent is a ; after you did your "generic swap", c would still think that the object a is its parent, but a would think it has no children and b consider c as its child.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM