web-dev-qa-db-fra.com

Python __str__ versus __unicode__

Existe-t-il une convention python pour le moment où vous devez implémenter __str__() par rapport à __unicode__(). J'ai déjà vu des classes remplacer __unicode__() plus fréquemment) que __str__() mais cela ne semble pas être cohérent Existe-t-il des règles spécifiques dans lesquelles il est préférable d'appliquer l'une ou l'autre? Est-il nécessaire/une bonne pratique de mettre en œuvre les deux?

209
Cory

__str__() est l'ancienne méthode - elle renvoie des octets. __unicode__() est la nouvelle méthode préférée - elle renvoie des caractères. Les noms sont un peu déroutants, mais en 2.x nous sommes coincés avec eux pour des raisons de compatibilité. Généralement, vous devriez mettre toute la chaîne en forme dans __unicode__() et créer une méthode stub __str__():

def __str__(self):
    return unicode(self).encode('utf-8')

Dans la version 3.0, str contient des caractères. Les mêmes méthodes sont donc nommées __bytes__() et __str__(). Ceux-ci se comportent comme prévu.

252
John Millikin

Si je ne tenais pas particulièrement à la micro-optimisation de la stringification pour une classe donnée, je mettrais toujours en œuvre __unicode__ seulement, comme c'est plus général. Quand je me soucie de ces problèmes de performance de minute (ce qui est l'exception, pas la règle), avoir __str__ uniquement (lorsque je peux prouver qu'il n'y aura jamais de caractères non-ASCII dans la sortie sous forme de chaîne), ou les deux (lorsque les deux sont possibles), pourrait être utile.

Je pense que ce sont des principes solides, mais dans la pratique, il est très courant de SAVOIR qu’il n’y aura que ASCII caractères sans s’efforcer de le prouver (par exemple, le formulaire à chaîne comporte uniquement des chiffres, de la ponctuation et peut-être un court ASCII nom ;-); dans ce cas, il est assez courant de passer directement au "just __str__ "approche (mais si une équipe de programmation avec laquelle je travaillais a proposé une directive locale pour éviter cela, je serais +1 sur la proposition, car il est facile de se tromper dans ces questions ET" l’optimisation prématurée est la racine de tout mal en programmation";-).

23
Alex Martelli

Avec la réduction de la taille du monde, il est probable que toute chaîne que vous rencontrerez contiendra éventuellement Unicode. Donc, pour toute nouvelle application, vous devez au moins fournir __unicode__(). Que vous remplaciez également __str__() n'est alors qu'une question de goût.

13
Aaron Digulla

Si vous travaillez à la fois dans python2 et python3 dans Django, je recommande le décorateur python_2_unicode_compatible:

Django offre un moyen simple de définir les méthodes str () et nicode () qui fonctionnent sur Python 2 et 3: vous devez définir un str () renvoie le texte et applique le décorateur python_2_unicode_compatible ().

Comme indiqué dans les commentaires précédents concernant une autre réponse, certaines versions de future.utils prennent également en charge ce décorateur. Sur mon système, je devais installer un module futur plus récent pour python2 et installer future pour python3. Après cela, voici un exemple fonctionnel:

#! /usr/bin/env python

from future.utils import python_2_unicode_compatible
from sys import version_info

@python_2_unicode_compatible
class SomeClass():
    def __str__(self):
        return "Called __str__"


if __== "__main__":
    some_inst = SomeClass()
    print(some_inst)
    if (version_info > (3,0)):
        print("Python 3 does not support unicode()")
    else:
        print(unicode(some_inst))

Voici un exemple de sortie (où venv2/venv3 sont des instances de virtualenv):

~/tmp$ ./venv3/bin/python3 demo_python_2_unicode_compatible.py 
Called __str__
Python 3 does not support unicode()

~/tmp$ ./venv2/bin/python2 demo_python_2_unicode_compatible.py 
Called __str__
Called __str__
6
sage

Python 2: Implémente __str __ () uniquement et renvoie un unicode.

Lorsque __unicode__() est omis et que quelqu'un appelle unicode(o) ou u"%s"%o, Python appelle o.__str__() et convertit en unicode en utilisant le codage du système. (Voir documentation de __unicode__() .)

Le contraire n'est pas vrai. Si vous implémentez __unicode__() mais pas __str__(), lorsque quelqu'un appelle str(o) ou "%s"%o, Python renvoie repr(o).


Raisonnement

Pourquoi fonctionnerait-il pour renvoyer un unicode de __str__() ?
Si __str__() renvoie un unicode, Python le convertit automatiquement en str à l'aide du codage du système.

Quel est l'avantage?
① Cela vous évite de vous soucier de l’encodage du système (c'est-à-dire, locale.getpreferredencoeding(…)). Personnellement, non seulement c'est compliqué, mais je pense que de toute façon, le système devrait en prendre soin. Si vous faites attention, votre code peut être compatible avec Python 3, dans lequel __str__() renvoie unicode.

N’est-il pas trompeur de renvoyer un unicode à partir d’une fonction appelée __str__() ?
Un peu. Cependant, vous le faites peut-être déjà. Si vous avez from __future__ import unicode_literals En haut de votre fichier, il y a de fortes chances que vous retourniez un unicode sans même le savoir.

Qu'en est-il Python 3?
Python 3 n'utilise pas __unicode__(). Cependant, si vous implémentez __str__() pour qu’il retourne unicode sous Python 2 ou Python 3, alors cette partie de votre code être compatible entre eux.

Et si je veux que unicode(o) soit substantiellement différent de str() ?
Implémente __str__() (retournant éventuellement str) et __unicode__(). J'imagine que cela serait rare, mais vous voudrez peut-être une sortie sensiblement différente (par exemple, ASCII de caractères spéciaux, comme ":)" Pour u"☺").

Je me rends compte que certains peuvent trouver cela controversé.

1
Alex Quinn

Cela vaut la peine de signaler à ceux qui ne connaissent pas le __unicode__ fonctionne avec certains des comportements par défaut qui l'entourent dans Python 2.x, en particulier lorsqu'il est défini côte à côte avec __str__.

class A :
    def __init__(self) :
        self.x = 123
        self.y = 23.3

    #def __str__(self) :
    #    return "STR      {}      {}".format( self.x , self.y)
    def __unicode__(self) :
        return u"UNICODE  {}      {}".format( self.x , self.y)

a1 = A()
a2 = A()

print( "__repr__ checks")
print( a1 )
print( a2 )

print( "\n__str__ vs __unicode__ checks")
print( str( a1 ))
print( unicode(a1))
print( "{}".format( a1 ))
print( u"{}".format( a1 ))

donne la sortie de console suivante ...

__repr__ checks
<__main__.A instance at 0x103f063f8>
<__main__.A instance at 0x103f06440>

__str__ vs __unicode__ checks
<__main__.A instance at 0x103f063f8>
UNICODE 123      23.3
<__main__.A instance at 0x103f063f8>
UNICODE 123      23.3

Maintenant, quand je dégage le __str__ méthode

__repr__ checks
STR      123      23.3
STR      123      23.3

__str__ vs __unicode__ checks
STR      123      23.3
UNICODE  123      23.3
STR      123      23.3
UNICODE  123      23.3
0
jxramos