ultima - ¿Por qué los segmentos en Python 3 todavía se copian y no las vistas?
version actual de python (2)
Además, el hecho de que puede usar la asignación a sectores para modificar la lista original, pero las secciones son en sí mismas copias y no vistas.
Hmm ... eso no está del todo bien; aunque puedo ver cómo puedes pensar eso. En otros idiomas, una asignación de sector, algo así como:
a[b:c] = d
es equivalente a
tmp = a.operator[](slice(b, c)) # which returns some sort of reference
tmp.operator=(d) # which has a special meaning for the reference type.
Pero en Python, la primera declaración se convierte a esto:
a.__setitem__(slice(b, c), d)
Lo que equivale a decir que una asignación de elemento realmente se reconoce especialmente en python para tener un significado especial, separado de la búsqueda y asignación de elementos ; pueden no estar relacionados. Esto es coherente con Python como un todo, porque python no tiene conceptos como los "lvalues" que se encuentran en C / C ++; No hay forma de sobrecargar el operador de asignación en sí mismo; solo casos específicos cuando el lado izquierdo de la asignación no es un identificador simple.
Supongamos que las listas tienen puntos de vista; Y trataste de usarlo:
myView = myList[1:10]
yourList = [1, 2, 3, 4]
myView = yourList
En los lenguajes además de python, podría haber una manera de yourList
en myList
, pero en python, dado que el nombre myView
aparece como un identificador myView
, solo puede significar un assignemnt variable; la vista esta perdida
Como ahora solo noté después de comentar esta respuesta , las rebanadas en Python 3 devuelven copias superficiales de lo que están cortando en lugar de vistas. ¿Por qué este sigue siendo el caso? Incluso dejando a un lado el uso numpy de vistas en lugar de copias para cortar, el hecho de que dict.keys
, dict.values
y dict.items
todos devuelvan vistas en Python 3, y que hay muchos otros aspectos de Python 3 orientados a un mayor uso de iteradores, parece que habría habido un movimiento hacia las divisiones que se volverían similares. itertools
tiene una función islice
que hace cortes iterativos, pero eso es más limitado que el corte normal y no proporciona funcionalidad de vista en las líneas de dict.keys
o dict.values
.
Además, el hecho de que pueda usar la asignación a sectores para modificar la lista original, pero las secciones son copias y no vistas, es un aspecto contradictorio del lenguaje y parece que viola varios de los principios ilustrados en el Zen de Python .
Es decir, el hecho de que puedes hacer
>>> a = [1, 2, 3, 4, 5]
>>> a[::2] = [0, 0, 0]
>>> a
[0, 2, 0, 4, 0]
Pero no
>>> a = [1, 2, 3, 4, 5]
>>> a[::2][0] = 0
>>> a
[0, 2, 3, 4, 5]
o algo así como
>>> 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]
Parece algo arbitrario / indeseable.
__getslice__
http://www.python.org/dev/peps/pep-3099/ y la parte donde dice "Las rebanadas y rebanadas extendidas no desaparecerán (incluso si las API __getslice__
y __setslice__
pueden ser reemplazadas ) ni devolverán vistas para los tipos de objetos estándar. ", pero la discusión vinculada no proporciona ninguna mención de por qué se tomó la decisión sobre rebanar con vistas; de hecho, la mayoría de los comentarios sobre esa sugerencia específica de las sugerencias enumeradas en la publicación original parecían ser positivas.
Lo que impidió que algo como esto se implementara en Python 3.0, que fue diseñado específicamente para no ser estrictamente compatible con versiones anteriores de Python 2.x y, por lo tanto, habría sido el mejor momento para implementar dicho cambio en el diseño, y ¿hay algo que pueda prevenirlo en futuras versiones de Python?
Bueno, parece que encontré mucho del razonamiento detrás de la decisión de las vistas, yendo por el hilo que comienza con http://mail.python.org/pipermail/python-3000/2006-August/003224.html (se trata principalmente de cortar cadenas , pero al menos un correo electrónico en el hilo menciona objetos mutables como listas), y también algunas cosas de:
http://mail.python.org/pipermail/python-3000/2007-February/005739.html
http://mail.python.org/pipermail/python-dev/2008-May/079692.html y siguientes correos electrónicos en el hilo
Parece que las ventajas de cambiar a este estilo para Python base serían ampliamente superadas por la complejidad inducida y varios casos extremos indeseables. Oh bien.
... Y luego comencé a preguntarme acerca de la posibilidad de simplemente reemplazar la forma actual en que se trabaja con una forma iterable a la itertools.islice
, como zip
, map
, etc. todos devuelven iterables en lugar de listas en Python 3 , Empecé a darme cuenta de todo el comportamiento inesperado y los posibles problemas que podrían surgir de eso. Parece que esto podría ser un callejón sin salida por ahora.
En el lado positivo, las matrices de numpy son bastante flexibles, por lo que en situaciones donde este tipo de cosas podría ser necesario, no sería demasiado difícil usar ndarrays unidimensionales en lugar de listas. Sin embargo, parece que las ndarrays no admiten el uso de slicing para insertar elementos adicionales dentro de las matrices, como ocurre con las listas de Python:
>>> a = [0, 0]
>>> a[:1] = [2, 3]
>>> a
[2, 3, 0]
Creo que el equivalente numpy sería algo como esto:
>>> 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 caso un poco más complicado:
>>> a = [1, 2, 3, 4]
>>> a[1:3] = [0, 0, 0]
>>> a
[1, 0, 0, 0, 4]
versus
>>> a = np.array([1, 2, 3, 4])
>>> a = np.hstack((a[:1], [0, 0, 0], a[3:]))
>>> a
array([1, 0, 0, 0, 4])
Y, por supuesto, los ejemplos numpy anteriores no almacenan el resultado en la matriz original como sucede con la expansión regular de la lista de Python.