Python: могу ли я написать полиморфный своп на изменяемые объекты?

Этот пост в блоге (в настоящее время обсуждается в 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 ответ

Ответом на 1 является что-то вроде "Python всегда использует передаваемые аргументы при постоянной ссылке на объекты".

Ответ 2: нет, вы не можете сделать это в общем виде, чтобы найти несколько контрпримеров, предположим, что вы хотите поменять 2 узла в дереве:

    r
   / \
  a   b
 /
c

и скажи что c знает, что его родитель a; после того, как вы сделали свой "общий обмен", c все равно будет думать, что объект a является его родителем, но a Казалось бы, у него нет детей и b рассматривать c как его ребенок.

Другие вопросы по тегам