Asignaciones e identidades
Ernesto Revilla
aerd en retemail.es
Lun Ago 19 15:38:10 CEST 2002
Hola,
se trata de tipos mutables y no mutables,
por ejemplo el entero 3 es inmutable, no puedes cambiar 3. 3 es 3 y ya está.
puedes asignar a una variable otro entero, pero es otro objeto.
3 y 3.0 no es lo mismo, aunque tengan un valor comparable. Son de tipos
diferentes así que imposiblemente pueden ser el mismo objeto. Por cierto,
los float también son inmutables.
Cadenas de caracteres, en contra de lo esperado, son también inmutables. Si
tú especificas dos veces "hola", el parser se da cuenta, porque mantiene
cadenas de caracteres únicas en una tabla de símbolos. Así que realmente
hacen referencia al mismo objeto. (comparable con Java String, que tb es
inmutable, pero StringBuffer sí es mutable). Operaciones como '+' o '%'
crean nuevas cadenas de caracteres, es decir, nuevos objetos:
>>> a="Hola"
>>> b="Hol"
>>> c=b+"a"
>>> a==c
1
>>> a is c
0
>>> a[2:3]="kk"
TypeError: object doesn't support slice assignment
Mientras que el parser ha hecho un buen trabajo optimizando el
almacenamiento de cadenas, el intérprete no es tan listo, es decir, una vez
interpretado, no se comprueba si la cadena resultante ya aparece en la tabla
de símbolos.
El tipo tupla también es inmutable. Una vez creada una tupla, esta no se
puede modificar.
>>> t=(1,2,3)
>>> t[0]=0
TypeError: object doesn't support item assignment
Lo mismo que se aplica a las cadenas de caracteres también vale para las
tuplas.
Los diccionarios y las listas son tipos mutables, es decir, su contenido
puede cambiar. Se puede agregar, modificar y borrar.
En a=[]
[] es un constructor que devuelve una nueva instancia de tipo lista y que
equivale a a=list()
Lo mismo pasa con los diccionarios. Dado que están haciendo una limpia de
conceptos, en Python 2.2 se ha introducido el alias 'dict' como tipo de
dictionarios.
d=dict() es lo mismo que d={}
>>> type(d)
<type 'dict'>
>>> dict
<type 'dict'>
Así que cada vez que escribas [] o {} estás creando un objeto nuevo.
Atención:!!!! pasando este tipo de estructuras por parámetro a funciones.
Si la función lo modifica puedes tener consecuencias inciertas en la función
llamante. Así que si quieres temporalmente modificar estas estructuras sin
que la función llamante se entere:
def x():
milista=[1,2,3]
print "milista antes de llamar funcion y",milista
y(milista)
print "milista despues de llamar funcion y",milista
def y(lista):
lista=list(lista) # Sacar copia de lista antes de modificarlo
lista.append(4)
print "lista en funcion y",lista
aunque como tu mencionaste lista=lista*1 o lista=lista[:] también valen,
pero con dict no funciona. En dict sí existe la definición copy, pero list
no la define. Quizá eso habría sido lo más explícito:
d={1: 'hola'}
d2=d.copy()
lista=[1,2,3]
lista2=lista1.copy() # No funciona, da error.
Finalmente, la asignación nunca crea un objeto, sino que sólo asocia. Eso en
otros lenguajes también es cierto en mayor medida. Expresiones que crean
instancias de tipos conocidos en Python son {...}, [...], "...". 1,2,3,
4j, 4.2, etc. son objetos ya existentes.
Saludos,
Erny
----- Original Message -----
From: "Chema Cortés" <chemacortes en wanadoo.es>
To: <python-es en aditel.org>
Sent: Monday, August 19, 2002 12:24 PM
Subject: [Python-es] Asignaciones e identidades
> Hola a todos:
>
> Ya de vuelta de vacaciones, he hecho algunos deberes.
>
> Una de las cosas que me ha dado por estudiar es la relación entre
asignaciones
> e identidades. He creado el siguiente test:
>
> >>> a=3
> >>> b=3
> >>> a is b
> 1
>
> Aquí vemos que, aunque 'a' y 'b' se crean en diferentes sentencias, ambos
son
> el mismo objeto!!!. He repetido el test para diversos tipos de datos y he
> obtenido los siguientes resultados:
>
> 3 true
> 3L false
> 3.0 false
> 3j false
> "" true
> () true
> [] false
> {} false
>
> No he encontrado una posible explicación que explique esta diferenciación
que
> se hace entre tipos de datos. ¿Alguien tiene una explicación?
>
>
> Estudiando un poco más el tema de las identidades, centrado ya en las
> asignaciones de listas tenemos que, si 'L' es una lista:
>
> >>> s=L
> >>> s is L
> 1
> >>> s=L[:]
> >>> s is L
> 0
> >>> s==L
> 1
>
> Vemos que la asignación opera de dos formas distintas:
>
> 1) en la primera asignación se da a 's' la misma referencia que tiene 'L'.
Por
> así decirlo, es similar una asignación de "punteros". En C++ sería:
>
> ListType& s = L;
>
>
> 2) en la segunda asignación, la expresión 'L[:]' genera una nueva lista
cuya
> referencia se asigna a 's'. En este caso, hay creación previa del nuevo
> objeto, cuya referencia se asigna a 's'.
>
> ListType& s = new ListType(L);
>
>
> El uso de operador de rebanado L[:] siempre es el que se ve como "truco"
para
> realizar una "copia" de una lista. Todo consiste en forzar que la
asignación
> se haga como en el segundo caso, para lo que se puede usar cualquier
> expresión que devuelva una lista igual a la original. 'L[:]' es el caso
más
> visto, pero se podría utilizar otros operadores como el de replicación
'L*1'
> e incluso el de añadir 'L+[]'. ¿Alguna razón que haga más aconsejable el
uso
> de L[:]? (Personalmente, me gusta más L*1 que L[:]).
>
>
> Espero no haber sido demasiado "espeso" con el tema, pero era algo que
tenía
> aún por digerir.
>
> Saludos,
> Chema Cortés
> _______________________________________________
> Python-es mailing list
> Python-es en aditel.org
> http://listas.aditel.org/listinfo.py/python-es
>
Más información sobre la lista de distribución Python-es