Python __str__ กับ __unicode__


213

จะมีการประชุมหลามสำหรับเมื่อคุณควรใช้เมื่อเทียบกับ__str__() __unicode__()ฉันเคยเห็นคลาสที่เขียนทับ__unicode__()บ่อยกว่า__str__()แต่ดูเหมือนจะไม่สอดคล้องกัน มีกฎเฉพาะเจาะจงหรือไม่เมื่อนำไปใช้กับกฎอื่นจะดีกว่า จำเป็นต้องมี / วิธีปฏิบัติที่ดีในการใช้ทั้งสองอย่างหรือไม่

คำตอบ:


257

__str__()เป็นวิธีการเก่า - มันส่งกลับไบต์ __unicode__()เป็นวิธีการใหม่ที่ต้องการ - ส่งคืนอักขระ ชื่อค่อนข้างสับสน แต่ใน 2.x เราติดกับพวกเขาด้วยเหตุผลที่เข้ากันได้ โดยทั่วไปคุณควรใส่การจัดรูปแบบสตริงทั้งหมดของคุณ__unicode__()และสร้าง__str__()วิธีการสตับ:

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

ใน 3.0 strประกอบด้วยอักขระดังนั้นวิธีการเดียวกันมีการตั้งชื่อและ__bytes__() __str__()พฤติกรรมเหล่านี้เป็นไปตามที่คาดไว้


2
คุณหมายถึงการสร้างทั้งวิธียูนิโค้ดและstrหรือเพียงแค่เก็บสตริงใน _ (u "") และสร้างสตริง (โดยไม่มีวิธี unicode)?
muntu

12
มีข้อผิดพลาดใด ๆ หรือไม่ในการใช้งานเพียงอย่างเดียว จะเกิดอะไรขึ้นเมื่อคุณนำไปใช้เท่านั้น__unicode__และจะต้องทำstr(obj)อย่างไร
RickyA

9
unicodeยกระดับNameErrorบน Python 3 เป็นรูปแบบง่าย ๆ ที่ใช้ได้ทั้ง 2 และ 3 หรือไม่?
bradley.ayers

1
@ bradley.ayers futureแพ็คเกจยังมอบให้python_2_unicode_compatibleโดยไม่ต้องพึ่ง Django
Monkpit

1
มันขึ้นอยู่กับ. เพราะ python3 ไม่ได้ใช้unicodeแต่แทนstr ;) สำหรับ python 2 unicode
Eddwin Paz

23

ถ้าฉันไม่สนใจการทำ stringing การปรับขนาดเล็กโดยเฉพาะอย่างยิ่งสำหรับคลาสที่กำหนดฉันมักจะนำไปใช้__unicode__เท่านั้นเพราะมันเป็นเรื่องทั่วไป เมื่อฉันสนใจเกี่ยวกับปัญหาประสิทธิภาพการทำงานในนาทีดังกล่าว (ซึ่งเป็นข้อยกเว้นไม่ใช่กฎ) มี__str__เพียง (เมื่อฉันสามารถพิสูจน์ได้ว่าจะไม่มีตัวอักษรที่ไม่ใช่ ASCII ในเอาต์พุตแบบสตริง) หรือทั้งสองอย่าง (เมื่อเป็นไปได้ทั้งสองอย่าง) อาจ ช่วยด้วย.

สิ่งเหล่านี้ฉันคิดว่าเป็นหลักการที่มั่นคง แต่ในทางปฏิบัติมันเป็นเรื่องธรรมดามากที่รู้ว่าจะไม่มีอะไรนอกจากตัวอักษร ASCII โดยไม่ต้องพยายามพิสูจน์ (เช่นรูปแบบที่มีสายอักขระมีตัวเลขหลักเครื่องหมายวรรคตอนและอาจเป็นชื่อ ASCII สั้น ๆ ;-) กรณีที่มันค่อนข้างทั่วไปที่จะไปโดยตรงไปยัง "เพียงแค่__str__วิธีการ" ( แต่ถ้าทีมงานเขียนโปรแกรมผมทำงานกับเสนอแนวทางในท้องถิ่นเพื่อหลีกเลี่ยงการที่ฉันจะ +1 เกี่ยวกับข้อเสนอตามที่มันเป็นเรื่องง่ายที่จะทำผิดพลาดในเรื่องเหล่านี้และ "การปรับให้เหมาะสมก่อนวัยอันควรเป็นรากของความชั่วร้ายทั้งหมดในการเขียนโปรแกรม" ;-)


2
ใน python 2.6.2 เมื่อเร็ว ๆ นี้ฉันได้รับการเพิ่มขึ้นเนื่องจากอินสแตนซ์ของคลาสย่อยยกเว้นในตัวเฉพาะให้ผลลัพธ์ที่แตกต่างกับ str (e) และ unicode (e) STR (e) ให้ผลลัพธ์ที่เป็นมิตรกับผู้ใช้ unicode (e) ให้เอาต์พุตที่ไม่เป็นมิตรกับผู้ใช้ สิ่งนี้ถือเป็นพฤติกรรมบั๊กกี้หรือไม่? คลาสคือ UnicodeDecodeError ฉันไม่ได้ตั้งชื่อล่วงหน้าเพื่อหลีกเลี่ยงความสับสนข้อเท็จจริงที่ว่าข้อยกเว้นนั้นเกี่ยวข้องกับ Unicode นั้นไม่เกี่ยวข้องกันเป็นพิเศษ
Paul Du Bois

13

เมื่อโลกเล็กลงโอกาสที่สตริงใด ๆ ที่คุณพบจะมี Unicode ในที่สุด ดังนั้นสำหรับปพลิเคชันใหม่ ๆ __unicode__()อย่างน้อยคุณควรจะให้ ไม่ว่าคุณจะลบล้าง__str__()มันก็เป็นเพียงเรื่องของรสนิยม


8

หากคุณกำลังทำงานทั้ง python2 และ python3 ใน Django ฉันขอแนะนำให้ python_2_unicode_compatible decorator:

Django มีวิธีง่าย ๆ ในการกำหนดวิธีstr () และ unicode () ที่ทำงานบน Python 2 และ 3: คุณต้องกำหนดเมธอดstr () ที่ส่งคืนข้อความและใช้ pator_3_unicode_compatible ()

ตามที่ระบุไว้ในความคิดเห็นก่อนหน้านี้สำหรับคำตอบอื่นรุ่นอนาคตบางรุ่นยังสนับสนุนตัวตกแต่งนี้ด้วย ในระบบของฉันฉันต้องติดตั้งโมดูลใหม่ในอนาคตสำหรับ python2 และติดตั้งในอนาคตสำหรับ python3 หลังจากนั้นต่อไปนี้เป็นตัวอย่างการทำงาน:

#! /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))

นี่คือตัวอย่างเอาต์พุต (โดยที่ venv2 / venv3 เป็นอินสแตนซ์ 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: ใช้งาน __str __ () เท่านั้นและส่งคืน Unicode

เมื่อ__unicode__()ละไว้และมีคนโทรออกunicode(o)หรือโทรหาu"%s"%oงูใหญ่o.__str__()และแปลงเป็นยูนิโค้ดโดยใช้การเข้ารหัสระบบ (ดูเอกสารประกอบของ__unicode__() )

ตรงกันข้ามไม่เป็นความจริง หากคุณใช้__unicode__()แต่ไม่ได้__str__()แล้วเมื่อสายใครบางคนstr(o)หรือผลตอบแทนหลาม"%s"%orepr(o)


หลักการและเหตุผล

ทำไมมันจะทำงานกลับunicodeจาก__str__()?
ถ้า__str__()ส่งคืนยูนิโค้ด Python จะแปลงเป็นการstrเข้ารหัสของระบบโดยอัตโนมัติ

ประโยชน์คืออะไร
①ทำให้คุณไม่ต้องกังวลเกี่ยวกับการเข้ารหัสของระบบ (เช่นlocale.getpreferredencoeding(…)) ไม่เพียง แต่จะยุ่งเท่านั้นส่วนตัว แต่ฉันคิดว่ามันเป็นสิ่งที่ระบบควรดูแลอยู่ดี ②หากคุณระมัดระวังรหัสของคุณอาจออกมาไขว้กันได้กับ Python 3 ซึ่ง__str__()ส่งคืน Unicode

ไม่เป็นการหลอกลวงที่จะส่งคืน Unicode จากฟังก์ชันที่เรียกว่า__str__()ใช่หรือไม่
เล็กน้อย. อย่างไรก็ตามคุณอาจทำไปแล้ว หากคุณfrom __future__ import unicode_literalsอยู่ที่ด้านบนสุดของไฟล์คุณมีโอกาสดีที่คุณจะส่งคืนยูนิโค้ดโดยที่ไม่รู้ตัว

Python 3 เกี่ยวกับอะไร?
งูหลาม 3 __unicode__()ไม่ได้ใช้ อย่างไรก็ตามหากคุณใช้งาน__str__()เพื่อให้ส่งคืน unicode ภายใต้ Python 2 หรือ Python 3 ส่วนหนึ่งของรหัสนั้นจะสามารถใช้งานร่วมกันได้

ถ้าฉันต้องการunicode(o)ที่จะแตกต่างอย่างมีนัยสำคัญจากที่str()ใด
การดำเนินการทั้งสอง__str__()(อาจจะกลับมาstr) __unicode__()และ ฉันคิดว่านี่จะหายาก แต่คุณอาจต้องการผลลัพธ์ที่แตกต่างอย่างมาก (เช่นอักขระพิเศษรุ่น ASCII เช่น":)"สำหรับu"☺")

ฉันรู้ว่าบางคนอาจพบข้อโต้แย้งนี้


1

มันคุ้มค่าที่จะชี้ให้ผู้ที่ไม่คุ้นเคยกับ__unicode__ฟังก์ชั่นบางอย่างของพฤติกรรมเริ่มต้นที่อยู่รอบตัวมันใน Python 2.x โดยเฉพาะอย่างยิ่งเมื่อมีการกำหนดแบบเคียงข้าง__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 ))

สร้างเอาต์พุตคอนโซลต่อไปนี้ ...

__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

ตอนนี้เมื่อฉัน uncomment out __str__วิธีการ

__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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.