Функция простой замены Python
Я столкнулся с этой проблемой при попытке изучить python. Рассмотрим следующую функцию:
def swap0(s1, s2):
assert type(s1) == list and type(s2) == list
tmp = s1[:]
s1 = s2[:]
s2 = tmp
return
s1 = [1]
s2 = [2]
swap0(s1, s2)
print s1, s2
Что будут печатать s1 и s2?
После выполнения проблемы я обнаружил, что оператор печати будет печатать 1 2. Кажется, что значение s1 и s2 не изменилось из функции swap0
. Единственное объяснение, о котором я мог думать, было из-за линии.
tmp = s1[:]
Так как s1 [:] является копией, имеет смысл, что значение s1 не будет меняться в вызове функции. Однако, поскольку параметр swap0
равен (s1, s2), я не уверен, что после выполнения tmp = s1 [:]. Каждый раз, когда я делаю
s1 = something...
это будет ссылка на копию s1, а не на s1. Может ли кто-нибудь предложить лучшее объяснение? Спасибо.
Ответы
Ответ 1
Это потому, что он назначает новые значения s1
и s2
внутри функции swap0
. Эти назначения не распространяются вне функции. Вы увидите, что он работает, если вы просто копируете и вставляете тело функции вместо вызова функции.
Вы можете обойти это, изменив объекты, на которые ссылаются аргументы, а не сами аргументы:
def swap0(s1, s2):
assert type(s1) == list and type(s2) == list
tmp = s1[:]
s1[:] = s2
s2[:] = tmp
Однако, проще и лучше сделать обмен в Python просто:
s1, s2 = s2, s1
Это тоже будет заменять эти конкретные ссылки на списки, но не сами содержимое списка.
Ответ 2
Как бы то ни было, ваш окончательный print
распечатает исходные значения s1
и s2
. Это связано с тем, что вы только меняете их в рамках функции. Это не повлияет на их значения вне функции (т.е. После их значений после вызова функции)
Если они являются изменяемыми типами (list
, set
, dict
и т.д.), вы можете изменить их на месте внутри swap
. Тем не менее, это ограничивает swap
работать только с изменяемыми типами.
Поэтому вам лучше возвращать входы в обратном порядке:
def swap(s1, s2):
return s2, s1
s1 = 'a'
s2 = 'b'
s1, s2 = swap(s1, s2)
print s1, s2 # prints 'b a'
Конечно, вы можете сделать это все в одной строке следующим образом:
s1, s2 = s2, s1
Ура!
Ответ 3
Другие ответы объясняют, что происходит не так. Здесь версия, которая делает то, что вы хотите:
def swap(s1, s2):
assert isinstance(s1, list) and isinstance(s2, list)
s1[:], s2[:] = s2[:], s1[:]
Смотрите также: isinstance vs. type
Ответ 4
Внутри функции вы привязываете локальные переменные s1
и s2
со значениями в правой части (которые также являются локальными, так как вы используете срезы для копирования). Даже если вы измените содержимое этих локальных переменных, вы не измените содержимое списков в области вызова, потому что они больше не относятся к тем же спискам.
Ответ 5
Вот однострочная функция, которая выполняет вашу задачу:
swap = lambda x: (x[1], x[0])
Ответ 6
Вы также можете сделать это с помощью старого метода swaping, используя индексирование и цикл, если оба списка имеют одинаковую длину. Это своего рода старая школа, но поможет понять индексирование
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
b = [0, 9, 8, 7, 6, 5, 4, 3, 2, 1]
for i in range(0, len(a)):
a[i] = a[i] + b[i]
b[i] = a[i] - b[i]
a[i] = a[i] - b[i]
print(a)
print(b)
Это даст результат как:
[0,9,8,7,6,5,4,3,2,1]
[1,2,3,4,5,6,7,8,9,0]
Или это также можно сделать с помощью Xor. Оператор Xor является побитовым оператором, который выполняет операцию Xor между операндами, например.
a = 5 #0b101
b = 4 #0b100
c = a ^ b #0b001
Здесь 0b101
является двоичным представлением 5, а 0b100
является двоичным представлением 4, а когда вы XOR, вы будете в качестве 0b001
i.e 1. Xor возвращает 1 выход, если один и только один из входов - 1. Если оба входа равны 0 или оба имеют результат 1, 0.
Мы можем поменять две переменные с помощью Xor, например:
a = 5 # 0b0101
b = 9 # 0b1001
a = a ^ b # Xor (0b0101, 0b1001) = 0b1100 (12)
b = a ^ b # Xor (0b1100, 0b1001) = 0b0101 (5)
a = a ^ b # Xor (0b1100, 0b0101) = 0b1001 (9)
print("a = {} and b = {}".format(a, b))
Выход будет a = 9 and b = 5
Аналогичным образом мы также можем поменять два списка, выполнив операцию Xor там, например:
a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 ]
b = [ 0, 9, 8, 7, 6, 5, 4, 3, 2, 1 ]
for i in range(0, len(a)) :
a[i] = a[i] ^ b[i]
b[i] = a[i] ^ b[i]
a[i] = a[i] ^ b[i]
print(a)
print(b)
Вывод:
[0, 9, 8, 7, 6, 5, 4, 3, 2, 1]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
Давайте возьмем другой сценарий. Что делать, если нам нужно поменять элементы в списке, например:
у нас есть список, подобный этому x = [ 13, 3, 7, 5, 11, 1 ]
, и нам нужно поменять его таким образом x = [ 1, 3, 5, 7 , 11, 13 ]
. Таким образом, мы можем сделать это, используя два побитовых оператора Xor ^
и Compliments ~
Код:
# List of items
a = [ 13, 3, 7, 5, 11, 1 ]
# Calculated the length of list using len() and
# then calulated the middle index of that list a
half = len(a) // 2
# Loop from 0 to middle index
for i in range(0, half) :
# This is to prevent index 1 and index 4 values to get swap
# because they are in their right place.
if (i+1) % 2 is not 0 :
#Here ~i means the compliment of i and ^ is Xor,
# if i = 0 then ~i will be -1
# As we know -ve values index the list from right to left
# so a [-1] = 1
a[i] = a[i] ^ a[~i]
a[~i] = a[i] ^ a[~i]
a[i] = a[i] ^ a[~i]
print(a)
Таким образом, вывод будет [1, 3, 5, 7, 11, 13]
Ответ 7
у тебя может быть это:
def swap(x , y):
x , y = y , x
return x , y
x = 5
y = 10
print ('x is {0} and y is {1}'.format(x,y)) # x is 5 and y is 10
x , y = swap(x,y) # doing swap
print ('x is {0} and y is {1}'.format(x,y)) # x is 10 and y is 5
Ответ 8
Там нет необходимости для функции вообще. a, b = b, a делает свое дело.
>>> a,b=1,2
>>> print (a,b)
(1, 2)
>>> a,b=b,a
>>> print (a,b)
(2, 1)
>>>
Это работает и для массивов. Но если вы так хотите, функция здесь
def swap(a,b)
return b,a