Clases de Python con una sola instancia: ¿cuándo crear una instancia de clase (única) y cuándo trabajar con la clase?

11

Dada una clase de Python que se instanciará solo una vez, es decir, solo habrá un objeto de la clase. Me preguntaba en qué casos tiene sentido crear una sola instancia de clase en lugar de trabajar directamente con la clase.

Hay una pregunta similar , pero tiene un enfoque diferente:

  1. se trata de agrupar variables y funciones globales en una clase y
  2. No es específico de Python. Esto último significa que no considera el hecho de que (en Python) las clases también son objetos.

ACTUALIZAR:

En Python, puedo hacer lo siguiente con clases y objetos:

class A(object):
    pass

A.some_state_var = True
# Then later
A.some_state_var = False


my_a = A()

my_a.some_state_var = True
# Then later
my_a.some_state_var = False

Entonces, no veo cómo la elección entre una clase y una instancia de esa clase se trata del estado (en Python). Puedo mantener un estado con cualquiera de los dos.

Además, la motivación para crear mi clase / instancia de clase no se trata de hacer cumplir un requisito de Singleton.

Además, no se trata tanto de crear un nuevo tipo.

La motivación es agrupar código y datos relacionados y tener una interfaz para ello. Es por eso que inicialmente lo modelé como una clase en un diagrama de clase. Solo cuando se trataba de la implementación comencé a preguntarme si crear una instancia de esta clase o no.

langlauf.io
fuente

Respuestas:

16

Dada una clase de Python que se instanciará solo una vez, es decir, solo habrá un objeto de la clase. Me preguntaba en qué casos tiene sentido crear una sola instancia de clase en lugar de trabajar directamente con la clase.

Entonces es esto:

class Singleton:
    '''don't bother instantiating me'''
    clsvar1 = 'foo'

    @classmethod
    def foobar(cls, *args, **kwargs):
        if condition():
            cls.clsvar1 = 'bar'

contra esto?

class Singleton:
    '''instantiate and use me'''
    def __init__(self):
        self.var1 = 'foo'

    def foobar(self, *args, **kwargs):
        if condition():
            self.var1 = 'bar'

Recomendación

Definitivamente preferiría el que está destinado a ser instanciado. Cuando creas un "tipo de cosa" que implica que creas cosas de ese tipo.

La motivación es agrupar código y datos relacionados y tener una interfaz para ello.

Dicho esto, ¿por qué no solo usar un módulo ya que todo lo que quieres es un espacio de nombres? Los módulos son singletons, códigos y datos relacionados con el grupo, y esto es un poco más simple y probablemente se consideraría más Pythonic:

var1 ='foo'

def foobar(*args, **kwargs):
    global var1
    if condition():
        var1 = 'bar'

Entonces el uso sería en lugar de:

from modules.singleton import Singleton
Singleton.foobar()

o

from modules.singleton import Singleton
the_singleton = Singleton()
the_singleton.foobar()

hacer esto:

from modules import singleton
singleton.foobar()
Aaron Hall
fuente
3
Gracias por tu respuesta. ¿Realmente sugeriría crear un nuevo módulo (un nuevo archivo .py) para cada función (incluidas las variables)? Esto podría resultar en muchos pequeños archivos .py. ¿O agruparía todas las funciones y variables "sin clase" (al menos de alguna manera relacionadas) en un módulo?
langlauf.io
Una observación más: escribes "ya que todo lo que quieres es un espacio de nombres". Lo que quiero es agrupar código relacionado, es decir, funciones y datos, en un solo lugar, y tener una interfaz para ello. No se trata tanto de crear un "Tipo". Durante el diseño, esto daría como resultado una clase en un diagrama de clase de todos modos, ¿no?
langlauf.io
2

Me preguntaba en qué casos tiene sentido crear una sola instancia de clase en lugar de trabajar directamente con la clase.

Esta es una de esas cosas que provocarán una guerra religiosa si te involucras demasiado.

Pero, en general, una práctica que he visto muchas veces es que los métodos de clase deberían preocuparse solo de crear instancias de esa clase.

Si piensa en qué es una clase, cuál es su propósito / comportamiento, entonces tiene sentido. El propósito de una clase es crear instancias de objetos que se basan en sí mismo . Es un plan que también puede construir el edificio. Una clase "Usuario" crea objetos "usuario". Una clase "Dog" crea objetos "dog", etc.

Si este es el comportamiento de una clase, tiene sentido, entonces, los métodos que agregue a la clase "X" se ocuparán de crear objetos "x".

Entonces, incluso si solo va a necesitar un objeto "x", debe instanciarlo.

Agregar métodos a la clase X que no están relacionados con la creación de instancias de objetos "x" puede generar un código inesperado confuso. Por supuesto, hay toneladas de ejemplos en el mundo real donde la gente ha hecho esto de todos modos, pero como dije, ese camino conduce a la guerra religiosa.

Cormac Mulhall
fuente