{"id":1145,"date":"2015-11-04T18:18:13","date_gmt":"2015-11-04T16:18:13","guid":{"rendered":"http:\/\/saladtomatonion.com\/blog\/?p=1145"},"modified":"2015-11-04T18:18:13","modified_gmt":"2015-11-04T16:18:13","slug":"python-implementer-simplement-__str__-sur-une-classe-quand-__unicode__-est-defini","status":"publish","type":"post","link":"https:\/\/saladtomatonion.com\/blog\/2015\/11\/04\/python-implementer-simplement-__str__-sur-une-classe-quand-__unicode__-est-defini\/","title":{"rendered":"Python: impl\u00e9menter simplement __str__ sur une classe quand __unicode__ est d\u00e9fini"},"content":{"rendered":"<p>En Python 2.7 et avant, appeler la fonction <code>str(\u2026)<\/code> sur un objet appelle forc\u00e9ment son impl\u00e9mentation de <code>__str__<\/code>, m\u00eame si la m\u00e9thode <code>__unicode__<\/code> est d\u00e9finie (l&rsquo;inverse fonctionne par contre). Il en va de m\u00eame pour le <em>statement<\/em> <code>print<\/code>, qui appelle en sous-main la fonction <code>str<\/code>.<\/p>\n<p>Voici comment simplement impl\u00e9menter une m\u00e9thode <code>__str__<\/code> qui s&rsquo;appuie sur <code>__unicode__<\/code>.<!--more--><br style=\"visibility:hidden;clear:both\" \/><br \/>\nPrenons par exemple une classe repr\u00e9sentant un fichier. Typiquement, le nom de mon fichier peut tout-\u00e0-fait contenir des caract\u00e8res non ASCII: des caract\u00e8res accentu\u00e9s.<\/p>\n<pre name=\"code\" class=\"py:nogutter:nocontrols\">\r\nclass MyFile(object):\r\n    def __init__(self, path):\r\n        if isinstance(path, str):\r\n            path = transform_to_unicode(path)\r\n            # Je passe les d\u00e9tails de cette fonction magique\r\n            # qui pourra faire l'objet d'un autre article\r\n        self._fpath = path\r\n    \r\n    def path(self):\r\n        return self._fpath\r\n    \r\n    def __unicode__(self):\r\n        # Ex: [monfichier.txt]\r\n        return u'[{0}]'.format(self.path())\r\n<\/pre>\n<p>Ce qui se passe, si je fais un <code>print<\/code> sur un objet, c&rsquo;est que python appelle sa m\u00e9thode <code>__repr__<\/code>:<\/p>\n<pre name=\"code\" class=\"py:nogutter:nocontrols\">\r\n>>> print MyFile('monfichier.txt')\r\n<MyFile object at 0x0000000007075160>\r\n<\/pre>\n<p>Ce n&rsquo;est pas ce que je veux!<\/p>\n<p>Je pourrais donc b\u00eatement faire que <code>__str__<\/code> renvoie le r\u00e9sultat de <code>__unicode__<\/code>, mais je m&rsquo;exposerai lors d&rsquo;un affichage dans une console, des probl\u00e8mes d&rsquo;encodage, se manifestant par une exception de type <code>UnicodeEncodeError<\/code>. En plus, \u00e7a ne serait \u00e9videmment pas correct que cette fonction renvoie autre chose qu&rsquo;un <code>str<\/code>. Il faut donc pr\u00e9ciser <strong>explicitement<\/strong> la conversion d&rsquo;encodage. Pour cela, je peux utiliser la valeur li\u00e9e \u00e0 la console courante.<\/p>\n<pre name=\"code\" class=\"py:nogutter:nocontrols\">\r\nclass MyFile(object):\r\n    # ...\r\n    # ...\r\n    def __str__(self):\r\n        import sys\r\n        return unicode(self).encode(sys.stdout.encoding or 'ascii','replace')\r\n<\/pre>\n<p>J&rsquo;utilise la m\u00e9thode <code>encode<\/code> du type <code>unicode<\/code> pour convertir en cha\u00eene de caract\u00e8res que comprendra ma console. En encodage fallback (si <code>sys.stdout.encoding<\/code> vaut <code>None<\/code>), j&rsquo;utilise <code>ASCII<\/code>. Et si jamais certains caract\u00e8res ne peuvent pas \u00eatre convertis dans l&rsquo;encodage cible, j&rsquo;ai pass\u00e9 l&rsquo;argument <code>'replace'<\/code> pour, au pire, remplacer les caract\u00e8res invalides par un <code>'?'<\/code>.<\/p>\n<blockquote><p>Au fait, si vous vous demandez pourquoi \u00ab\u00a0<code style=\"color:green;\">sys.stdout.encoding or 'ascii'<\/code>\u00ab\u00a0, <a href=\"http:\/\/saladtomatonion.com\/blog\/2014\/12\/18\/une-utilisation-etonnante-du-mot-cle-or-en-python\/\" title=\"Une utilisation \u00e9tonnante du mot-cl\u00e9 \u00ab\u00a0or\u00a0\u00bb en python\">allez voir cet article<\/a>.<\/p><\/blockquote>\n<p>\u00c0 partir de Python 3, le probl\u00e8me devient plus simple, car toutes les cha\u00eenes de caract\u00e8res sont des <code>unicode<\/code>, la fonction <code>encode<\/code> servant alors \u00e0 obtenir <strong>la cha\u00eene d&rsquo;octets<\/strong> dans le bon encodage.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>En Python 2.7 et avant, appeler la fonction str(\u2026) sur un objet appelle forc\u00e9ment son impl\u00e9mentation de __str__, m\u00eame si la m\u00e9thode __unicode__ est d\u00e9finie (l&rsquo;inverse fonctionne par contre). Il en va de m\u00eame&#46;&#46;&#46;<\/p>\n","protected":false},"author":2,"featured_media":708,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[4],"tags":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/saladtomatonion.com\/blog\/wp-content\/uploads\/2011\/04\/python-logo-glassy-small.png","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/saladtomatonion.com\/blog\/wp-json\/wp\/v2\/posts\/1145"}],"collection":[{"href":"https:\/\/saladtomatonion.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/saladtomatonion.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/saladtomatonion.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/saladtomatonion.com\/blog\/wp-json\/wp\/v2\/comments?post=1145"}],"version-history":[{"count":20,"href":"https:\/\/saladtomatonion.com\/blog\/wp-json\/wp\/v2\/posts\/1145\/revisions"}],"predecessor-version":[{"id":1165,"href":"https:\/\/saladtomatonion.com\/blog\/wp-json\/wp\/v2\/posts\/1145\/revisions\/1165"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/saladtomatonion.com\/blog\/wp-json\/wp\/v2\/media\/708"}],"wp:attachment":[{"href":"https:\/\/saladtomatonion.com\/blog\/wp-json\/wp\/v2\/media?parent=1145"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/saladtomatonion.com\/blog\/wp-json\/wp\/v2\/categories?post=1145"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/saladtomatonion.com\/blog\/wp-json\/wp\/v2\/tags?post=1145"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}