¿Es una buena práctica declarar las variables de instancia como Ninguna en una clase en Python?

53

Considera la siguiente clase:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

Mis compañeros de trabajo tienden a definirlo así:

class Person:
    name = None
    age = None

    def __init__(self, name, age):
        self.name = name
        self.age = age

La razón principal de esto es que su editor de elección muestra las propiedades para el autocompletado.

Personalmente, no me gusta este último, porque no tiene sentido que una clase tenga esas propiedades configuradas en None .

¿Cuál sería una mejor práctica y por qué razones?

    
pregunta Remco Haszing 27.08.2014 - 13:08

5 respuestas

58

Yo llamo a esta última mala práctica bajo la regla "esto no hace lo que crees que hace".

La posición de su compañero de trabajo se puede reescribir como: "Voy a crear un grupo de variables cuasi globales de clase estática a las que nunca se accede, pero que ocupan espacio en las tablas de espacio de nombres de varias clases ( __dict__ ), sólo para hacer que mi IDE haga algo ".

    
respondido por el StarWeaver 27.08.2014 - 16:53
22

1. Haz que tu código sea fácil de entender

El código se lee mucho más a menudo que escrito. Haga que la tarea del mantenedor de su código sea más fácil (también puede ser usted el próximo año).

No conozco ninguna regla estricta, pero prefiero tener un estado de instancia futuro claramente declarado claramente. Chocar con un AttributeError es suficientemente malo. No ver claramente el ciclo de vida de un atributo de instancia es peor. La cantidad de gimnasia mental necesaria para restaurar las posibles secuencias de llamadas que conducen a la asignación del atributo puede convertirse fácilmente en no trivial, lo que lleva a errores.

Por lo general, no solo defino todo en el constructor, sino que también me esfuerzo por mantener el número de atributos mutables al mínimo.

2. No mezcle miembros de nivel de clase y nivel de instancia

Todo lo que defina justo dentro de la declaración class pertenece a la clase y es compartido por todas las instancias de la clase. P.ej. Cuando define una función dentro de una clase, se convierte en un método que es el mismo para todas las instancias. Lo mismo se aplica a los miembros de datos. Esto es totalmente diferente a los atributos de instancia que usualmente define en __init__ .

Los miembros de datos de nivel de clase son más útiles como constantes:

class Missile(object):
  MAX_SPEED = 100  # all missiles accelerate up to this speed
  ACCELERATION = 5  # rate of acceleration per game frame

  def move(self):
    self.speed += self.ACCELERATION
    if self.speed > self.MAX_SPEED:
      self.speed = self.MAX_SPEED
    # ...
    
respondido por el 9000 27.08.2014 - 17:14
13

Personalmente defino los miembros en el método __ init __ (). Nunca pensé en definirlos en la parte de la clase. Pero lo que siempre hago: inicio a todos los miembros en el método __ init__, incluso a aquellos que no son necesarios en el método __ init__.

Ejemplo:

class Person:
    def __init__(self, name, age):
        self._name = name
        self._age = age
        self._selected = None

   def setSelected(self, value):
        self._selected = value

Creo que es importante definir a todos los miembros en un solo lugar. Hace que el código sea más legible. Ya sea dentro de __ init __ () o fuera, no es tan importante. Pero es importante que un equipo se comprometa con más o menos el mismo estilo de codificación.

Ah, y puedes notar que alguna vez agrego el prefijo "_" a las variables miembro.

    
respondido por el this.myself 27.08.2014 - 14:08
9

Esta es una mala práctica. No necesita esos valores, desordenan el código y pueden causar errores.

Considera:

>>> class WithNone:
...   x = None
...   y = None
...   def __init__(self, x, y):
...     self.x = x
...     self.y = y
... 
>>> class InitOnly:
...   def __init__(self, x, y):
...     self.x = x
...     self.y = y
... 
>>> wn = WithNone(1,2)
>>> wn.x
1
>>> WithNone.x #Note that it returns none, no error
>>> io = InitOnly(1,2)
>>> InitOnly.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: class InitOnly has no attribute 'x'
    
respondido por el Daenyth 27.08.2014 - 16:38
0

Iré con "un poco como docstrings, luego" y lo declararé inofensivo, siempre y cuando sea siempre None , o un rango estrecho de otros valores, todos inmutables.

Apesta a atavismo y apego excesivo a lenguajes tipificados estáticamente. Y no sirve como código. Pero tiene un propósito menor que permanece, en la documentación.

Documenta cuáles son los nombres esperados, así que si combino el código con alguien y uno de nosotros tiene 'username' y el otro nombre_usuario, hay una pista para los humanos de que nos hemos separado y no estamos usando las mismas variables. .

Forzar la inicialización completa como una política logra lo mismo de una manera más Pythonic, pero si hay un código real en el __init__ , esto proporciona un lugar más claro para documentar las variables en uso.

Obviamente, el problema GRANDE aquí es que tienta a la gente a inicializarse con valores distintos a None , lo que puede ser malo:

class X:
    v = {}
x = X()
x.v[1] = 2

deja una traza global y no crea una instancia para x.

Pero eso es más una peculiaridad en Python en su conjunto que en esta práctica, y ya deberíamos estar paranoicos al respecto.

    
respondido por el Jon Jay Obermark 27.08.2014 - 20:44

Lea otras preguntas en las etiquetas