Classes Python com apenas uma instância: quando criar uma instância de classe (única) e quando trabalhar com a classe?

11

Dada uma classe Python que será instanciada apenas uma vez, ou seja, haverá apenas um objeto da classe. Eu queria saber em quais casos, faz sentido criar uma instância de classe única em vez de trabalhar diretamente com a classe.

Há uma pergunta semelhante , mas tem um foco diferente:

  1. trata-se de agrupar variáveis ​​e funções globais em uma classe e
  2. Não é específico do Python. O último significa que não considera o fato de que (em Python) as classes também são objetos.

ATUALIZAR:

No Python, eu posso fazer o seguinte com classes e 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

Portanto, não vejo como a escolha entre uma classe e uma instância dessa classe é sobre estado (em Python). Eu posso manter um estado com qualquer um dos dois.

Além disso, a motivação para criar minha classe / instância de classe não é impor um requisito Singleton.

Além disso, não se trata tanto de criar um novo tipo.

A motivação é agrupar códigos e dados relacionados e ter uma interface para eles. Foi por isso que inicialmente o modelei como uma classe em um diagrama de classes. Somente quando se tratou da implementação, comecei a me perguntar se instanciaria essa classe ou não.

langlauf.io
fonte

Respostas:

16

Dada uma classe Python que será instanciada apenas uma vez, ou seja, haverá apenas um objeto da classe. Eu queria saber em quais casos, faz sentido criar uma instância de classe única em vez de trabalhar diretamente com a classe.

Então é isso:

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

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

contra isso?

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

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

Recomendação

Definitivamente, eu preferiria o que se pretende instanciar. Quando você cria um "tipo de coisa", isso implica que você cria coisas desse tipo.

A motivação é agrupar códigos e dados relacionados e ter uma interface para eles.

Dito isto, por que não usar apenas um módulo, pois tudo que você deseja é um espaço para nome? Os módulos são singletons, código e dados relacionados ao grupo, e isso é um pouco mais simples e provavelmente seria considerado mais Pythonic:

var1 ='foo'

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

Portanto, o uso seria em vez de:

from modules.singleton import Singleton
Singleton.foobar()

ou

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

faça isso:

from modules import singleton
singleton.foobar()
Aaron Hall
fonte
3
Obrigado pela sua resposta. Você realmente sugeriria a criação de um novo módulo (um novo arquivo .py) para todas as funções (incluindo variáveis)? Isso pode resultar em muitos arquivos .py pequenos. Ou você agruparia todas (pelo menos de alguma forma relacionadas) funções e variáveis ​​"sem classe" em um módulo?
langlauf.io
Mais uma observação: você escreve "já que tudo que você quer é um espaço para nome". O que eu quero é agrupar código relacionado, isto é, funções e dados, em um só lugar, e ter uma interface para ele. Não se trata muito de criar um "Tipo". De qualquer maneira, durante o design, isso resultaria em uma classe em um diagrama de classes, não?
langlauf.io
2

Eu queria saber em quais casos, faz sentido criar uma instância de classe única em vez de trabalhar diretamente com a classe.

Essa é uma daquelas coisas que causará uma guerra religiosa se você se envolver muito nela.

Mas, em geral, uma prática que já vi muitas vezes é que os métodos de classe devem se preocupar apenas em criar instâncias dessa classe.

Se você pensa sobre o que é uma classe, qual é seu objetivo / comportamento, isso faz sentido. O objetivo de uma classe é criar instâncias de objetos baseados em si mesmos . É um projeto que também pode construir o edifício. Uma classe "Usuário" cria objetos "usuário". Uma classe "Dog" cria objetos "dog" etc etc

Dado que esse é o comportamento de uma classe, faz sentido que os métodos adicionados à classe "X" se preocupem em criar objetos "x".

Portanto, mesmo que você precise apenas de um objeto "x", você ainda deve instancia-lo.

Adicionar métodos à classe X que não estejam relacionados à criação de instâncias de objetos "x" pode levar a códigos inesperados confusos. É claro que existem muitos exemplos no mundo real em que as pessoas fizeram isso de qualquer maneira, mas, como eu disse, esse caminho leva à guerra religiosa.

Cormac Mulhall
fonte