50 votes

Pourquoi les tranches dans Python 3 sont-elles toujours des copies et non des vues?

Comme je l'ai seulement maintenant remarqué après commentant cette réponse, tranches dans Python 3 retour peu profondes des copies de tout ce qu'ils sont de découpage plutôt que de vues. Pourquoi est-ce toujours le cas? Même en laissant de côté numpy l'utilisation de points de vue plutôt que de copies pour le tranchage, le fait qu' dict.keys, dict.values, et dict.items tout retour de vues en Python 3, et qu'il y a de nombreux autres aspects de Python 3 orienté vers une plus grande utilisation des itérateurs, il semble qu'il y aurait eu un mouvement vers des tranches de devenir semblable. itertools a un islice fonction itérative tranches, mais c'est plus limité que la normale, de tranchage et de ne pas fournir des fonctionnalités d'affichage le long des lignes de dict.keys ou dict.values.

Ainsi, le fait que vous pouvez utiliser l'affectation à des tranches de modifier la liste d'origine, mais les tranches sont eux-mêmes des copies et pas les vues, est un aspect contradictoire de la langue et semble comme il viole plusieurs de ces principes illustrés dans le Zen de Python.

Qui est, le fait que vous pouvez faire

>>> a = [1, 2, 3, 4, 5]
>>> a[::2] = [0, 0, 0]
>>> a
[0, 2, 0, 4, 0]

Mais pas

>>> a = [1, 2, 3, 4, 5]
>>> a[::2][0] = 0
>>> a
[0, 2, 3, 4, 5]

ou quelque chose comme

>>> a = [1, 2, 3, 4, 5]
>>> b = a[::2]
>>> b
view(a[::2] -> [1, 3, 5])   # numpy doesn't explicitly state that its slices are views, but it would probably be a good idea to do it in some way for regular Python
>>> b[0] = 0
>>> b
view(a[::2] -> [0, 3, 5])
>>> a
[0, 2, 3, 4, 5]

Semble quelque peu arbitraire/indésirable.

Je suis conscient de http://www.python.org/dev/peps/pep-3099/ et la partie où il est dit "des Tranches et des tranches étendues ne va pas loin (même si l' __getslice__ et __setslice__ Api peut être remplacé) et ils ne seront pas de retour de vues pour le standard de types d'objet.", mais les liées discussion prévoit pas de mentionner la raison pour laquelle la décision sur le découpage avec des vues a eu lieu; en effet, la majorité des commentaires sur cette suggestion spécifique de la liste de suggestions dans le post original semblait être positive.

Ce qui a empêché quelque chose comme cela, d'être mis en œuvre en Python 3.0, qui a été spécialement conçu pour ne pas être strictement vers l'arrière-compatible avec Python 2.x et donc aurait été le meilleur moment pour mettre en œuvre un tel changement dans la conception, et il n'y a rien qui peut l'empêcher dans les futures versions de Python?

11voto

IfLoop Points 59461

Ainsi, le fait que vous pouvez utiliser l'affectation à des tranches de modifier la liste d'origine, mais les tranches sont eux-mêmes des copies et pas les vues.

Hmm.. c'est pas tout à fait raison; même si je peux voir comment vous pourriez penser que. Dans d'autres langues, une tranche de cession, de quelque chose comme:

a[b:c] = d

est équivalent à

tmp = a.operator[](slice(b, c)) # which returns some sort of reference
tmp.operator=(d)        # which has a special meaning for the reference type.

Mais en python, la première instruction est effectivement converti à ceci:

a.__setitem__(slice(b, c), d)

Qui est-à-dire qu'un élément d'assignation est fait spécialement reconnu dans python ont une signification particulière, distincte de l'élément de recherche et d'affectation; ils peuvent ne pas être liés. Ceci est cohérent avec python dans son ensemble, parce que python n'a pas de notions telles que le "lvalues" trouvé en C/C++; Il n'y a aucun moyen de la surcharge de l'opérateur d'affectation de lui-même; seulement des cas spécifiques, lorsque le côté gauche de l'affectation n'est pas un simple identifiant.

Supposons que les listes n' ont vues; Et vous avez essayé de l'utiliser:

myView = myList[1:10]
yourList = [1, 2, 3, 4]
myView = yourList

Dans des langues autres que python, il y a peut être un moyen de pousser yourList en myList, mais en python, puisque le nom myView apparaît comme un simple identifiant, il ne peut signifier qu'une variable assignemnt; la vue est perdu.

2voto

JAB Points 11053

Ainsi, il semble que j'ai trouvé beaucoup de raisonnement derrière le point de vue de la décision, en passant par le fil de départ avec http://mail.python.org/pipermail/python-3000/2006-August/003224.html (c'est principalement sur le découpage des chaînes, mais au moins un e-mail dans le fil mentionne mutable objets comme des listes), et aussi des choses à partir de:

http://mail.python.org/pipermail/python-3000/2007-February/005739.html
http://mail.python.org/pipermail/python-dev/2008-May/079692.html et à la suite d'e-mails dans le thread

Ressemble les avantages de la commutation à ce style de base de Python serait largement compensé par l'induit de la complexité et de divers indésirables des cas limites. Oh bien.

...Et comme j'ai alors commencé à me demander à propos de la possibilité de tout simplement en remplacement de l'actuelle voie slice des objets sont travaillés avec un objet iterable forme à la itertools.islice, tout comme zip, map, etc. tout retour iterables au lieu de listes en Python 3, j'ai commencé la réalisation de toutes les comportement inattendu et les problèmes éventuels qui pourraient en sortir. Ressemble à ce pourrait être une impasse pour l'instant.

Sur le côté positif, numpy du tableaux sont assez souples, dans les situations où ce genre de chose pourrait être nécessaire, il ne serait pas trop difficile à utiliser à une dimension ndarrays au lieu de listes. Cependant, il semble ndarrays ne prennent pas en charge à l'aide de découpage pour insérer d'autres éléments dans des tableaux, comme il arrive avec Python listes:

>>> a = [0, 0]
>>> a[:1] = [2, 3]
>>> a
[2, 3, 0]

Je pense que le numpy équivalent serait plutôt quelque chose comme ceci:

>>> a = np.array([0, 0])  # or a = np.zeros([2]), but that's not important here
>>> a = np.hstack(([2, 3], a[1:]))
>>> a
array([2, 3, 0])

Un peu plus compliqué cas:

>>> a = [1, 2, 3, 4]
>>> a[1:3] = [0, 0, 0]
>>> a
[1, 0, 0, 0, 4]

rapport

>>> a = np.array([1, 2, 3, 4])
>>> a = np.hstack((a[:1], [0, 0, 0], a[3:]))
>>> a
array([1, 0, 0, 0, 4])

Et, bien sûr, le ci-dessus numpy exemples à ne pas stocker le résultat dans le tableau d'origine, comme il arrive régulièrement Python extension de la liste.

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