2010-12-29 20 views
7

decir que tengo dos listas:Python referencias de datos básica, lista de misma referencia

>>> l1=[1,2,3,4] 
>>> l2=[11,12,13,14] 

puedo poner esas listas en una tupla, o diccionario, y parece que son todas las referencias volver a la lista original :

>>> t=(l1,l2) 
>>> d={'l1':l1, 'l2':l2} 
>>> id(l1)==id(d['l1'])==id(t[0]) 
True 
>>> l1 is d['l1'] is t[0] 
True 

Puesto que son las referencias, puedo cambiar l1 y los datos indicados en la tupla y el cambio diccionario en consecuencia:

>>> l1.append(5) 
>>> l1 
[1, 2, 3, 4, 5] 
>>> t 
([1, 2, 3, 4, 5], [11, 12, 13, 14]) 
>>> d 
{'l2': [11, 12, 13, 14], 'l1': [1, 2, 3, 4, 5]} 

Incluyendo si añado la referencia en el diccionario d o referencia mutable en la tupla t:

>>> d['l1'].append(6) 
>>> t[0].append(7) 
>>> d 
{'l2': [11, 12, 13, 14], 'l1': [1, 2, 3, 4, 5, 6, 7]} 
>>> l1 
[1, 2, 3, 4, 5, 6, 7] 

Si ahora me puse l1 a una nueva lista, la cuenta de referencia para la lista original disminuye:

>>> sys.getrefcount(l1) 
4 
>>> sys.getrefcount(t[0]) 
4 
>>> l1=['new','list'] 
>>> l1 is d['l1'] is t[0] 
False 
>>> sys.getrefcount(l1) 
2 
>>> sys.getrefcount(t[0]) 
3 

Y anexar o cambiar l1 no cambia d['l1'] o t[0] ya que ahora es una nueva referencia. La noción de referencias indirectas es covered fairly well en los documentos de Python pero no completamente.

Mis preguntas:

  1. es un objeto mutable siempre una referencia? ¿Puede siempre suponer que modificarlo modifica el original (a menos que haga específicamente una copia con el tipo de modismo l2=l1[:])?

  2. ¿Puedo armar una lista de todas las mismas referencias en Python? es decir, ¿alguna función f(l1) que devuelve ['l1', 'd', 't'] si todos esos se están refiriendo a la misma lista?

  3. Supongo que pase lo que pase, los datos seguirán siendo válidos siempre que haya alguna referencia al mismo.

es decir:

l=[1,2,3]   # create an object of three integers and create a ref to it 
l2=l    # create a reference to the same object 
l=[4,5,6]   # create a new object of 3 ints; the original now referenced 
        # by l2 is unchanged and unmoved 
+0

Relevante para 3: http://docs.python.org/library/weakref.html –

Respuesta

6

1) Modificación de un objeto mutable través de una referencia se siempre modificar el "original". Honestamente, esto está traicionando una mala interpretación de las referencias. La referencia más reciente es tan "original" como cualquier otra referencia. Siempre que ambos nombres apunten al mismo objeto, la modificación del objeto a través de cualquiera de los nombres se reflejará cuando se acceda a través del otro nombre.

2) No exactamente como lo que quiere. gc.get_referrers devuelve todos referencias al objeto.

>>> l = [1, 2] 
>>> d = {0: l} 
>>> t = (l,) 
>>> import gc 
>>> import pprint 
>>> pprint.pprint(gc.get_referrers(l)) 
[{'__builtins__': <module '__builtin__' (built-in)>, 
    '__doc__': None, 
    '__name__': '__main__', 
    '__package__': None, 
    'd': {0: [1, 2]}, 
    'gc': <module 'gc' (built-in)>, 
    'l': [1, 2], 
    'pprint': <module 'pprint' from '/usr/lib/python2.6/pprint.pyc'>, 
    't': ([1, 2],)}, # This is globals() 

{0: [1, 2]}, # This is d 
([1, 2],)] # this is t 

Tenga en cuenta que el objeto real referenciado por l no está incluido en la lista devuelta porque no contiene una referencia a sí mismo. globals() se devuelve porque hace contiene una referencia a la lista original.

3) Si por válido, quiere decir "no será basura recolectada", esto es correcto, salvo un error altamente improbable. Sería un lamentable recolector de basura que "robó" tus datos.

0

1- ¿Es un objeto mutable siempre una referencia ? ¿Se puede asumir siempre que modificándolo modifica el original (a menos que haga específicamente una copia con l2 = l1 [:] tipo de expresión idiomática)?

Sí. En realidad, los objetos no mutables también son siempre una referencia. Simplemente no puede cambiarlos para percibir esto.

2 - ¿Puedo armar una lista de todas las mismas referencias en Python? es decir, algunos función f (l1) que devuelve ['l1', 'd', 't'] si todos esos son haciendo referencia a la misma lista?

Eso es extraño, pero se puede hacer.

Puede comparar objetos para "samenes" con el operador is. Al igual que en l1 is t[0]

y se puede obtener toda la que se refiere a los objetos con la función gc.get_referrers en el módulo recolector de basura (GC) - Puede comprobar cuál de estos referentes punto O de su objeto con el operador is. Entonces, sí, se puede hacer. Simplemente no creo que sea una buena idea. Es más probable que la oferta is operador una manera para que usted pueda hacer waht que necesita solo

3- Es mi suposición de que no importa lo que , los datos seguirán siendo válidas por lo siempre que haya alguna referencia lo.

Sí.

0

¿Es siempre un objeto mutable una referencia? ¿Se puede asumir siempre que modificarlo modifica el original (a menos que se haga una copia específicamente con l2 = l1 [:] tipo de modismo)?

Python tiene la semántica de referencia: Las variables no tienda valores que en C++, pero en lugar etiqueta ellos. El concepto de "original" es defectuoso: si dos variables etiquetan el mismo valor, es totalmente irrelevante cuál fue "el primero". No importa si el objeto es mutable o no (excepto que los objetos inmutables no harán que sea tan fácil saber lo que sucede detrás de escena). Para hacer copias de una manera más general, pruebe el módulo copy.

¿Puedo armar una lista de todas las mismas referencias en Python? es decir, alguna función f (l1) que devuelve ['l1', 'd', 't'] si todos esos se están refiriendo a la misma lista?

No es fácil. Consulte la respuesta de aaronasterling para más detalles.También puede intentar algo como k for k, v in locals().items() if v is the_object, pero también tendrá que buscar globals(), extrañará algunas cosas y podría causar algún tipo de problema debido a la repetición de la búsqueda con los nombres 'k' y 'v' (no lo he hecho probado).

Supongo que pase lo que pase, los datos seguirán siendo válidos siempre que haya alguna referencia al respecto.

Absolutamente.

0
  1. "... objeto es una referencia ..." es una tontería. Las referencias no son objetos. Las variables, campos de miembros, espacios en listas y conjuntos, etc. contienen referencias, y estas referencias apuntan a objetos. Puede haber cualquier número (en implementaciones que no sean refutaciones, incluso ninguna - temporalmente, es decir, hasta que el GC entre) referencias a un objeto. Todos los que tienen una referencia a un objeto pueden invocar sus métodos, acceder a sus miembros, etc. - esto es cierto para todos los objetos. Por supuesto, solo los objetos mutables se pueden cambiar de esta manera, por lo que normalmente no se preocupan por los inmutables.
  2. Sí, como otros han demostrado. Pero esto no debería ser necesario a menos que esté depurando el GC o rastreando una fuga de memoria grave en su código, ¿por qué cree que necesita esto?
  3. Python tiene administración de memoria automática, entonces sí. Mientras haya una referencia a un objeto, no se eliminará (sin embargo, puede permanecer activo por un tiempo después de que se vuelva inalcanzable, debido a las referencias cíclicas y al hecho de que los GC solo se ejecutan de vez en cuando).
3

Cada variable en Python es una referencia.

Para las listas, se está enfocando en los resultados del método append(), y perdiendo de vista la imagen más grande de las estructuras de datos de Python. Hay otros métodos en las listas, y hay ventajas y consecuencias sobre cómo se construye una lista. Es útil pensar en la lista como ver en otros objetos a los que se hace referencia en la lista. No "contienen" nada más que las reglas y las formas de acceder a los datos a los que se refieren los objetos dentro de ellos.

El list.append(x)method specifically es equivalente a l[len(l):]=[list]

Así:

>>> l1=range(3) 
>>> l2=range(20,23) 
>>> l3=range(30,33) 
>>> l1[len(l1):]=[l2] # equivalent to 'append' for subscriptable sequences 
>>> l1[len(l1):]=l3  # same as 'extend' 
>>> l1 
[0, 1, 2, [20, 21, 22], 30, 31, 32] 
>>> len(l1) 
7 
>>> l1.index(30) 
4 
>>> l1.index(20) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: list.index(x): x not in list 
>>> 20 in l1 
False 
>>> 30 in l1 
True 

Al poner la lista constructor de alrededor de L2 en l1[len(l1):]=[l2], o llamando l.append(l2), se crea una referencia que está obligado a L2. Si cambia l2, las referencias también mostrarán el cambio. La longitud de eso en la lista es un elemento único: la referencia a la secuencia anexa.

Sin atajo de constructor como en l1[len(l1):]=l3, copia cada elemento de la secuencia.

Si utiliza otros métodos de lista comunes, como l.index(something) o in, no encontrará elementos dentro de las referencias de datos. l.sort() no ordenará correctamente. Son operaciones "superficiales" en el objeto y, al usar l1[len(l1):]=[l2], está creando una estructura de datos recursiva.

Si usa l1[len(l1):]=l3, está haciendo una copia verdadera (poco profunda) de los elementos en l3.

Estas son expresiones bastante básicas de Python, y la mayoría de las veces 'hacen lo correcto'. Puede, sin embargo, obtener resultados sorprendentes, tales como:

>>> m=[[None]*2]*3 
>>> m 
[[None, None], [None, None], [None, None]] 
>>> m[0][1]=33 
>>> m 
[[None, 33], [None, 33], [None, 33]] # probably not what was intended... 
>>> m[0] is m[1] is m[2]    # same object, that's why they all changed 
True 

Algunos novatos Python tratan de crear una dimensión de varios haciendo algo como m=[[None]*2]*3 Los primeros trabajos sequence replication como se esperaba; crea 2 copias de None. Es el segundo problema: crea tres copias de la referencia a la primera lista. Entonces al ingresar m[0][1]=33 se modifica la lista dentro de la lista vinculada a my luego todas las referencias enlazadas cambian para mostrar ese cambio.

Comparar con:

>>> m=[[None]*2,[None]*2,[None]*2] 
>>> m 
[[None, None], [None, None], [None, None]] 
>>> m[0][1]=33 
>>> m 
[[None, 33], [None, None], [None, None]] 

También puede utilizar nested list comprehensions a hacer lo mismo de esta manera:

>>> m=[[ None for i in range(2)] for j in range(3)] 
>>> m 
[[None, None], [None, None], [None, None]] 
>>> m[0][1]=44 
>>> m 
[[None, 44], [None, None], [None, None]] 
>>> m[0] is m[1] is m[2]      # three different lists.... 
False 

Para listas y referencias, Fredrik Lundh tiene this text para una buena introducción.

En cuanto a sus preguntas específicas:

1) En Python, Todo es un sello o una referencia a un objeto. No hay 'original' (un concepto de C++) y no hay distinción entre 'referencia', puntero o datos reales (un concepto de C/Perl)

2) Fredrik Lundh tiene una gran analogía sobre la referencia to a question similar to this:

la misma forma que se obtiene el nombre de ese gato que encontró en el porche: la gato (objeto) en sí mismo no se puede decir su nombre, y no le importa realmente - por lo que el La única manera de averiguar cómo se llama es preguntar a todos sus vecinos (espacios de nombres) si es su gato (objeto) ...

.... y no se sorprenda si va a encontrar que es conocido por muchos nombres, o sin nombre!

Puede encontrar esta lista con algún esfuerzo, pero ¿por qué? Simplemente llámalo como lo vas a llamar, como un gato encontrado.

3) Es cierto.

0
1a. Is a mutable object always a reference? 

No hay diferencia entre los objetos mutables y no modificables. Ver los nombres de las variables como referencias es útil para las personas con un C-background (pero implica que se les puede quitar la referencia, lo que no pueden hacer).

1b. Can you always assume that modifying it modifies the original 

Por favor, no es "el original". Es el mismo objeto. b = a significa b y a ahora son el mismo objeto.

1c. (Unless you specifically make a copy with l2=l1[:] kind of idiom)? 

Bien, porque entonces ya no es el mismo objeto. (Aunque las entradas en la lista serán los mismos objetos que la lista original).

2. Can I assemble a list of all the same references in Python? 

Sí, probablemente, pero usted nunca jamás lo necesita, por lo que sería un desperdicio de energía. :)

3. It is my assumption that no matter what, the data will remain valid so long as there is some reference to it. 

Sí, un objeto no será basura recolectada mientras tenga una referencia al mismo. (El uso de la palabra "válido" aquí parece incorrecto, pero supongo que esto es lo que quiere decir).

Cuestiones relacionadas