Estou confuso sobre o que é um tipo imutável. Eu sei que o float
objeto é considerado imutável, com este tipo de exemplo do meu livro:
class RoundFloat(float):
def __new__(cls, val):
return float.__new__(cls, round(val, 2))
Isso é considerado imutável por causa da estrutura / hierarquia da classe ?, o significado float
está no topo da classe e é sua própria chamada de método. Semelhante a este tipo de exemplo (mesmo que meu livro diga que dict
é mutável):
class SortedKeyDict(dict):
def __new__(cls, val):
return dict.__new__(cls, val.clear())
Enquanto algo mutável tem métodos dentro da classe, com este tipo de exemplo:
class SortedKeyDict_a(dict):
def example(self):
return self.keys()
Além disso, por último class(SortedKeyDict_a)
, se eu passar esse tipo de conjunto para ele:
d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))
sem chamar o example
método, ele retorna um dicionário. O sinaliza SortedKeyDict
com __new__
como um erro. Tentei passar números inteiros para a RoundFloat
classe com __new__
e ele sinalizou sem erros.
python
immutability
mutable
user1027217
fonte
fonte
Respostas:
O que? Carros alegóricos são imutáveis? Mas não posso fazer
Isso não "mut" x?
Bem, você concorda que as cordas são imutáveis, certo? Mas você pode fazer a mesma coisa.
O valor da variável muda, mas muda alterando o que a variável se refere. Um tipo mutável pode mudar dessa maneira e também "in loco".
Aqui está a diferença.
Exemplos concretos
fonte
def f(my_list): my_list = [1, 2, 3]
. Com a passagem por referência em C, o valor do argumento pode mudar chamando essa função. No Python, essa função não faz nada.def f(my_list): my_list[:] = [1, 2, 3]
faria algo.a += b
algumas vezes, ser mutação. E o fato de que a atribuição a parte de um objeto maior às vezes significa mutação desse objeto maior, apenas nunca a mutação da parte - por exemplo,a[0] = b
não muda.a[0]
, mas provavelmente faz mutaçãoa
... qual é porque pode ser melhor não tentar colocar as coisas em termos de C ++ e, em vez apenas descrever o que Python faz em seus próprios termos ...)Você precisa entender que o Python representa todos os seus dados como objetos. Alguns desses objetos, como listas e dicionários, são mutáveis, o que significa que você pode alterar o conteúdo sem alterar a identidade. Outros objetos, como números inteiros, flutuantes, strings e tuplas, são objetos que não podem ser alterados. Uma maneira fácil de entender isso é se você der uma olhada no ID de um objeto.
Abaixo você vê uma string que é imutável. Você não pode alterar seu conteúdo. Isso aumentará um
TypeError
se você tentar alterá-lo. Além disso, se atribuirmos novo conteúdo, um novo objeto será criado em vez do conteúdo que está sendo modificado.Você pode fazer isso com uma lista e isso não mudará a identidade dos objetos
Para ler mais sobre o modelo de dados do Python, você pode dar uma olhada na referência da linguagem Python:
fonte
Tipo imutável comum:
int()
,float()
,complex()
str()
,tuple()
,frozenset()
,bytes()
Tipo mutável comum (quase tudo o resto):
list()
,bytearray()
set()
dict()
Um truque para testar rapidamente se um tipo é mutável ou não, é usar
id()
a função interna.Exemplos, usando em número inteiro,
usando na lista,
fonte
id()
. +1.id()
é enganoso aqui. Um determinado objeto sempre terá o mesmo ID durante sua vida útil, mas objetos diferentes que existem em momentos diferentes podem ter o mesmo ID devido à coleta de lixo.Primeiro de tudo, se uma classe tem métodos ou o que é sua estrutura de classe não tem nada a ver com mutabilidade.
int
sefloat
são imutáveis . Se eu fizerAponta o nome
a
para um1
lugar na memória na primeira linha. Na segunda linha, parece-se que1
, acrescenta5
, recebe6
, em seguida, pontosa
em que6
na memória - não alterar o1
a um6
de qualquer maneira. A mesma lógica se aplica aos exemplos a seguir, usando outros tipos imutáveis :Para tipos mutáveis , posso fazer algo que realmente altera o valor em que é armazenado na memória . Com:
Eu criei uma lista dos locais de
1
,2
e3
na memória. Se eu fizerEu apenas aponto
e
para os mesmoslist
d
pontos em. Eu posso então fazer:E a lista na qual ambos apontam
e
ed
será atualizada também terá os locais4
e5
na memória.Se eu voltar para um tipo imutável e fizer isso com um
tuple
:Então
f
ainda aponta apenas para o originaltuple
- você apontoug
para um totalmente novotuple
.Agora, com o seu exemplo de
Onde você passa
(que é uma
tuple
dastuples
) comoval
, você está recebendo um erro porquetuple
s não tem um.clear()
método - você teria que passardict(d)
comoval
para que ele funcione, caso em que você vai ter um vazioSortedKeyDict
, como resultado.fonte
Se você está vindo para o Python de outra linguagem (exceto uma que é muito parecida com o Python, como o Ruby) e insiste em entendê-lo em termos dessa outra linguagem, é aqui que as pessoas geralmente ficam confusas:
No Python, a atribuição não é uma mutação no Python.
No C ++, se você escrever
a = 2
, você está chamandoa.operator=(2)
, o que mudará o objeto armazenadoa
. (E se não havia nenhum objeto armazenadoa
, isso é um erro.)No Python,
a = 2
nada faz para o que foi armazenadoa
; significa apenas que2
agora está armazenadoa
. (E se não era nenhum objeto armazenado ema
, isso é bom.)Em última análise, isso faz parte de uma distinção ainda mais profunda.
Uma variável em uma linguagem como C ++ é um local digitado na memória. Se
a
for umint
, significa 4 bytes em algum lugar que o compilador sabe que deve ser interpretado como umint
. Então, quando você faza = 2
, ele muda o que é armazenado nesses 4 bytes de memória de0, 0, 0, 1
para0, 0, 0, 2
. Se houver outra variável int em outro lugar, ele possui seus próprios 4 bytes.Uma variável em uma linguagem como Python é um nome para um objeto que possui vida própria. Há um objeto para o número
1
e outro objeto para o número2
. Ea
não são 4 bytes de memória que são representados como umint
, é apenas um nome que aponta para o1
objeto. Não faz sentidoa = 2
transformar o número 1 no número 2 (isso daria a qualquer programador Python muito poder para mudar o funcionamento fundamental do universo); o que ele faz é apenasa
esquecer o1
objeto e apontar para o2
objeto.Então, se a atribuição não é uma mutação, o que é uma mutação?
a.append(b)
. (Observe que esses métodos quase sempre retornamNone
). Tipos imutáveis não possuem nenhum desses métodos, normalmente tipos mutáveis.a.spam = b
oua[0] = b
. Tipos imutáveis não permitem a atribuição de atributos ou elementos; tipos mutáveis geralmente permitem um ou outro.a += b
, às vezes não. Tipos mutáveis geralmente modificam o valor; tipos imutáveis nunca funcionam e fornecem uma cópia (eles calculama + b
e atribuem o resultado aa
).Mas se a atribuição não é mutação, como é atribuir parte da mutação do objeto? É aí que fica complicado.
a[0] = b
faz não mutaçãoa[0]
(mais uma vez, ao contrário do C ++), mas faz mutaçãoa
(ao contrário do C ++, exceto indiretamente).Tudo isso é por que provavelmente é melhor não tentar colocar a semântica do Python em termos de uma linguagem com a qual você está acostumado e, em vez disso, aprender a semântica do Python em seus próprios termos.
fonte
Se um objeto é mutável ou não, depende do seu tipo. Isso não depende de ter ou não certos métodos, nem da estrutura da hierarquia de classes.
Tipos definidos pelo usuário (ou seja, classes) são geralmente mutáveis. Existem algumas exceções, como subclasses simples de um tipo imutável. Outros tipos imutáveis incluir alguns tipos internos, como
int
,float
,tuple
estr
, assim como algumas classes Python implementado em C.Uma explicação geral do capítulo "Modelo de dados" na Referência da linguagem Python " :
fonte
Diferença entre objetos Mutáveis e Imutáveis
Definições
Objeto mutável : objeto que pode ser alterado após a criação.
Objeto imutável : objeto que não pode ser alterado após a criação.
Em python, se você alterar o valor do objeto imutável, ele criará um novo objeto.
Objetos mutáveis
Aqui estão os objetos em Python que são do tipo mutável:
list
Dictionary
Set
bytearray
user defined classes
Objetos imutáveis
Aqui estão os objetos em Python que são do tipo imutável:
int
float
decimal
complex
bool
string
tuple
range
frozenset
bytes
Algumas perguntas não respondidas
Perguntas : String é um tipo imutável?
Resposta : sim , mas você pode explicar isso: Prova 1 :
Resultado
No exemplo acima, a string foi criada como "Hello" e depois foi alterada para "Hello World". Isso implica que a string é do tipo mutável. Mas não é quando checamos sua identidade para ver se é de um tipo mutável ou não.
Resultado
Prova 2 :
Resultado
Perguntas : Tuple é um tipo imutável?
Resposta : sim , é. Prova 1 :
Resultado
fonte
Um objeto mutável deve ter pelo menos um método capaz de mutá-lo. Por exemplo, o
list
objeto possui oappend
método, que na verdade muda o objeto:mas a classe
float
não tem método para alterar um objeto flutuante. Você pode fazer:mas o
=
operando não é um método. Apenas cria uma ligação entre a variável e o que estiver à direita dela, nada mais. Ele nunca muda ou cria objetos. É uma declaração do que a variável apontará, desde agora.Quando você executa
b = b + 0.1
o=
operando, vincula a variável a um novo float, que é criado com o resultado de5 + 0.1
.Quando você atribui uma variável a um objeto existente, mutável ou não, o
=
operando vincula a variável a esse objeto. E nada mais aconteceEm ambos os casos, o
=
justo faz a ligação. Não muda ou cria objetos.Quando você faz
a = 1.0
, o=
operando não é o que cria o flutuador, mas a1.0
parte da linha. Na verdade, quando você escreve1.0
, é uma abreviação parafloat(1.0)
uma chamada de construtor retornando um objeto flutuante. (Essa é a razão pela qual, se você digitar1.0
e pressionar enter, obtém o "eco"1.0
impresso abaixo; esse é o valor de retorno da função construtora que você chamou)Agora, se
b
é um float e você atribuia = b
, as duas variáveis estão apontando para o mesmo objeto, mas, na verdade, as variáveis não podem se comunicar entre si, porque o objeto é imutável e, se o fizerb += 1
, agorab
aponta para um novo objeto ea
é ainda apontando para o idoso e não pode saber o queb
está apontando.mas se
c
for, digamos, alist
, e você atribuira = c
agoraa
ec
puder "se comunicar", porquelist
é mutável, e se o fizerc.append('msg')
, basta verificar sea
você recebe a mensagem.(A propósito, todo objeto tem um número de identificação exclusivo associado, com o qual você pode entrar
id(x)
. Assim, você pode verificar se um objeto é o mesmo ou se não está verificando se seu ID exclusivo foi alterado.)fonte
Em outra palavra, altere o valor inteiro dessa variável
(name)
ou deixe em paz.Exemplo:
você esperava que isso funcionasse e imprimisse olá mundo, mas isso geraria o seguinte erro:
O intérprete está dizendo: não consigo alterar o primeiro caractere dessa string
você precisará alterar o todo
string
para que funcione:verifique esta tabela:
fonte
fonte
my_string = 'h' + my_string[1:]
. Isso irá gerar uma nova string chamada my_string, e o original my_string se foi (imprimaid(my_string)
para ver isso). Claro que isso não é muito flexível; para o caso mais geral, você pode converter em lista e voltar: #l = list(my_string)
l[0] = 'h'
my_string = ''.join(l)
Parece-me que você está lutando com a pergunta que mutável / imutável realmente significa . Então, aqui está uma explicação simples:
Primeiro, precisamos de uma base para basear a explicação.
Então pense em qualquer coisa que você programa como um objeto virtual, algo que é salvo na memória do computador como uma sequência de números binários. (Não tente imaginar isso muito difícil. ^^) Agora, na maioria das linguagens de computador, você não trabalha diretamente com esses números binários, mas, mais ainda, usa uma interpretação dos números binários.
Por exemplo, você não pensa em números como 0x110, 0xaf0278297319 ou similar, mas pensa em números como 6 ou Strings como "Olá, mundo". Mesmo assim, esses números ou seqüências de caracteres são uma interpretação de um número binário na memória do computador. O mesmo vale para qualquer valor de uma variável.
Em suma: Nós não programar com valores reais, mas com interpretações de valores binários reais.
Agora, temos interpretações que não devem ser alteradas por razões de lógica e outras "coisas legais", enquanto há interpretações que podem muito bem ser alteradas. Por exemplo, pense na simulação de uma cidade, em outras palavras, um programa onde existem muitos objetos virtuais e alguns deles são casas. Agora, esses objetos virtuais (as casas) podem ser alterados e ainda podem ser considerados as mesmas casas? Bem, é claro que eles podem. Assim, eles são mutáveis: podem ser alterados sem se tornar um objeto "completamente" diferente.
Agora pense em números inteiros: esses também são objetos virtuais (sequências de números binários na memória de um computador). Então, se mudarmos um deles, como aumentar o valor seis por um, ainda é um seis? Bem, claro que não. Assim, qualquer número inteiro é imutável.
Portanto: se qualquer alteração em um objeto virtual significa que ele realmente se torna outro objeto virtual, é chamado de imutável.
Considerações finais:
(1) Nunca misture sua experiência no mundo real de mutável e imutável com a programação em um determinado idioma:
Toda linguagem de programação possui uma definição própria sobre quais objetos podem ser silenciados e quais não.
Portanto, embora agora você possa entender a diferença de significado, ainda precisa aprender a implementação real de cada linguagem de programação. ... De fato, pode haver o propósito de uma linguagem na qual um 6 pode ser silenciado para se tornar um 7. Então, novamente, isso seria algo muito louco ou interessante, como simulações de universos paralelos.
(2) Essa explicação certamente não é científica, serve para ajudá-lo a entender a diferença entre mutável e imutável.
fonte
O objetivo desta resposta é criar um único local para encontrar todas as boas idéias sobre como saber se você está lidando com mutação / não mutação (imutável / mutável) e, sempre que possível, o que fazer sobre isso? Há momentos em que a mutação é indesejável e o comportamento do python a esse respeito pode parecer contra-intuitivo para os codificadores que acessam outras linguagens.
De acordo com um post útil de @ mina-gabriel:
Analisando o acima e combinando com uma postagem de @ arrakëën:
O que não pode mudar inesperadamente?
O que pode?
por "inesperadamente", quero dizer que programadores de outras linguagens podem não esperar esse comportamento (com exceção do Ruby e talvez algumas outras linguagens "do tipo Python").
Adicionando a esta discussão:
Esse comportamento é uma vantagem quando impede que você preencha acidentalmente seu código com várias cópias de grandes estruturas de dados que consomem memória. Mas quando isso é indesejável, como contornar isso?
Com as listas, a solução simples é criar uma nova assim:
lista2 = lista (lista1)
com outras estruturas ... a solução pode ser mais complicada. Uma maneira é percorrer os elementos e adicioná-los a uma nova estrutura de dados vazia (do mesmo tipo).
funções podem alterar o original quando você passa em estruturas mutáveis. Como dizer?
Abordagens não padrão (se útil): Encontrei isso no github publicado sob uma licença MIT:
Para classes personalizadas, @semicolon sugere verificar se há uma
__hash__
função, porque objetos mutáveis geralmente não devem ter um__hash__()
função.É tudo o que acumulei neste tópico por enquanto. Outras idéias, correções, etc. são bem-vindas. Obrigado.
fonte
Uma maneira de pensar na diferença:
As atribuições a objetos imutáveis em python podem ser consideradas cópias profundas, enquanto as atribuições a objetos mutáveis são rasas
fonte
A resposta mais simples:
Uma variável mutável é aquela cujo valor pode mudar no local, enquanto em uma variável imutável a mudança de valor não ocorrerá no local. Modificar uma variável imutável reconstruirá a mesma variável.
Exemplo:
Criará um valor 5 referenciado por x
x -> 5
Esta declaração fará com que você se refira a 5 de x
x -------------> 5 <----------- y
Como x sendo um número inteiro (tipo imutável) foi reconstruído.
Na instrução, a expressão no RHS resultará no valor 10 e, quando for atribuído ao LHS (x), x será reconstruído para 10. Então, agora
x ---------> 10
y ---------> 5
fonte
Não li todas as respostas, mas a resposta selecionada não está correta e acho que o autor tem uma ideia de que ser capaz de reatribuir uma variável significa que qualquer tipo de dados é mutável. Esse não é o caso. Mutabilidade tem a ver com passagem por referência, em vez de passagem por valor.
Digamos que você criou uma lista
Se você dissesse:
Mesmo que você tenha reatribuído um valor em B, ele também reatribuirá o valor em a. É porque quando você atribui "b = a". Você está passando a "Referência" para o objeto em vez de uma cópia do valor. Este não é o caso de strings, floats etc. Isso torna a lista, dicionários e os gostos mutáveis, mas booleanos, floats etc. imutáveis.
fonte
Para objetos imutáveis, a atribuição cria uma nova cópia de valores, por exemplo.
Para objetos mutáveis, a atribuição não cria outra cópia dos valores. Por exemplo,
fonte
x=10
é simplesmente outra tarefa , enquantox[2] = 5
chama um método mutador.int
objetos simplesmente não têm métodos modificadores , mas a semântica de atribuição python não dependem do tipoNo Python, há uma maneira fácil de saber:
Imutável:
Mutável:
E:
Então, eu acho que a função interna também é imutável no Python.
Mas eu realmente não entendo como o float funciona:
Isto é tão estranho.
fonte
x = (1, 2)
e tente mudarx
, não é possível. Uma maneira que eu encontrei para verificar a mutabilidade é quehash
ela funciona para os objetos internos, pelo menos.hash(1)
hash('a')
hash((1, 2))
hash(True)
tudo funciona ehash([])
hash({})
hash({1, 2})
tudo não funciona.hash()
ele funcionará se o objeto definir um__hash__()
método, mesmo que as classes definidas pelo usuário sejam geralmente mutáveis.hash
método ainda é bastante bom, porque objetos mutáveis geralmente não devem ter um__hash__()
método, pois torná-los chaves em um dicionário é apenas perigoso.