web-dev-qa-db-fra.com

Fonction d'échange simple Python

Je suis tombé sur ce problème en essayant d’apprendre le python. Considérons la fonction suivante:

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

Que vont imprimer s1 et s2?

Après avoir exécuté le problème, j'ai constaté que l'instruction print imprimera 1 2. Il semble que les valeurs de s1 et s2 n'aient pas changé par rapport à la fonction swap0. La seule explication à laquelle je pouvais penser était à cause de la ligne.

tmp = s1[:]

Puisque s1 [:] est une copie, cela signifie que la valeur de s1 ne changera pas dans l'appel de fonction. Cependant, étant donné que le paramètre swap0 est (s1, s2), je ne sais pas si après avoir effectué tmp = s1 [:]. Chaque fois que je fais

s1 = something...

ce sera une référence à la copie de s1, au lieu de s1 elle-même. Quelqu'un peut-il offrir une meilleure explication? Merci.

10
Rhs

C'est parce qu'il attribue de nouvelles valeurs à s1 et s2 dans la fonction swap0. Ces assignations ne se propagent pas en dehors de la fonction. Vous verrez que cela fonctionne si vous copiez et collez simplement le corps de la fonction à la place de l'appel de la fonction.

Vous pouvez contourner ce problème en modifiant les objets référencés par les arguments, plutôt que les arguments eux-mêmes:

def swap0(s1, s2):
    assert type(s1) == list and type(s2) == list
    tmp = s1[:]
    s1[:] = s2
    s2[:] = tmp

Cependant, la méthode la plus simple et la plus efficace pour effectuer un échange en Python est simplement:

s1, s2 = s2, s1

Cela aussi ne fera qu'échanger ces références particulières avec les listes, mais pas le contenu de la liste elle-même.

22
Thomas

Dans l’état actuel, votre print finale imprimera les valeurs originales de s1 et s2. En effet, vous ne les échangez que dans le cadre de la fonction. Cela n'affectera pas leurs valeurs en dehors de la fonction (c'est-à-dire après que leurs valeurs après l'appel de la fonction)

S'il s'agit de types mutables (list, set, dict, etc.), vous pouvez les modifier sur place dans swap. Cependant, cela limite swap à travailler uniquement sur les types mutables.

Il est donc préférable de renvoyer les entrées dans l'ordre inverse:

def swap(s1, s2):
    return s2, s1

s1 = 'a'
s2 = 'b'
s1, s2 = swap(s1, s2)
print s1, s2 # prints 'b a'

Bien sûr, vous pouvez le faire en une seule ligne comme suit:

s1, s2 = s2, s1

À votre santé!

11
inspectorG4dget

Les autres réponses expliquent ce qui ne va pas. Voici une version qui fait ce que vous voulez:

def swap(s1, s2):
    assert isinstance(s1, list) and isinstance(s2, list)
    s1[:], s2[:] = s2[:], s1[:]

Voir aussi: isinstance vs. type

6
Zero Piraeus

Dans la fonction, vous reliez local variables s1 et s2 avec les valeurs du côté droit (qui sont également locales car vous utilisez des découpes pour créer des copies). Même si vous modifiez le contenu de ces variables locales, vous ne modifiez pas le contenu des listes de l'étendue d'appel, car elles ne font plus référence aux mêmes listes.

4
mgilson

Voici une fonction d'une ligne qui permet d'atteindre votre objectif:

swap = lambda x: (x[1], x[0])
2
parallelogram

Vous pouvez également le faire en utilisant l'ancienne méthode d'échange en utilisant l'indexation et la boucle si les deux listes ont la même longueur. C'est un peu la vieille école, mais cela aidera à comprendre l'indexation 

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)

Cela donnera la sortie comme:

 [0,9,8,7,6,5,4,3,2,1]
 [1,2,3,4,5,6,7,8,9,0]

Ou cela peut aussi être fait en utilisant Xor. L'opérateur Xor est un opérateur au niveau des bits qui effectue l'opération Xor entre les opérandes, par exemple.

a = 5 #0b101
b = 4 #0b100
c = a ^ b #0b001

Ici 0b101 est une représentation binaire de 5 et 0b100 est une représentation binaire de 4 et lorsque vous Xor, vous obtenez le résultat sous la forme 0b001, c.-à-d. 1. Xou renvoie 1 résultat en sortie si une et une seule des entrées est 1. Si les deux entrées sont 0 ou les deux sont 1, les résultats en sortie . Nous pouvons échanger deux variables en utilisant Xor, par exemple:

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

La sortie sera a = 9 and b = 5 

De même, nous pouvons également échanger deux listes en effectuant X ou une opération sur leurs éléments, par exemple:

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)

Sortie:

[0, 9, 8, 7, 6, 5, 4, 3, 2, 1]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]

Prenons un autre scénario, Que se passe-t-il si nous devons échanger les éléments de la liste, par exemple: Nous avons une liste comme celle-ci x = [ 13, 3, 7, 5, 11, 1 ] et nous devons échanger son article comme suit x = [ 1, 3, 5, 7 , 11, 13 ] faites cela en utilisant deux opérateurs au niveau du bit Xor ^ et Compliments ~ 

Code:

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

Donc, la sortie sera [1, 3, 5, 7, 11, 13]

2
Devil-oper

vous pouvez avoir ceci:

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
1
a_m_dev