O que eu quero é esse comportamento:
class a:
list = []
x = a()
y = a()
x.list.append(1)
y.list.append(2)
x.list.append(3)
y.list.append(4)
print(x.list) # prints [1, 3]
print(y.list) # prints [2, 4]
Obviamente, o que realmente acontece quando imprimo é:
print(x.list) # prints [1, 2, 3, 4]
print(y.list) # prints [1, 2, 3, 4]
Claramente eles estão compartilhando os dados em sala de aula a
. Como obtenho instâncias separadas para alcançar o comportamento que desejo?
list
como um nome de atributo.list
é uma função embutida para construir uma nova lista. Você deve escrever classes de nome com letra maiúscula.Respostas:
Você quer isso:
Declarar as variáveis dentro da declaração de classe faz com que sejam membros da "classe" e não membros da instância. Declará-los dentro do
__init__
método garante que uma nova instância dos membros seja criada ao lado de cada nova instância do objeto, que é o comportamento que você está procurando.fonte
x.list = []
, poderá alterá-lo e não afetar outros. O problema que você enfrenta é essax.list
ey.list
é a mesma lista; portanto, quando você chama o anexo em um, isso afeta o outro.__init__
.A resposta aceita funciona, mas um pouco mais de explicação não dói.
Atributos de classe não se tornam atributos de instância quando uma instância é criada. Eles se tornam atributos de instância quando um valor é atribuído a eles.
No código original, nenhum valor é atribuído ao
list
atributo após a instanciação; portanto, permanece um atributo de classe. A definição de lista interna__init__
funciona porque__init__
é chamada após a instanciação. Como alternativa, esse código também produziria a saída desejada:No entanto, o cenário confuso da pergunta nunca acontecerá com objetos imutáveis, como números e cadeias, porque seu valor não pode ser alterado sem atribuição. Por exemplo, um código semelhante ao original com o tipo de atributo string funciona sem nenhum problema:
Então, para resumir: os atributos de classe tornam-se atributos de instância se e somente se um valor é atribuído a eles após a instanciação, estando no
__init__
método ou não . Isso é bom porque dessa forma você pode ter atributos estáticos se nunca atribuir um valor a um atributo após a instanciação.fonte
Você declarou "lista" como "propriedade de nível de classe" e não "propriedade de nível de instância". Para ter propriedades com escopo definido no nível da instância, é necessário inicializá-las através da referência ao parâmetro "self" no
__init__
método (ou em outro lugar, dependendo da situação).Você não precisa estritamente inicializar as propriedades da instância no
__init__
método, mas facilita o entendimento.fonte
Embora a resposta aceita esteja correta, eu gostaria de adicionar uma pequena descrição.
Vamos fazer um pequeno exercício
Antes de tudo, defina uma classe da seguinte maneira:
Então o que temos aqui?
temp
que é uma string__init__
método que defineself.x
self.temp
Bem direto até agora, sim? Agora vamos começar a brincar com essa classe. Vamos inicializar esta classe primeiro:
Agora faça o seguinte:
Bem,
a.temp
funcionou como esperado, mas como diabosA.temp
funcionou? Bem, funcionou porque temp é um atributo de classe. Tudo em python é um objeto. Aqui A também é um objeto de classetype
. Portanto, o atributo temp é um atributo mantido pelaA
classe e se você alterar o valor de temp atravésA
(e não através de uma instância dea
), o valor alterado será refletido em toda a instância daA
classe. Vamos em frente e faça isso:Interessante, não é? E note que
id(a.temp)
eid(A.temp)
ainda são os mesmos .Qualquer objeto Python recebe automaticamente um
__dict__
atributo, que contém sua lista de atributos. Vamos investigar o que esse dicionário contém para nossos objetos de exemplo:Observe que o
temp
atributo é listado entreA
os atributos da classe, enquantox
é listado para a instância.Então, como é que obtemos um valor definido
a.temp
se ele nem está listado para a instânciaa
? Bem, essa é a mágica do__getattribute__()
método. No Python, a sintaxe pontilhada invoca automaticamente esse método; portanto, quando escrevemosa.temp
, o Python é executadoa.__getattribute__('temp')
. Esse método executa a ação de pesquisa de atributo, ou seja, localiza o valor do atributo procurando em lugares diferentes.A implementação padrão de
__getattribute__()
pesquisas primeiro no dicionário interno ( dict ) de um objeto, depois no tipo do objeto em si. Nesse caso,a.__getattribute__('temp')
executa primeiroa.__dict__['temp']
e depoisa.__class__.__dict__['temp']
Ok, agora vamos usar o nosso
change
método:Bem, agora que usamos
self
,print(a.temp)
nos dá um valor diferente deprint(A.temp)
.Agora, se compararmos
id(a.temp)
eid(A.temp)
, eles serão diferentes.fonte
Sim, você deve declarar no "construtor" se desejar que a lista se torne uma propriedade de objeto e não uma propriedade de classe.
fonte
Portanto, quase todas as respostas aqui parecem perder um ponto específico. Variáveis de classe nunca se tornam variáveis de instância, conforme demonstrado pelo código abaixo. Utilizando uma metaclasse para interceptar a atribuição de variável no nível da classe, podemos ver que quando a.myattr é reatribuído, o método mágico de atribuição de campo na classe não é chamado. Isso ocorre porque a atribuição cria uma nova variável de instância . Esse comportamento não tem absolutamente nada a ver com a variável de classe, como demonstrado pela segunda classe, que não possui variáveis de classe e ainda permite a atribuição de campos.
IN SHORT As variáveis de classe não têm nada a ver com variáveis de instância.
Mais claramente Eles estão no escopo de pesquisas em instâncias. Variáveis de classe são de fato variáveis de instância no próprio objeto de classe. Você também pode ter variáveis de metaclasse, se desejar, porque as metaclasses também são objetos. Tudo é um objeto, seja ele usado para criar outros objetos ou não, portanto, não fique vinculado à semântica do uso de outras línguas da classe de palavras. Em python, uma classe é realmente apenas um objeto usado para determinar como criar outros objetos e quais serão seus comportamentos. Metaclasses são classes que criam classes, apenas para ilustrar melhor este ponto.
fonte
Para proteger sua variável compartilhada por outra instância, você precisa criar uma nova variável de instância sempre que criar uma instância. Quando você está declarando uma variável dentro de uma classe, ela é variável e compartilhada por todas as instâncias. Se você quiser fazê-lo, por exemplo, é necessário usar o método init para reinicializar a variável, conforme a instância
Dos objetos e classe Python da Programiz.com :
Por exemplo:
fonte