Функция простой замены 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