Python __str__ so với __unicode__


213

Có một quy ước python khi bạn nên thực hiện __str__()so với __unicode__(). Tôi đã thấy các lớp ghi đè __unicode__()thường xuyên hơn __str__()nhưng nó dường như không nhất quán. Có quy tắc cụ thể nào khi thực hiện cái này tốt hơn cái kia không? Có cần thiết / thực hành tốt để thực hiện cả hai?

Câu trả lời:


257

__str__()là phương thức cũ - nó trả về byte. __unicode__()là phương thức mới, được ưa thích - nó trả về các ký tự. Tên hơi khó hiểu, nhưng trong 2.x chúng tôi bị mắc kẹt với chúng vì lý do tương thích. Nói chung, bạn nên đặt tất cả định dạng chuỗi của mình vào __unicode__()và tạo một __str__()phương thức sơ khai :

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

Trong 3.0, strchứa các ký tự, vì vậy các phương thức tương tự được đặt tên __bytes__()__str__(). Những hành vi như mong đợi.


2
Bạn có nghĩa là tạo cả hai phương thức unicodestr hoặc chỉ giữ các chuỗi trong _ (u "") và tạo chuỗi (không có phương thức unicode)?
Ubuntu

12
Có bất kỳ cạm bẫy trong việc thực hiện chỉ một trong số họ? Điều gì xảy ra khi bạn chỉ thực hiện __unicode__và sau đó làm gì str(obj)?
RickyA

9
unicodenâng cao NameErrortrên Python 3, một mẫu đơn giản có hoạt động trên cả 2 và 3 không?
bradley.ay

1
@ bradley.ayers futuregói cũng cung cấp python_2_unicode_compatiblemà không cần Django làm phụ thuộc.
Monkpit

1
Nó phụ thuộc. Bởi vì python3 không sử dụng unicode mà thay vào đó là str ;) cho python 2 unicode
Eddwin Paz

23

Nếu tôi không đặc biệt quan tâm đến việc tối ưu hóa vi mô hóa cho một lớp nhất định, tôi sẽ luôn luôn __unicode__chỉ thực hiện , vì nó chung chung hơn. Khi tôi quan tâm đến các vấn đề hiệu suất phút như vậy (ngoại lệ, không phải là quy tắc), __str__chỉ có (khi tôi có thể chứng minh sẽ không bao giờ có các ký tự không phải ASCII trong đầu ra được xâu chuỗi) hoặc cả hai (khi cả hai đều có thể) Cứu giúp.

Những điều này tôi nghĩ là những nguyên tắc vững chắc, nhưng trong thực tế, nó rất phổ biến để BIẾT sẽ không có gì ngoài các ký tự ASCII mà không nỗ lực chứng minh nó (ví dụ: dạng chuỗi chỉ có chữ số, dấu câu và có thể là một tên ASCII ngắn ;-) trong đó trong trường hợp khá là điển hình để chuyển trực tiếp sang __str__cách tiếp cận " chỉ " (nhưng nếu một nhóm lập trình tôi làm việc với đề xuất một hướng dẫn địa phương để tránh điều đó, tôi sẽ được +1 về đề xuất này, vì nó dễ sai lầm trong những vấn đề này VÀ "Tối ưu hóa sớm là gốc rễ của mọi tội lỗi trong lập trình" ;-).


2
Trong python 2.6.2, gần đây tôi đã gặp sự cố vì các trường hợp của một lớp con Exception tích hợp cụ thể đã cho kết quả khác nhau với str (e) và unicode (e). str (e) đã cho đầu ra thân thiện với người dùng; unicode (e) đã cho đầu ra khác nhau, không thân thiện với người dùng. Đây có được coi là hành vi lỗi không? Lớp này là UnicodeDecodeError; Tôi đã không nêu tên trước để tránh nhầm lẫn - thực tế là ngoại lệ liên quan đến unicode không liên quan đặc biệt.
Paul Du Bois

13

Với thế giới ngày càng nhỏ hơn, nhiều khả năng là bất kỳ chuỗi nào bạn gặp sẽ chứa Unicode. Vì vậy, đối với bất kỳ ứng dụng mới, ít nhất bạn nên cung cấp __unicode__(). Cho dù bạn cũng ghi đè __str__()thì đó chỉ là vấn đề của hương vị.


8

Nếu bạn đang làm việc trong cả python2 và python3 trong Django, tôi khuyên bạn nên trang trí python_2_unicode_comp tương thích:

Django cung cấp một cách đơn giản để xác định các phương thức str () và unicode () hoạt động trên Python 2 và 3: bạn phải xác định một phương thức str () trả về văn bản và áp dụng trình trang trí python_2_unicode_compiverse ().

Như đã lưu ý trong các bình luận trước đó cho câu trả lời khác, một số phiên bản của Future.utils cũng hỗ trợ trang trí này. Trên hệ thống của tôi, tôi cần cài đặt một mô-đun tương lai mới hơn cho python2 và cài đặt tương lai cho python3. Sau đó, đây là một ví dụ chức năng:

#! /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 __name__ == "__main__":
    some_inst = SomeClass()
    print(some_inst)
    if (version_info > (3,0)):
        print("Python 3 does not support unicode()")
    else:
        print(unicode(some_inst))

Dưới đây là ví dụ đầu ra (trong đó venv2 / venv3 là các thể hiện 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__

3

Python 2: Chỉ triển khai __str __ () và trả về một unicode.

Khi __unicode__()bị bỏ qua và ai đó gọi unicode(o)hoặc u"%s"%o, Python gọi o.__str__()và chuyển đổi thành unicode bằng mã hóa hệ thống. (Xem tài liệu của__unicode__() .)

Điều ngược lại là không đúng sự thật. Nếu bạn thực hiện __unicode__()nhưng không __str__(), thì khi ai đó gọi str(o)hoặc "%s"%o, Python trả về repr(o).


Cơ sở lý luận

Tại sao nó hoạt động để trả lại unicodetừ __str__()?
Nếu __str__()trả về một unicode, Python sẽ tự động chuyển đổi nó thành strsử dụng mã hóa hệ thống.

Lợi ích là gì?
Nó giải phóng bạn khỏi lo lắng về việc mã hóa hệ thống là gì (nghĩa là locale.getpreferredencoeding(…)). Cá nhân tôi không chỉ lộn xộn, mà tôi nghĩ đó là điều mà hệ thống nên quan tâm. Nếu bạn cẩn thận, mã của bạn có thể tương thích chéo với Python 3, trong đó __str__()trả về unicode.

Không phải là lừa dối để trả về một unicode từ một hàm được gọi __str__()sao?
Một chút. Tuy nhiên, bạn có thể đã làm điều đó. Nếu bạn có from __future__ import unicode_literalsở đầu tệp của mình, rất có thể bạn sẽ trả lại một unicode mà không hề biết.

Còn Python 3 thì sao?
Python 3 không sử dụng __unicode__(). Tuy nhiên, nếu bạn triển khai __str__()để nó trả về unicode trong Python 2 hoặc Python 3, thì phần mã đó của bạn sẽ tương thích chéo.

Điều gì xảy ra nếu tôi muốn unicode(o)khác biệt đáng kể str()?
Thực hiện cả hai __str__()(có thể trở lại str) và __unicode__(). Tôi tưởng tượng điều này sẽ hiếm, nhưng bạn có thể muốn đầu ra khác biệt đáng kể (ví dụ: phiên bản ASCII của các ký tự đặc biệt, như ":)"cho u"☺").

Tôi nhận ra một số có thể tìm thấy điều này gây tranh cãi.


1

Thật đáng để chỉ ra cho những người không quen thuộc với __unicode__chức năng một số hành vi mặc định xung quanh nó trong Python 2.x, đặc biệt là khi được xác định cạnh nhau __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 ))

mang lại đầu ra giao diện điều khiển sau ...

__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

Bây giờ khi tôi bỏ qua __str__phương pháp

__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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.