variables de instancia de clase de Python y variables de clase

6 minutos de lectura

variables de instancia de clase de Python y variables de
jonathan topf

Tengo problemas para entender cómo funcionan las variables de clase/instancia en Python. No entiendo por qué cuando pruebo este código, la variable de lista parece ser una variable de clase

class testClass():
    list = []
    def __init__(self):
        self.list.append('thing')

p = testClass()
print p.list

f = testClass()
print f.list

Producción:

['thing']
['thing', 'thing']

y cuando hago esto parece ser una variable de instancia

class testClass():
    def __init__(self):
        self.list = []
        self.list.append('thing')

p = testClass()
print p.list

f = testClass()
print f.list

Producción:

['thing']
['thing']

  • Si lo entiendo correctamente, está solicitando una justificación detrás de una decisión de diseño particular con respecto a la sintaxis de Python. Para tales preguntas, la mejor respuesta es “porque encaja con el espíritu de la lengua”, o más descaradamente: “pregúntale a su creador”.

    – Xión

    02 ene.

  • ok, entonces las variables son variables de clase por defecto, de ahí surgió mi confusión, esa debería haber sido mi pregunta, hacer que las variables sean variables de clase por defecto

    – Jonathan Topf

    02 ene.

  • @jonathantopf No, las variables NO son variables de clase por defecto. En Python no declaras varables. De hecho, en realidad no son variables (python es un sin variables idioma), solo nombres. Y no declaras ni asignas nombres, tú unir ellos a un objeto. Y cada objeto en tiempo de ejecución tiene un diccionario de nombres a objetos. E incluso si dos objetos son de la misma clase, pueden tener diccionarios muy diferentes.

    – rodrigo

    02 ene.

  • En su primer ejemplo, creó un recurso compartido de buena fe entre todos los miembros de la clase MyClass. Luego pasaste a privatizar los contenidos de un rasgo compartido en cada miembro de la clase. MyClass.

    – yurisich

    02 ene.

  • posible duplicado de ¿Cómo evito que los datos de la clase de Python se compartan entre instancias?

    – Martijn Pieters

    23 feb. 13 en 15:42

1643785269 829 variables de instancia de clase de Python y variables de
rodrigo

Esto se debe a la forma en que Python resuelve los nombres con el .. Cuando escribes self.list el tiempo de ejecución de Python intenta resolver el list nombre primero buscándolo en el objeto de instancia, y si no se encuentra allí, entonces en la instancia de clase.

Veámoslo paso a paso

self.list.append(1)
  1. Hay un list nombre en el objeto self?
    • Sí: ¡Úsalo! Terminar.
    • No: Ir a 2.
  2. Hay un list nombre en la instancia de clase del objeto self?
    • Sí: ¡Úsalo! Terminar
    • ¡No hay error!

Pero cuando vinculas un nombre, las cosas son diferentes:

self.list = []
  1. Hay un list nombre en el objeto self?
    • Sí: ¡sobrescríbelo!
    • No: ¡Átalo!

Entonces, esa es siempre una variable de instancia.

Su primer ejemplo crea un list en la instancia de clase, ya que este es el ámbito activo en ese momento (no self en cualquier lugar). Pero su segundo ejemplo crea un list explícitamente en el ámbito de self.

Más interesante sería el ejemplo:

class testClass():
    list = ['foo']
    def __init__(self):
        self.list = []
        self.list.append('thing')

x = testClass()
print x.list
print testClass.list
del x.list
print x.list

Eso imprimirá:

['thing']
['foo']
['foo']

En el momento en que elimina el nombre de la instancia, el nombre de la clase es visible a través del self referencia.

  • ok, estoy siguiendo, en ese caso, ¿hay alguna manera de definir variables de instancia fuera del en eso función, acabo de intentar hacer self.list[] fuera de en esoesto tiene sentido, pero ¿hay alguna manera?

    – Jonathan Topf

    02 ene.

  • @jonathantopf: las variables de instancia solo se pueden crear cuando tiene una instancia. Deben crearse en un método que se invoque en una instancia. Su otra opción es sobrecargar __new__ y crearlos allí, pero eso es realmente feo ya que no es lo que __new__ es realmente para, y en realidad no es mejor que crearlos en __init__. ¿Para qué crees que necesitas esta habilidad? Podrías crear una metaclase que se sobrecargue __new__ para mirar a través del dictado de la clase y copiar cosas en el dictado de la instancia. Pero eso es De Verdad feo.

    – Omnifaro

    02 ene.


  • 🙂 punto tomado, eso tiene sentido, odio hacer preguntas como esa, pero a veces es la mejor manera de averiguar si lo que estoy pensando es una locura o no, ¡ahora lo sé!

    – Jonathan Topf

    02 ene.

  • @jonathantopf Puedes hacerlo p.list = []fuera de cualquier función, en el ámbito global y simplemente funcionará.

    – rodrigo

    02 ene.

  • @jonathantopf: Sí, lo que estás tratando de hacer es luchar contra el funcionamiento de Python y tratar de forzarlo en el modelo de Java. Tenga en cuenta que Python básicamente no tiene ‘declaraciones’. Todo es código ejecutable. El class construcción es solo azúcar sintáctica para un montón de asignaciones a miembros de un class ejemplo. Lo más parecido a una declaración es una asignación a la clase’ __slots__ variable para una clase de nuevo estilo.

    – Omnifaro

    02 ene.

Python tiene reglas interesantes sobre la búsqueda de nombres. Si realmente quieres cambiar tu mente, prueba este código:

class testClass():
    l = []
    def __init__(self):
        self.l = ['fred']

Esto le dará a cada instancia una variable llamada l que enmascara la variable de clase l. Todavía podrá acceder a la variable de clase si lo hace self.__class__.l.

La forma en que lo pienso es esta… Siempre que lo haces instance.variable (incluso para los nombres de los métodos, son solo variables cuyos valores resultan ser funciones) lo busca en el diccionario de la instancia. Y si no lo encuentra allí, intenta buscarlo en el diccionario de la clase de la instancia. Esto es solo si la variable está siendo ‘leída’. Si se le asigna, siempre crea una nueva entrada en el diccionario de instancias.

  • ¡Qué complicaciones tortuosas! Esta respuesta fue realmente útil, porque el caso de ‘leer versus escribir’ me estaba dando dolor de cabeza.

    – ankush981

    17 ene.

En tu primer ejemplo, list es un atributo de la clase, compartido por todas las instancias de la misma. Esto significa que incluso puede acceder a él sin tener un objeto de tipo testClass:

>>> class testClass():
...     list = []
...     def __init__(self):
...             self.list.append("thing")
... 
>>> testClass.list
[]
>>> testClass.list.append(1)
>>> testClass.list
[1]

Pero todos los objetos comparten la list atributo con la clase y entre sí:

>>> testObject = testClass()
>>> testObject.list
[1, 'thing']
>>> testClass.list
[1, 'thing']
>>> 
>>> testObject2 = testClass()
>>> testClass.list
[1, 'thing', 'thing']
>>> testObject2.list
[1, 'thing', 'thing']

Cuando instancias una clase, __init__ El método se ejecuta automáticamente.

En el primer caso, su lista es un atributo de clase y es compartida por todas sus instancias. Obtuviste dos ‘cosas’ porque añadiste una al instanciar p y otro cuando se instancia f (el primero ya estaba anexado en la primera convocatoria).

.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad