Tipos imutáveis ​​vs mutáveis

186

Estou confuso sobre o que é um tipo imutável. Eu sei que o floatobjeto é 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 floatestá 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 examplemétodo, ele retorna um dicionário. O sinaliza SortedKeyDictcom __new__como um erro. Tentei passar números inteiros para a RoundFloatclasse com __new__e ele sinalizou sem erros.

user1027217
fonte
Você também pode verificar a atribuição de lista com [:] e python quando usar copy.copy, que eu também respondi para obter mais informações sobre mutabilidade.
agf

Respostas:

232

O que? Carros alegóricos são imutáveis? Mas não posso fazer

x = 5.0
x += 7.0
print x # 12.0

Isso não "mut" x?

Bem, você concorda que as cordas são imutáveis, certo? Mas você pode fazer a mesma coisa.

s = 'foo'
s += 'bar'
print s # foobar

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.

x = something # immutable type
print x
func(x)
print x # prints the same thing

x = something # mutable type
print x
func(x)
print x # might print something different

x = something # immutable type
y = x
print x
# some statement that operates on y
print x # prints the same thing

x = something # mutable type
y = x
print x
# some statement that operates on y
print x # might print something different

Exemplos concretos

x = 'foo'
y = x
print x # foo
y += 'bar'
print x # foo

x = [1, 2, 3]
y = x
print x # [1, 2, 3]
y += [3, 2, 1]
print x # [1, 2, 3, 3, 2, 1]

def func(val):
    val += 'bar'

x = 'foo'
print x # foo
func(x)
print x # foo

def func(val):
    val += [3, 2, 1]

x = [1, 2, 3]
print x # [1, 2, 3]
func(x)
print x # [1, 2, 3, 3, 2, 1]
estrela da Manhã
fonte
5
O que você explica significa para mim: variáveis ​​mutáveis ​​são passadas por referência, variáveis ​​imutáveis ​​são passadas por valor. Isso está correto?
Lorenz Meyer
17
Quase, mas não exatamente. Tecnicamente, todas as variáveis ​​são passadas por referência em Python, mas têm uma semântica mais parecida com a passagem por valor em C. Um contra-exemplo à sua analogia é se você o fizer 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.
Morningstar
6
Tipos mutáveis ​​podem ser alterados no local. Tipos imutáveis ​​não podem mudar de lugar. É assim que o python vê o mundo. Independentemente de como as variáveis ​​são passadas para as funções.
ychaouche
13
A principal diferença entre a semântica do Python e a semântica de passagem por referência do C ++ é que a atribuição não é uma mutação no Python e está no C ++. (Mas é claro que isso é complicado pelo fato de uma atribuição aumentada, como a += balgumas 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] = bnão muda. a[0], mas provavelmente faz mutação a... 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 ...)
abarnert
2
Achei esta resposta enganosa porque não usa id (), essencial para entender o que significa imutável.
pawel_winzig
185

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 TypeErrorse 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.

>>> s = "abc"
>>>id(s)
4702124
>>> s[0] 
'a'
>>> s[0] = "o"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> s = "xyz"
>>>id(s)
4800100
>>> s += "uvw"
>>>id(s)
4800500

Você pode fazer isso com uma lista e isso não mudará a identidade dos objetos

>>> i = [1,2,3]
>>>id(i)
2146718700
>>> i[0] 
1
>>> i[0] = 7
>>> id(i)
2146718700

Para ler mais sobre o modelo de dados do Python, você pode dar uma olhada na referência da linguagem Python:

sebs
fonte
4
+1 Para o link para os documentos do Python. No entanto, demorei algum tempo até eu perceber que hoje você precisa diferenciar entre Python 2 e 3 - atualizei a resposta para enfatizar isso.
Benjamin
107

Tipo imutável comum:

  1. números: int(), float(),complex()
  2. sequências imutáveis: str(), tuple(), frozenset(),bytes()

Tipo mutável comum (quase tudo o resto):

  1. sequências mutáveis: list(),bytearray()
  2. definir tipo: set()
  3. tipo de mapeamento: dict()
  4. classes, instâncias de classe
  5. etc.

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,

>>> i = 1
>>> id(i)
***704
>>> i += 1
>>> i
2
>>> id(i)
***736 (different from ***704)

usando na lista,

>>> a = [1]
>>> id(a)
***416
>>> a.append(2)
>>> a
[1, 2]
>>> id(a)
***416 (same with the above id)
Espectral
fonte
11
Bem explicado. Gostei do conceito de verificar por id(). +1.
Parag Tyagi
4
Na verdade, o uso de 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.
Aug
37

Primeiro de tudo, se uma classe tem métodos ou o que é sua estrutura de classe não tem nada a ver com mutabilidade.

intse floatsão imutáveis . Se eu fizer

a = 1
a += 5

Aponta o nome apara um 1lugar na memória na primeira linha. Na segunda linha, parece-se que 1, acrescenta 5, recebe 6, em seguida, pontos aem que 6na memória - não alterar o 1a um 6de qualquer maneira. A mesma lógica se aplica aos exemplos a seguir, usando outros tipos imutáveis :

b = 'some string'
b += 'some other string'
c = ('some', 'tuple')
c += ('some', 'other', 'tuple')

Para tipos mutáveis , posso fazer algo que realmente altera o valor em que é armazenado na memória . Com:

d = [1, 2, 3]

Eu criei uma lista dos locais de 1, 2e 3na memória. Se eu fizer

e = d

Eu apenas aponto epara os mesmoslist d pontos em. Eu posso então fazer:

e += [4, 5]

E a lista na qual ambos apontam ee dserá atualizada também terá os locais 4e 5na memória.

Se eu voltar para um tipo imutável e fizer isso com um tuple:

f = (1, 2, 3)
g = f
g += (4, 5)

Então fainda aponta apenas para o originaltuple - você apontou gpara um totalmente novotuple .

Agora, com o seu exemplo de

class SortedKeyDict(dict):
    def __new__(cls, val):
        return dict.__new__(cls, val.clear())

Onde você passa

d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))

(que é uma tupledas tuples) como val, você está recebendo um erro porque tuples não tem um .clear()método - você teria que passar dict(d)como valpara que ele funcione, caso em que você vai ter um vazio SortedKeyDict, como resultado.

agf
fonte
2
Esta é uma explicação muito boa. Adorei essa pergunta e várias perspectivas (novas) interessantes para explicá-la.
Cientista falhado
25

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:

>>> a = 1
>>> a = 2 # I thought int was immutable, but I just changed it?!

No Python, a atribuição não é uma mutação no Python.

No C ++, se você escrever a = 2, você está chamando a.operator=(2), o que mudará o objeto armazenado a. (E se não havia nenhum objeto armazenado a, isso é um erro.)

No Python, a = 2nada faz para o que foi armazenado a; significa apenas que 2agora está armazenado a. (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 afor um int, significa 4 bytes em algum lugar que o compilador sabe que deve ser interpretado como um int. Então, quando você faz a = 2, ele muda o que é armazenado nesses 4 bytes de memória de 0, 0, 0, 1para 0, 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 1e outro objeto para o número 2. E anão são 4 bytes de memória que são representados como um int, é apenas um nome que aponta para o 1objeto. Não faz sentido a = 2transformar 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 é apenas aesquecer o 1objeto e apontar para o 2objeto.


Então, se a atribuição não é uma mutação, o que é uma mutação?

  • Chamar um método que está documentado para sofrer mutação, como a.append(b). (Observe que esses métodos quase sempre retornam None). Tipos imutáveis ​​não possuem nenhum desses métodos, normalmente tipos mutáveis.
  • Atribuindo a uma parte do objeto, como a.spam = bou a[0] = b. Tipos imutáveis ​​não permitem a atribuição de atributos ou elementos; tipos mutáveis ​​geralmente permitem um ou outro.
  • Às vezes, usando atribuição aumentada a += b, às vezes não. Tipos mutáveis ​​geralmente modificam o valor; tipos imutáveis ​​nunca funcionam e fornecem uma cópia (eles calculam a + be atribuem o resultado a a).

Mas se a atribuição não é mutação, como é atribuir parte da mutação do objeto? É aí que fica complicado. a[0] = bfaz não mutação a[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.

abarnert
fonte
2
Diga a = 'oi'. a [0] = 'f' terá 'print a' print '' fi '(Estou certo até agora?), portanto, quando você diz que não modifica a [0], sim a, o que isso significa ? Um [n] também tem seu próprio lugar agora e a alteração de seu valor o aponta para um valor diferente?
Daniel Springer
19

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, tupleestr , assim como algumas classes Python implementado em C.

Uma explicação geral do capítulo "Modelo de dados" na Referência da linguagem Python " :

O valor de alguns objetos pode mudar. Os objetos cujo valor pode mudar são considerados mutáveis; objetos cujo valor é imutável após a criação são chamados imutáveis.

(O valor de um objeto contêiner imutável que contém uma referência a um objeto mutável pode mudar quando o valor deste último é alterado; no entanto, o contêiner ainda é considerado imutável, porque a coleção de objetos que ele contém não pode ser alterada. Portanto, a imutabilidade não é estritamente o mesmo que ter um valor imutável, é mais sutil.)

A mutabilidade de um objeto é determinada por seu tipo; por exemplo, números, strings e tuplas são imutáveis, enquanto dicionários e listas são mutáveis.

taleinat
fonte
+1 Observe que apenas alguns tipos de extensão (você pode revisar sua definição disso, todos os tipos internos do Python são implementados em C) são imutáveis. Outros (a maioria, ouso dizer) são perfeitamente mutáveis.
@ delnan Como você chama "tipos de extensões" ?
Eyquem
@eyquem: usei o termo "tipos de extensão" incorretamente na minha resposta, e delnan estava se referindo a isso. Após seu comentário, revisei minha resposta e evitei usar esse termo.
taleinat
19

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:

  1. list
  2. Dictionary
  3. Set
  4. bytearray
  5. user defined classes

Objetos imutáveis

Aqui estão os objetos em Python que são do tipo imutável:

  1. int
  2. float
  3. decimal
  4. complex
  5. bool
  6. string
  7. tuple
  8. range
  9. frozenset
  10. bytes

Algumas perguntas não respondidas

Perguntas : String é um tipo imutável?
Resposta : sim , mas você pode explicar isso: Prova 1 :

a = "Hello"
a +=" World"
print a

Resultado

"Hello World"

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.

a = "Hello"
identity_a = id(a)
a += " World"
new_identity_a = id(a)
if identity_a != new_identity_a:
    print "String is Immutable"

Resultado

String is Immutable

Prova 2 :

a = "Hello World"
a[0] = "M"

Resultado

TypeError 'str' object does not support item assignment

Perguntas : Tuple é um tipo imutável?
Resposta : sim , é. Prova 1 :

tuple_a = (1,)
tuple_a[0] = (2,)
print a

Resultado

'tuple' object does not support item assignment
anand tripathi
fonte
In [46]: a = "Hello" In [47]: id (a) Out [47]: 140071263880128 In [48]: a = a.replace ("H", "g") Em [49]: a Out [49]: 'gello' In [50]: id (a) Out [50]: 140071263881040
Argus Malware
você gostaria de provar seu problema de atribuição de itens ao meu exemplo acima
Argus Malware
a atribuição de itens não é problema em tipos imutáveis. No seu caso, você está alterando a string a, mas na memória está atribuindo uma nova variável. A atribuição de itens no meu caso não alterará a memória da variável, como no caso de lista ou dicionário. se você estiver fazendo substituir você está criando uma nova variável não modificar variável existente
Anand tripathi
@ArgusMalware no seu caso, dois ID são iguais por causa do primeiro reciclado pelo GC; portanto, o segundo reutiliza a memória.
Cologler
11

Um objeto mutável deve ter pelo menos um método capaz de mutá-lo. Por exemplo, o listobjeto possui o appendmétodo, que na verdade muda o objeto:

>>> a = [1,2,3]
>>> a.append('hello') # `a` has mutated but is still the same object
>>> a
[1, 2, 3, 'hello']

mas a classe floatnão tem método para alterar um objeto flutuante. Você pode fazer:

>>> b = 5.0 
>>> b = b + 0.1
>>> b
5.1

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.1o =operando, vincula a variável a um novo float, que é criado com o resultado de 5 + 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 acontece

Em 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 a 1.0parte da linha. Na verdade, quando você escreve 1.0, é uma abreviação para float(1.0)uma chamada de construtor retornando um objeto flutuante. (Essa é a razão pela qual, se você digitar 1.0e pressionar enter, obtém o "eco" 1.0impresso abaixo; esse é o valor de retorno da função construtora que você chamou)

Agora, se bé um float e você atribui a = 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 fizer b += 1, agora baponta para um novo objeto e aé ainda apontando para o idoso e não pode saber o que bestá apontando.

mas se cfor, digamos, a list, e você atribuir a = cagora ae cpuder "se comunicar", porque listé mutável, e se o fizer c.append('msg'), basta verificar se avocê 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.)

nadapez
fonte
6

Uma classe é imutável se cada objeto dessa classe tiver um valor fixo por instanciação que não possa ser SUBSEQUENTEMENTE alterado.

Em outra palavra, altere o valor inteiro dessa variável (name)ou deixe em paz.

Exemplo:

my_string = "Hello world" 
my_string[0] = "h"
print my_string 

você esperava que isso funcionasse e imprimisse olá mundo, mas isso geraria o seguinte erro:

Traceback (most recent call last):
File "test.py", line 4, in <module>
my_string[0] = "h"
TypeError: 'str' object does not support item assignment

O intérprete está dizendo: não consigo alterar o primeiro caractere dessa string

você precisará alterar o todo stringpara que funcione:

my_string = "Hello World" 
my_string = "hello world"
print my_string #hello world

verifique esta tabela:

insira a descrição da imagem aqui

fonte

Mina Gabriel
fonte
Como se pode modificar componentes de uma string python de maneira mais concisa do que você mostrou acima?
Luke Davis
@LukeDavis Você poderia fazer my_string = 'h' + my_string[1:]. Isso irá gerar uma nova string chamada my_string, e o original my_string se foi (imprima id(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)
danio
5

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.

Markus Alpers
fonte
5

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?

  • escalares (tipos de variáveis ​​que armazenam um único valor) não são alterados inesperadamente
    • exemplos numéricos: int (), float (), complexo ()
  • existem algumas "sequências mutáveis":
    • str (), tupla (), frozenset (), bytes ()

O que pode?

  • lista como objetos (listas, dicionários, conjuntos, bytearray ())
  • um post aqui também diz classes e instâncias de classe, mas isso pode depender do que a classe herda e / ou como é construída.

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?

  • Existem alguns testes feitos em outros comentários neste tópico, mas há comentários indicando que esses testes não são uma prova completa
  • object.function () é um método do objeto original, mas apenas alguns deles sofrem mutação. Se eles não devolvem nada, provavelmente o fazem. Seria de esperar que o .append () sofresse uma mutação sem testar o nome. .union () retorna a união de set1.union (set2) e não sofre mutação. Em caso de dúvida, a função pode ser verificada quanto a um valor de retorno. Se return = None, ele não muda.
  • Sorted () pode ser uma solução alternativa em alguns casos. Como ele retorna uma versão classificada do original, pode permitir que você armazene uma cópia não mutada antes de começar a trabalhar no original de outras maneiras. No entanto, essa opção pressupõe que você não se preocupa com a ordem dos elementos originais (se precisar, precisa encontrar outra maneira). Por outro lado, .sort () modifica o original (como seria de esperar).

Abordagens não padrão (se útil): Encontrei isso no github publicado sob uma licença MIT:

  • Repositório do github em: tobgu chamado: pyrsistent
  • O que é: código de estrutura de dados persistente do Python escrito para ser usado no lugar das estruturas de dados principais quando a mutação é indesejável

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.

TMWP
fonte
3

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

Aditya Sihag
fonte
1
Isto está incorreto. Todas as atribuições no Python são por referência. Não há cópia envolvida.
Aug
3

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:

>>>x = 5

Criará um valor 5 referenciado por x

x -> 5

>>>y = x

Esta declaração fará com que você se refira a 5 de x

x -------------> 5 <----------- y

>>>x = x + 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

Amit Upadhyay
fonte
-1

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

a = [1,2]

Se você dissesse:

b = a
b[1] = 3

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.

Scott
fonte
-1

Para objetos imutáveis, a atribuição cria uma nova cópia de valores, por exemplo.

x=7
y=x
print(x,y)
x=10 # so for immutable objects this creates a new copy so that it doesnot 
#effect the value of y
print(x,y)

Para objetos mutáveis, a atribuição não cria outra cópia dos valores. Por exemplo,

x=[1,2,3,4]
print(x)
y=x #for immutable objects assignment doesn't create new copy 
x[2]=5
print(x,y) # both x&y holds the same list
Ravi Gurnatham
fonte
1
Absolutamente incorreto. A atribuição nunca cria uma cópia . Por favor, leia nedbatchelder.com/text/names.html No primeiro caso, x=10é simplesmente outra tarefa , enquanto x[2] = 5chama um método mutador. intobjetos simplesmente não têm métodos modificadores , mas a semântica de atribuição python não dependem do tipo
juanpa.arrivillaga
-2

No Python, há uma maneira fácil de saber:

Imutável:

    >>> s='asd'
    >>> s is 'asd'
    True
    >>> s=None
    >>> s is None
    True
    >>> s=123
    >>> s is 123
    True

Mutável:

>>> s={}
>>> s is {}
False
>>> {} is {}
Flase
>>> s=[1,2]
>>> s is [1,2]
False
>>> s=(1,2)
>>> s is (1,2)
False

E:

>>> s=abs
>>> s is abs
True

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:

>>> s=12.3
>>> s is 12.3
False
>>> 12.3 is 12.3
True
>>> s == 12.3
True
>>> id(12.3)
140241478380112
>>> id(s)
140241478380256
>>> s=12.3
>>> id(s)
140241478380112
>>> id(12.3)
140241478380256
>>> id(12.3)
140241478380256

Isto é tão estranho.

Jason Yan
fonte
Mas isso claramente não é válido. Porque as tuplas são imutáveis. Digite x = (1, 2)e tente mudar x, não é possível. Uma maneira que eu encontrei para verificar a mutabilidade é que hashela funciona para os objetos internos, pelo menos. hash(1) hash('a') hash((1, 2)) hash(True)tudo funciona e hash([]) hash({}) hash({1, 2})tudo não funciona.
ponto
@semicolon Para classes definidas pelo usuário, hash()ele funcionará se o objeto definir um __hash__()método, mesmo que as classes definidas pelo usuário sejam geralmente mutáveis.
Aug
1
@augurar Quero dizer que sim, mas nada no Python garantirá nada, porque o Python não tem digitação estática real ou garantias formais. Mas o hashmé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.
ponto
1
@augurar e ponto-e-vírgula (ou outros, se souberem): __hash __ () solução ... o criador de uma classe personalizada precisa adicioná-lo para que ele esteja lá? Nesse caso, a regra é se existe o objeto deve ser imutável; se não existir, não podemos saber, pois o criador pode simplesmente ter parado se desligado.
TMWP 14/03