35 votes

Syntaxe de découpage de liste Python utilisée sans raison évidente

Je vois occasionnellement la syntaxe de la tranche de liste utilisée dans le code Python comme ceci :

newList = oldList[:]

C'est sûrement la même chose que :

newList = oldList

Ou est-ce que je rate quelque chose ?

52voto

[:] Copies superficielles la liste, en faisant une copie de la structure de la liste contenant des références aux membres de la liste originale. Cela signifie que les opérations sur la copie n'affectent pas la structure de l'original. Toutefois, si vous effectuez des opérations sur les membres de la liste, les deux listes y font toujours référence, de sorte que les mises à jour seront visibles si l'on accède aux membres par l'intermédiaire de l'original.

A Copie profonde ferait également des copies de tous les membres de la liste.

L'extrait de code ci-dessous montre une copie superficielle en action.

# ================================================================
# === ShallowCopy.py =============================================
# ================================================================
#
class Foo:
    def __init__(self, data):
        self._data = data

aa = Foo ('aaa')
bb = Foo ('bbb')

# The initial list has two elements containing 'aaa' and 'bbb'
OldList = [aa,bb]
print OldList[0]._data

# The shallow copy makes a new list pointing to the old elements
NewList = OldList[:]
print NewList[0]._data

# Updating one of the elements through the new list sees the
# change reflected when you access that element through the
# old list.
NewList[0]._data = 'xxx'
print OldList[0]._data

# Updating the new list to point to something new is not reflected
# in the old list.
NewList[0] = Foo ('ccc')
print NewList[0]._data
print OldList[0]._data

L'exécuter dans un shell python donne la transcription suivante. Nous pouvons voir la est faite avec des copies des anciens objets. Un des objets peut avoir son état mis à jour par référence à travers l'ancienne liste, et les mises à jour peuvent être mises à jour sont visibles lorsque l'on accède à l'objet via l'ancienne liste. Enfin, la modification d'une dans la nouvelle liste ne se reflète pas dans l'ancienne liste, car la nouvelle liste fait maintenant référence à un objet différent.

>>> # ================================================================
... # === ShallowCopy.py =============================================
... # ================================================================
... #
... class Foo:
...     def __init__(self, data):
...         self._data = data
...
>>> aa = Foo ('aaa')
>>> bb = Foo ('bbb')
>>>
>>> # The initial list has two elements containing 'aaa' and 'bbb'
... OldList = [aa,bb]
>>> print OldList[0]._data
aaa
>>>
>>> # The shallow copy makes a new list pointing to the old elements
... NewList = OldList[:]
>>> print NewList[0]._data
aaa
>>>
>>> # Updating one of the elements through the new list sees the
... # change reflected when you access that element through the
... # old list.
... NewList[0]._data = 'xxx'
>>> print OldList[0]._data
xxx
>>>
>>> # Updating the new list to point to something new is not reflected
... # in the old list.
... NewList[0] = Foo ('ccc')
>>> print NewList[0]._data
ccc
>>> print OldList[0]._data
xxx

48voto

Deinumite Points 1488

Comme l'a dit NXC, les noms de variables Python pointent en fait vers un objet, et non vers un endroit spécifique de la mémoire.

newList = oldList créerait deux variables différentes qui pointent vers le même objet, donc, modifier oldList changerait également newList .

Cependant, lorsque vous faites newList = oldList[:] il "découpe" la liste et crée une nouvelle liste. Les valeurs par défaut de [:] sont 0 et la fin de la liste, donc il copie tout. Il crée donc une nouvelle liste avec toutes les données contenues dans la première, mais les deux peuvent être modifiées sans que l'autre ne le soit.

12voto

Dan Points 4107

Comme il y a déjà été répondu, je vais simplement ajouter une simple démonstration :

>>> a = [1, 2, 3, 4]
>>> b = a
>>> c = a[:]
>>> b[2] = 10
>>> c[3] = 20
>>> a
[1, 2, 10, 4]
>>> b
[1, 2, 10, 4]
>>> c
[1, 2, 3, 20]

4voto

kaleissin Points 577

Ne pensez jamais que "a = b" en Python signifie "copier b en a". S'il y a des variables des deux côtés, vous ne pouvez pas vraiment le savoir. Pensez plutôt que cela signifie "donner à b le nom supplémentaire a".

Si b est un objet immuable (comme un nombre, un tuple ou une chaîne), alors oui, l'effet est que vous obtenez une copie. Mais c'est parce que lorsque vous traitez avec des immuables (qui auraient peut-être dû être appelés lecture seulement , immuable o WORM ) vous toujours obtenir une copie, par définition.

Si b est un mutable, vous il faut toujours faire quelque chose de plus pour être sûr d'avoir une copie conforme. . Toujours . Avec les listes, c'est aussi simple qu'une tranche : a = b[ :].

La mutabilité est également à l'origine de cette situation :

def myfunction(mylist=[]): 
    pass

... ne fait pas tout à fait ce que vous pensez qu'il fait.

Si vous venez d'un environnement C : ce qui reste du '=' est un pointeur, toujours. Toutes les variables sont des pointeurs, toujours. Si vous placez des variables dans une liste : a = [b, c], vous avez placé des pointeurs sur les valeurs indiquées par b et c dans une liste indiquée par a. Si vous définissez ensuite a[0] = d, le pointeur en position 0 indique maintenant ce que d indique.

Voir aussi le module de copie :  http://docs.python.org/library/copy.html

-2voto

abhiomkar Points 641

Copie superficielle : (copie des morceaux de mémoire d'un emplacement à un autre)

a = ['one','two','three']

b = a[:]

b[1] = 2

print id(a), a #Output: 1077248300 ['one', 'two', 'three']
print id(b), b #Output: 1077248908 ['one', 2, 'three']

Copie profonde : (Copie la référence de l'objet)

a = ['one','two','three']

b = a

b[1] = 2

print id(a), a #Output: 1077248300 ['one', 2, 'three']
print id(b), b #Output: 1077248300 ['one', 2, 'three']

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