Qual é a diferença entre __str__
e __repr__
no Python?
fonte
Alex resumiu bem, mas, surpreendentemente, foi muito sucinto.
Primeiro, deixe-me reiterar os pontos principais no post de Alex :
__repr__
objetivo é ser inequívoco__str__
objetivo é ser legível__str__
usa objetos contidos '__repr__
A implementação padrão é inútil
Isso é principalmente uma surpresa, porque os padrões do Python tendem a ser bastante úteis. No entanto, nesse caso, ter um padrão para o __repr__
qual agiria como:
return "%s(%r)" % (self.__class__, self.__dict__)
teria sido muito perigoso (por exemplo, muito fácil entrar em recursão infinita se objetos se referirem uns aos outros). Então, o Python aguenta. Observe que há um padrão que é verdadeiro: se __repr__
for definido e __str__
não, o objeto se comportará como se __str__=__repr__
.
Isso significa, em termos simples: quase todos os objetos que você implementa devem ter um funcional __repr__
que seja útil para entender o objeto. Implementando__str__
é opcional: faça isso se você precisar de uma funcionalidade de "impressão bonita" (por exemplo, usada por um gerador de relatórios).
O objetivo __repr__
é ser inequívoco
Deixe-me falar e dizer: não acredito em depuradores. Realmente não sei como usar nenhum depurador e nunca o usei seriamente. Além disso, acredito que a grande falha nos depuradores é sua natureza básica - a maioria das falhas depuradoras aconteceu há muito tempo, em uma galáxia muito distante. Isso significa que eu acredito, com fervor religioso, na exploração madeireira. O registro é a força vital de qualquer sistema de servidor decente de ignorar. O Python facilita o log: com talvez alguns wrappers específicos do projeto, tudo o que você precisa é de um
log(INFO, "I am in the weird function and a is", a, "and b is", b, "but I got a null C — using default", default_c)
Mas você precisa executar o último passo - verifique se todos os objetos implementados têm uma repr útil, para que um código como esse possa funcionar. É por isso que a coisa “eval” surge: se você tem informações suficientes eval(repr(c))==c
, significa que você sabe tudo o que há para saber c
. Se isso é fácil o suficiente, pelo menos de uma maneira difusa, faça-o. Caso contrário, verifique se você tem informações suficientes c
. Eu costumo usar um eval-like formato: "MyClass(this=%r,that=%r)" % (self.this,self.that)
. Isso não significa que você pode realmente criar MyClass, ou que esses são os argumentos corretos do construtor - mas é uma forma útil de expressar “isso é tudo o que você precisa saber sobre essa instância”.
Nota: Eu usei %r
acima, não %s
. Você sempre deseja usar repr()
[ou %r
formatar caracteres, de forma equivalente] dentro da __repr__
implementação, ou está derrotando o objetivo de repr. Você quer ser capaz de diferenciar MyClass(3)
e MyClass("3")
.
O objetivo __str__
é ser legível
Especificamente, não se destina a ser inequívoco - observe isso str(3)==str("3")
. Da mesma forma, se você implementar uma abstração de IP, ter o str dela parecido com 192.168.1.1 é bom. Ao implementar uma abstração de data / hora, o str pode ser "2010/4/12 15:35:22" etc. O objetivo é representá-lo de uma maneira que um usuário, não um programador, deseje lê-lo. Pique dígitos inúteis, finja ser de outra classe - desde que apóie a legibilidade, é uma melhoria.
O contêiner __str__
usa objetos contidos '__repr__
Isso parece surpreendente, não é? É um pouco, mas quão legível seria se usasse o deles __str__
?
[moshe is, 3, hello
world, this is a list, oh I don't know, containing just 4 elements]
Não muito. Especificamente, as seqüências de caracteres em um contêiner acham muito fácil perturbar sua representação. Diante da ambiguidade, lembre-se, Python resiste à tentação de adivinhar. Se você deseja o comportamento acima ao imprimir uma lista, basta
print "[" + ", ".join(l) + "]"
(você provavelmente também pode descobrir o que fazer com os dicionários.
Sumário
Implemente __repr__
para qualquer classe que você implemente. Isso deve ser uma segunda natureza. Implemente __str__
se você acha que seria útil ter uma versão de string que erre no lado da legibilidade.
__repr__
era o que eu precisava para depurar. Obrigado pela ajuda.Minha regra de ouro:
__repr__
é para desenvolvedores,__str__
é para clientes.fonte
__str__
para que os desenvolvedores normais tenham um objeto legível. Por outro lado,__repr__
é para os próprios desenvolvedores do SDK.A menos que você aja especificamente para garantir o contrário, a maioria das classes não terá resultados úteis para:
Como você vê - nenhuma diferença e nenhuma informação além da classe e do objeto
id
. Se você substituir apenas um dos dois ...:como você vê, se você substituir
__repr__
, isso também é usado__str__
, mas não vice-versa.Outros boatos cruciais a saber:
__str__
em um contêiner embutido, usa__repr__
NÃO__str__
, para os itens que ele contém. E, apesar das palavras sobre o assunto encontradas nos documentos típicos, quase ninguém se incomoda em tornar os__repr__
objetos uma string queeval
pode ser usada para criar um objeto igual (é muito difícil e NÃO saber como o módulo relevante foi realmente importado o torna realmente impossível).Então, meu conselho: concentre-se em tornar
__str__
razoavelmente legível para o ser humano e o__repr__
mais inequívoco possível, mesmo que isso interfira no objetivo impreciso e impreciso de tornar__repr__
o valor retornado aceitável como entrada__eval__
!fonte
eval(repr(foo))
se o objeto é igual afoo
. Você está certo de que não funcionará fora dos meus casos de teste, pois não sei como o módulo é importado, mas isso pelo menos garante que funcione em algum contexto previsível. Eu acho que é uma boa maneira de avaliar se o resultado de__repr__
é suficientemente explícito. Fazer isso em um teste de unidade também ajuda a garantir que as__repr__
alterações sejam seguidas na classe.eval(repr(spam)) == spam
(pelo menos no contexto certo) oueval(repr(spam))
gera umSyntaxError
. Dessa forma, você evita confusão. (E isso é quase verdade para os builtins e a maioria dos stdlib, exceto, por exemplo, listas recursivas, ondea=[]; a.append(a); print(eval(repr(a)))
você fornece[[Ellipses]]
...) É claro que eu não faço isso para realmente usá-loeval(repr(spam))
, exceto como verificação de sanidade nos testes de unidade ... mas eu que , por vezes, copiar e colarrepr(spam)
em uma sessão interativa.__str__
para cada elemento em vez de__repr__
? Parece totalmente errado para mim, pois implementei um legível__str__
no meu objeto e, quando faz parte de uma lista, vejo o mais feio__repr__
.eval(repr(x))
falha mesmo para os tipos internos:class A(str, Enum): X = 'x'
aumentará o SyntaxErroreval(repr(A.X))
. É triste, mas compreensível. BTW,eval(str(A.X))
na verdade funciona, mas é claro apenas seclass A
estiver no escopo - portanto, provavelmente não é muito útil.str
elemento de uso de contêinerrepr
porque[1, 2, 3]
! =["1", "2, 3"]
.__repr__
: a representação do objeto python geralmente eval o converterá novamente nesse objeto__str__
: é o que você acha que é esse objeto em forma de textopor exemplo
fonte
Aqui está um bom exemplo:
Leia esta documentação para repr:
Aqui está a documentação para str:
fonte
__str__
(lidos como "dunder (sublinhado duplo)") e__repr__
(lidos como "dunder-repper" (para "representação")) são métodos especiais que retornam seqüências de caracteres com base no estado do objeto.__repr__
fornece comportamento de backup se__str__
estiver ausente.Portanto, deve-se primeiro escrever um
__repr__
que permita restabelecer um objeto equivalente a partir da string que ele retorna, por exemplo, usandoeval
ou digitando caractere por caractere em um shell Python.A qualquer momento, pode-se escrever um
__str__
para uma representação de string legível pelo usuário da instância, quando julgar necessário.__str__
Se você imprimir um objeto ou passá-lo para
format
,,str.format
oustr
, se um__str__
método for definido, esse método será chamado, caso contrário,__repr__
será usado.__repr__
O
__repr__
método é chamado pela função embutidarepr
e é o que é ecoado no shell python quando avalia uma expressão que retorna um objeto.Como ele fornece um backup
__str__
, se você puder escrever apenas um, comece com__repr__
Aqui está a ajuda integrada sobre
repr
:Ou seja, para a maioria dos objetos, se você digitar o que é impresso
repr
, poderá criar um objeto equivalente. Mas essa não é a implementação padrão.Implementação padrão de
__repr__
O objeto padrão
__repr__
é ( fonte C Python ) algo como:Isso significa que, por padrão, você imprimirá o módulo do qual o objeto é, o nome da classe e a representação hexadecimal de sua localização na memória - por exemplo:
Essas informações não são muito úteis, mas não há como derivar como se pode criar com precisão uma representação canônica de qualquer instância, e é melhor que nada, pelo menos nos dizendo como podemos identificá-las exclusivamente na memória.
Como pode
__repr__
ser útil?Vamos ver como isso pode ser útil, usando o shell e os
datetime
objetos Python . Primeiro, precisamos importar odatetime
módulo:Se chamarmos
datetime.now
o shell, veremos tudo o que precisamos para recriar um objeto datetime equivalente. Isso é criado pela data__repr__
e hora :Se imprimirmos um objeto datetime, veremos um bom formato legível por humanos (de fato, ISO). Isso é implementado pelo datetime
__str__
:É simples recriar o objeto que perdemos porque não o atribuímos a uma variável, copiando e colando da
__repr__
saída, imprimindo-a e obtendo-a na mesma saída legível por humanos que o outro objeto:Como eu os implemento?
Enquanto você está desenvolvendo, você poderá reproduzir objetos no mesmo estado, se possível. Por exemplo, é assim que o objeto datetime define
__repr__
( fonte Python ). É bastante complexo, devido a todos os atributos necessários para reproduzir esse objeto:Se você deseja que seu objeto tenha uma representação legível por humanos, você pode implementar a
__str__
seguir. Veja como o objeto datetime ( fonte Python ) implementa__str__
, o que é fácil porque ele já tem uma função para exibi-lo no formato ISO:Set
__repr__ = __str__
?Esta é uma crítica de outra resposta aqui que sugere configuração
__repr__ = __str__
.A configuração
__repr__ = __str__
é boba -__repr__
é um substituto para__str__
e um__repr__
, escrito para uso dos desenvolvedores na depuração, deve ser escrito antes de você escrever um__str__
.Você precisa de um
__str__
somente quando precisar de uma representação textual do objeto.Conclusão
Defina os
__repr__
objetos que você escreve para que você e outros desenvolvedores tenham um exemplo reproduzível ao usá-lo à medida que desenvolve. Defina__str__
quando você precisa de uma representação de sequência legível por humanos.fonte
type(obj).__qualname__
?Na página 358 do livro Python scripting for science computational, de Hans Petter Langtangen, afirma claramente que
__repr__
objetivo é uma representação completa da string do objeto;__str__
é retornar uma boa string para impressão.Então, eu prefiro entendê-los como
do ponto de vista do usuário, embora esse seja um mal-entendido que eu fiz ao aprender python.
Um pequeno mas bom exemplo também é dado na mesma página da seguinte maneira:
Exemplo
fonte
repr
reprodução. É melhor pensar nisso como representar.Além de todas as respostas dadas, gostaria de acrescentar alguns pontos: -
1)
__repr__()
é chamado quando você simplesmente escreve o nome do objeto no console python interativo e pressiona enter.2)
__str__()
é invocado quando você usa o objeto com a instrução print.3) Caso
__str__
esteja faltando, imprima e qualquer função usandostr()
invoca__repr__()
de objeto.4)
__str__()
de contêineres, quando invocados, executarão o__repr__()
método de seus elementos contidos.5)
str()
chamado dentro__str__()
poderia recorrer sem um caso base e erro na profundidade máxima da recursão.6)
__repr__()
pode chamar orepr()
que tentará evitar a recursão infinita automaticamente, substituindo um objeto já representado por...
.fonte
Simplificando:
__str__
é usado para mostrar uma representação de string do seu objeto para ser lida facilmente por outras pessoas.__repr__
é utilizado para mostrar uma representação em cadeia do objecto.Digamos que eu queira criar uma
Fraction
classe em que a representação de string de uma fração seja '(1/2)' e o objeto (classe Fraction) seja representado como 'Fraction (1,2)'Assim, podemos criar uma classe Fraction simples:
fonte
Com toda a honestidade,
eval(repr(obj))
nunca é usado. Se você se encontra usando, deve parar, porqueeval
é perigoso, e as cordas são uma maneira muito ineficiente de serializar seus objetos (usepickle
vez disso).Portanto, eu recomendaria a configuração
__repr__ = __str__
. A razão é questr(list)
chamarepr
os elementos (considero que essa é uma das maiores falhas de design do Python que não foi abordada pelo Python 3). Um realrepr
provavelmente não será muito útil como a saída deprint [your, objects]
.Para qualificar isso, na minha experiência, o caso de uso mais útil da
repr
função é colocar uma string dentro de outra (usando a formatação da string). Dessa forma, você não precisa se preocupar com escapar aspas ou algo assim. Mas observe que não há nadaeval
acontecendo aqui.fonte
eval(repr(obj))
é um teste de sanidade e uma regra de ouro - se isso recriar o objeto original corretamente, você terá uma__repr__
implementação decente . Não se pretende que você serialize objetos dessa maneira.eval
não é inerentemente perigoso. Não é mais perigoso do queunlink
,open
ou a gravar arquivos. Devemos parar de gravar em arquivos, porque talvez um ataque malicioso possa usar um caminho arbitrário para inserir conteúdo? Tudo é perigoso se usado de maneira burra por pessoas burras. A idiotice é perigosa. Os efeitos de Dunning-Kruger são perigosos.eval
é apenas uma função.De um Wiki de referência do Python (não oficial) (cópia de arquivo) por effbot:
__str__
" calcula a representação de string" informal "de um objeto. Isso difere de__repr__
que não precisa ser uma expressão válida do Python: uma representação mais conveniente ou concisa pode ser usada. "fonte
__repr__
não é de forma alguma necessário para retornar uma expressão Python vaild.str
- Cria um novo objeto de string do objeto especificado.repr
- Retorna a representação de string canônica do objeto.As diferenças:
str ():
repr ():
fonte
Um aspecto que está faltando em outras respostas. É verdade que, em geral, o padrão é:
__str__
: legível por humanos__repr__
: inequívoco, possivelmente legível por máquina viaeval
Infelizmente, essa diferenciação é falha, porque o Python REPL e também o IPython usam
__repr__
para imprimir objetos em um console REPL (consulte as perguntas relacionadas para Python e IPython ). Assim, projetos direcionados ao trabalho de console interativo (por exemplo, Numpy ou Pandas) começaram a ignorar as regras acima e, em vez disso, fornecem uma__repr__
implementação legível por humanos .fonte
Do livro Fluent Python :
fonte
Excelentes respostas já cobrem a diferença entre
__str__
e__repr__
, o que para mim se resume ao fato de o primeiro ser legível até mesmo por um usuário final, e o último ser o mais útil possível para os desenvolvedores. Dado isso, acho que a implementação padrão__repr__
geralmente falha em atingir esse objetivo porque omite informações úteis para os desenvolvedores.Por esse motivo, se eu tiver um simples
__str__
, geralmente apenas tento obter o melhor dos dois mundos com algo como:fonte
O Python favorece a ambiguidade sobre a legibilidade , a
__str__
chamada de atuple
chama de objetos contidos__repr__
, a representação "formal" de um objeto. Embora a representação formal seja mais difícil de ler do que a informal, ela é inequívoca e mais robusta contra bugs.fonte
__repr__
quando (__str__
) não está definido! Então, você está errado.Em poucas palavras:
fonte
Quando
print()
é chamado, o resultado dodecimal.Decimal(23) / decimal.Decimal("1.05")
número bruto é impresso; essa saída está na forma de string que pode ser obtida com__str__()
. Se simplesmente inserirmos a expressão, obtemos umadecimal.Decimal
saída - essa saída está na forma representacional que pode ser obtida com__repr__()
. Todos os objetos Python têm duas formas de saída. O formato da string foi projetado para ser legível por humanos. A forma representacional é projetada para produzir resultados que, se alimentados a um intérprete Python, (quando possível) reproduziriam o objeto representado.fonte
__str__
pode ser chamado em um objeto chamandostr(obj)
e deve retornar uma sequência legível por humanos.__repr__
pode ser chamado em um objeto chamandorepr(obj)
e deve retornar um objeto interno (campos / atributos do objeto)Este exemplo pode ajudar:
fonte
Compreender
__str__
e__repr__
distinga-os intuitivamente e permanentemente.__str__
retorna o corpo disfarçado de um determinado objeto para legível dos olhos__repr__
possam ser retornar o corpo real de carne de um determinado objeto (retornar em si) para que a ambiguidade seja identificada.Veja em um exemplo
Quanto a
__repr__
Podemos realizar operações aritméticas de forma
__repr__
conveniente.se aplicar a operação em
__str__
Retorna nada além de erro.
Outro exemplo.
Espero que isso ajude a construir bases concretas para explorar mais respostas.
fonte
__str__
deve retornar o objeto string enquanto__repr__
pode retornar qualquer expressão python.__str__
implementação estiver ausente, a__repr__
função será usada como fallback. Não há fallback se a__repr__
implementação da função estiver ausente.__repr__
função estiver retornando a representação String do objeto, podemos pular a implementação da__str__
função.Fonte: https://www.journaldev.com/22460/python-str-repr-functions
fonte
__repr__
é usado em qualquer lugar, exceto porprint
estr
métodos (quando a__str__
é definido!)fonte