48 votes

Ordre de déballage des tuples change les valeurs attribuées

Je pense que les deux sont identiques.

 nums = [1, 2, 0]    
nums[nums[0]], nums[0] = nums[0], nums[nums[0]]    
print nums  # [2, 1, 0]

nums = [1, 2, 0]    
nums[0], nums[nums[0]] = nums[nums[0]], nums[0]    
print nums  # [2, 2, 1] 
 

Mais les résultats sont différents.
Pourquoi les résultats sont-ils différents? (pourquoi le second résultat?)

46voto

Bhargav Rao Points 20835

Conditions préalables - 2 Points importants

  • Les listes sont mutable

    La partie principale dans les listes, c'est que les listes sont mutables. Cela signifie que l' les valeurs de listes peuvent être modifiées. C'est l'un de la raison pour laquelle vous êtes face à la difficulté. Consultez la documentation pour plus d'info

  • Ordre d'Évaluation

    L'autre partie est que pendant le déballage d'un n-uplet, le début de l'évaluation de gauche à droite. Consultez la documentation pour plus d'info


Introduction

lorsque vous effectuez a,b = c,d les valeurs de c et d sont d'abord stockées. Puis à partir de la gauche, la valeur de a est d'abord changé d' c , puis la valeur de b est changé en d.

Le hic, c'est que si il y a des effets secondaires liés à l'emplacement de b tandis que l'évolution de la valeur de a, alors d est attribué au plus tard b, ce qui est l' b touchés par les effets secondaires de l' a.


Cas D'Utilisation

Maintenant, pour en venir à votre problème

Dans le premier cas,

nums = [1, 2, 0]    
nums[nums[0]], nums[0] = nums[0], nums[nums[0]]    

nums[0] est initialement 1 et nums[nums[0]] est 2 parce qu'il évalue à l' nums[1]. Donc 1,2 est maintenant enregistré dans la mémoire.

Maintenant tuple déballage qui se passe du côté gauche, de sorte

nums[nums[0]] = nums[1] = 1   # NO side Effect. 
nums[0] = 2

par conséquent print nums imprime [2, 1, 0]

Toutefois, dans ce cas

nums = [1, 2, 0]   
nums[0], nums[nums[0]] = nums[nums[0]], nums[0]    

nums[nums[0]], nums[0] met 2,1 sur la pile tout comme le premier cas.

Cependant, sur le côté gauche, c'est - nums[0], nums[nums[0]], l'évolution de l' nums[0] a un effet secondaire tel qu'il est utilisé comme index dans nums[nums[0]]. Ainsi

nums[0] = 2
nums[nums[0]] = nums[2] = 1  # NOTE THAT nums[0] HAS CHANGED

nums[1] reste inchangé à valeur 2. par conséquent print nums imprime [2, 2, 1]

18voto

eph Points 1486

Vous pouvez définir une classe pour suivre le processus:

class MyList(list):
    def __getitem__(self, key):
        print('get ' + str(key))
        return super(MyList, self).__getitem__(key)
    def __setitem__(self, key, value):
        print('set ' + str(key) + ', ' + str(value))
        return super(MyList, self).__setitem__(key, value)

Pour la première méthode:

nums = MyList([1, 2, 0])
nums[nums[0]], nums[0] = nums[0], nums[nums[0]]

la sortie est:

get 0
get 0
get 1
get 0
set 1, 1
set 0, 2

Tandis que la seconde méthode:

nums = MyList([1, 2, 0])
nums[0], nums[nums[0]] = nums[nums[0]], nums[0]

la sortie est:

get 0
get 1
get 0
set 0, 2
get 0
set 2, 1

Dans les deux méthodes, les trois premières lignes sont liées à un tuple de la génération, tandis que les trois dernières lignes sont liées à des affectations. Côté droit tuple de la première méthode est - (1, 2) et la deuxième méthode est - (2, 1).

Dans l'étape de l'assignation, la première méthode get nums[0] qui 1, et définissez nums[1] = 1, alors nums[0] = 2, deuxième méthode attribuer nums[0] = 2, puis obtenir de l' nums[0] qui 2, et finalement mis en nums[2] = 1.

10voto

Kasramvd Points 32864

C'est à cause de cela python attribution de la priorité est de gauche à droite.Donc, dans le code suivant:

 nums = [1, 2, 0]
 nums[nums[0]], nums[0] = nums[0], nums[nums[0]]

D'abord affecté à l' nums[0] de nums[nums[0]] moyen nums[1]==1 puis comme les listes sont des objets mutables les nums serait :

[1,1,0]

et puis, nums[nums[0]] sera attribuée nums[0] ce qui signifie nums[0]==2 et de :

nums = [2,1,0]

Et comme pour la deuxième partie.

Notez que le point important ici est que les objets de la liste sont mutables et quand vous le changez dans un segment de code, il peut être changer de place. ainsi, il aura une incidence sur le reste du code.

Ordre d'évaluation

Python évalue les expressions de gauche à droite. Notez que, bien que l'évaluation d'une cession, le côté droit est évalué avant le côté gauche.

3voto

Dans le premier exemple, nums [1] est défini sur 1, puis sur nums [0] sur 2, comme vous pouvez vous attendre.

Dans le deuxième exemple, nums [0] est défini sur 2, puis nums [2] sur 1. Cela est dû au fait que, dans la partie gauche, nums [nums [0]] fait réellement référence à nums [2 ] lorsque l'assignation se produit, car nums [0] venait tout juste d'être réglé sur 2.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X