ความแตกต่างระหว่าง __str__ กับ __repr__?


คำตอบ:


2723

อเล็กซ์สรุปได้ดี แต่น่าแปลกใจที่รวบรัดเกินไป

ก่อนอื่นให้ฉันย้ำประเด็นหลักในการโพสต์ของ Alex :

  • การใช้งานเริ่มต้นนั้นไร้ประโยชน์ (มันยากที่จะคิดว่าสิ่งใดที่ไม่ควรทำ แต่ใช่)
  • __repr__ เป้าหมายคือการไม่คลุมเครือ
  • __str__ เป้าหมายคือสามารถอ่านได้
  • การ__str__ใช้ภาชนะบรรจุวัตถุที่มีอยู่__repr__

การใช้งานเริ่มต้นไม่มีประโยชน์

นี่เป็นเรื่องที่น่าประหลาดใจมากเนื่องจากค่าเริ่มต้นของ Python นั้นค่อนข้างมีประโยชน์พอสมควร อย่างไรก็ตามในกรณีนี้มีค่าเริ่มต้น__repr__ซึ่งจะทำหน้าที่เช่น:

return "%s(%r)" % (self.__class__, self.__dict__)

จะเป็นอันตรายเกินไป (ตัวอย่างเช่นง่ายเกินไปที่จะเข้าสู่การเรียกซ้ำแบบไม่สิ้นสุดหากวัตถุอ้างอิงซึ่งกันและกัน) Python จึงโผล่ออกมา ทราบว่ามีคนเริ่มต้นที่เป็นจริง: ถ้า__repr__มีการกำหนดและไม่ได้เป็นวัตถุจะทำตัวราวกับว่า__str____str__=__repr__

ซึ่งหมายความว่าในแง่ง่ายๆวัตถุเกือบทุกอย่างที่คุณใช้ควรมีฟังก์ชัน__repr__ที่ใช้งานได้เพื่อทำความเข้าใจวัตถุ การนำไปใช้__str__เป็นทางเลือก: ทำเช่นนั้นหากคุณต้องการฟังก์ชั่น“ พิมพ์สวย” (ตัวอย่างเช่นใช้โดยเครื่องมือสร้างรายงาน)

เป้าหมายของ__repr__การที่จะไม่คลุมเครือ

ให้ฉันออกมาทันทีและพูดมัน - ฉันไม่เชื่อใน debuggers ฉันไม่รู้วิธีใช้ดีบักเกอร์จริง ๆ และไม่เคยใช้อย่างจริงจัง นอกจากนี้ฉันเชื่อว่าความผิดพลาดครั้งใหญ่ของผู้ debuggers คือธรรมชาติพื้นฐานของพวกเขา - ความล้มเหลวส่วนใหญ่ที่ฉันดีบักเกิดขึ้นมานานแล้วในกาแลคซีไกลโพ้น ซึ่งหมายความว่าฉันเชื่อด้วยความกระตือรือร้นทางศาสนาในการเข้าสู่ระบบ การบันทึกเป็นส่วนสำคัญของระบบเซิร์ฟเวอร์ไฟและลืมที่ดี Python ช่วยให้ง่ายต่อการเข้าสู่ระบบ: ด้วยการห่อบางโครงการที่เฉพาะเจาะจงสิ่งที่คุณต้องมีคือ

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)

แต่คุณต้องทำตามขั้นตอนสุดท้าย - ตรวจสอบให้แน่ใจว่าทุกอ็อบเจ็กต์ที่คุณใช้มีการพิมพ์ที่มีประโยชน์ดังนั้นโค้ดเช่นนั้นสามารถใช้งานได้ นี่คือเหตุผลที่ว่า“EVAL” สิ่งที่เกิดขึ้นถ้าคุณมีข้อมูลที่เพียงพอเพื่อนั่นหมายความว่าคุณรู้ทุกอย่างมีความรู้เกี่ยวกับeval(repr(c))==c cถ้านั่นง่ายพออย่างน้อยก็ในทางที่คลุมเครือให้ทำ ถ้าไม่แน่ใจว่าคุณมีข้อมูลเพียงพอcอยู่แล้ว ฉันมักจะใช้ EVAL "MyClass(this=%r,that=%r)" % (self.this,self.that)เหมือนรูปแบบ: ไม่ได้หมายความว่าคุณสามารถสร้าง MyClass ได้จริงหรือว่าเป็นอาร์กิวเมนต์ตัวสร้างที่ถูกต้อง แต่เป็นรูปแบบที่มีประโยชน์ในการแสดง“ นี่คือทุกสิ่งที่คุณต้องรู้เกี่ยวกับอินสแตนซ์นี้”

หมายเหตุ: ผมใช้ข้างต้นไม่ได้%r %sคุณต้องการใช้repr()[หรือ%rตัวอักษรการจัดรูปแบบเท่ากัน] ใน__repr__การใช้งานหรือคุณเอาชนะเป้าหมายของการพิมพ์ซ้ำ คุณต้องการที่จะสามารถที่จะแยกความแตกต่างและMyClass(3)MyClass("3")

เป้าหมายของ__str__การอ่านนั้นคือ

โดยเฉพาะมันไม่ได้มีวัตถุประสงค์ที่จะเป็นที่ชัดเจน - str(3)==str("3")แจ้งให้ทราบว่า ในทำนองเดียวกันถ้าคุณใช้นามธรรม Ab, การมี str ของมันดูเหมือน 192.168.1.1 ก็โอเค เมื่อใช้นามธรรมวันที่ / เวลา str สามารถเป็น "2010/4/12 15:35:22" ฯลฯ เป้าหมายคือการแสดงมันในแบบที่ผู้ใช้ไม่ใช่โปรแกรมเมอร์ต้องการที่จะอ่าน ตัดตัวเลขที่ไร้ประโยชน์ออกไปแกล้งเป็นคลาสอื่น - ตราบใดที่มันรองรับการอ่านได้มันเป็นการปรับปรุง

การ__str__ใช้ภาชนะบรรจุวัตถุที่มีอยู่__repr__

มันดูน่าประหลาดใจใช่มั้ย มันน้อย แต่มันจะอ่านได้อย่างไรถ้ามันใช้มัน__str__?

[moshe is, 3, hello
world, this is a list, oh I don't know, containing just 4 elements]

ไม่มาก. โดยเฉพาะอย่างยิ่งสตริงในคอนเทนเนอร์จะพบว่ามันง่ายเกินไปที่จะรบกวนการแสดงสตริง ในการเผชิญกับความกำกวมจำไว้ว่า Python ต่อต้านสิ่งล่อใจที่จะคาดเดา หากคุณต้องการพฤติกรรมข้างต้นเมื่อคุณกำลังพิมพ์รายการเพียง

print "[" + ", ".join(l) + "]"

(คุณอาจจะสามารถคิดได้ว่าจะทำอย่างไรกับพจนานุกรม

สรุป

ใช้งาน__repr__สำหรับคลาสใด ๆ ที่คุณใช้งาน นี่ควรเป็นลักษณะที่สอง ใช้งาน__str__ถ้าคุณคิดว่ามันจะมีประโยชน์ที่จะมีรุ่นสตริงที่ผิดพลาดในด้านของการอ่าน


154
ไม่เห็นด้วยอย่างแน่นอนกับความคิดเห็นของคุณว่าการดีบักไม่ใช่วิธีที่จะไป สำหรับการพัฒนาให้ใช้ดีบักเกอร์ (และ / หรือการบันทึก) สำหรับการบันทึกการใช้งานจริง ด้วยดีบักเกอร์คุณจะสามารถมองเห็นทุกสิ่งที่ผิดพลาดเมื่อเกิดปัญหา คุณสามารถดูภาพเต็ม นอกจากว่าคุณกำลังบันทึกทุกอย่างคุณจะไม่ได้รับสิ่งนั้น นอกจากนี้หากคุณกำลังบันทึกทุกสิ่งที่คุณจะต้องลุยข้อมูลมากมายเพื่อให้ได้สิ่งที่คุณต้องการ
ซามูเอล

21
คำตอบที่ดี (ยกเว้นบิตเกี่ยวกับการไม่ใช้ debuggers) ฉันแค่ต้องการเพิ่มลิงค์ไปยังคำถามและคำตอบอื่น ๆ เกี่ยวกับstr vs unicodeใน Python 3ซึ่งอาจเกี่ยวข้องกับการสนทนาสำหรับผู้ที่เปลี่ยน
ThatAintWorking

11
plus1 สำหรับผู้ใช้ debuggers นั้นไร้ประโยชน์และอย่าเพิ่มมูลค่าเล็กน้อย รับปริมาณงานบันทึกของคุณเพิ่มขึ้นแทน และใช่นี่คือโพสต์เขียนดี ปรากฎ__repr__ว่าเป็นสิ่งที่ฉันต้องการสำหรับการดีบัก ขอขอบคุณสำหรับความช่วยเหลือของคุณ.
personal_cloud

7
นักแก้จุดบกพร่องของคุณเขลากันฉันเรียนรู้% r และนั่นก็คุ้มค่ากับการลงคะแนนอยู่ดี
Mickey Perlstein

6
บน debugger และ no debugger: ไม่ได้รับความคิดเห็นที่ยึดที่มั่นดังกล่าว ในบางแอพพลิเคชั่นการดีบั๊กนั้นไม่เหมือนจริงโดยทั่วไปเมื่อมีส่วนเกี่ยวข้องแบบเรียลไทม์หรือเมื่อโค้ดของคุณรันจากระยะไกลบนแพลตฟอร์มที่เข้าถึงน้อยหรือไม่มีคอนโซล ในกรณีอื่น ๆ ส่วนใหญ่จะเร็วกว่าที่จะหยุดที่ข้อยกเว้นเพื่อตรวจสอบหรือตั้งค่าเบรกพอยต์เนื่องจากคุณไม่จำเป็นต้องผ่านการบันทึกหลายพันบรรทัด (ซึ่งจะทำให้ดิสก์ของคุณยุ่งเหยิงและทำให้แอปพลิเคชันช้าลง) ในที่สุดมันก็เป็นไปไม่ได้ที่จะเข้าสู่ระบบเสมอตัวอย่างเช่นบนอุปกรณ์ฝังตัวมีการดีบักเกอร์ด้วย
RedGlyph

523

กฎง่ายๆของฉัน: __repr__สำหรับนักพัฒนา__str__สำหรับลูกค้า


2
สิ่งนี้เป็นจริงเพราะสำหรับ obj = uuid.uuid1 (), obj .__ str __ () คือ "2d7fc7f0-7706-11e9-94-94-0272-94" และ "obd." Repu __ () คือ "UUID ('2d7fc7f0-7706-112-119-112-94-02-011-02 ')" นักพัฒนาต้องการ (ค่า + แหล่งกำเนิด) ในขณะที่ลูกค้าต้องการค่าและพวกเขาไม่สนใจว่าพวกเขาได้รับมัน!
Naren Yellavula

1
ที่นี่ลูกค้าอาจไม่ได้หมายถึงผู้ใช้ปลายทาง มันเป็นลูกค้าหรือผู้ใช้ของวัตถุ ดังนั้นหากเป็น SDK แล้วผู้พัฒนา SDK จะใช้__str__นักพัฒนาปกติที่มีวัตถุที่อ่านได้ ในทางตรงกันข้าม__repr__สำหรับนักพัฒนา SDK เอง
Shiplu Mokaddim

398

ถ้าคุณไม่ทำอย่างนั้นเป็นพิเศษคลาสส่วนใหญ่จะไม่มีผลลัพธ์ที่เป็นประโยชน์สำหรับ:

>>> class Sic(object): pass
... 
>>> print str(Sic())
<__main__.Sic object at 0x8b7d0>
>>> print repr(Sic())
<__main__.Sic object at 0x8b7d0>
>>> 

ตามที่คุณเห็น - idไม่แตกต่างกันและข้อมูลนอกเหนือจากการเรียนและวัตถุไม่มี หากคุณแทนที่เพียงหนึ่งในสอง ... :

>>> class Sic(object): 
...   def __repr__(object): return 'foo'
... 
>>> print str(Sic())
foo
>>> print repr(Sic())
foo
>>> class Sic(object):
...   def __str__(object): return 'foo'
... 
>>> print str(Sic())
foo
>>> print repr(Sic())
<__main__.Sic object at 0x2617f0>
>>> 

อย่างที่คุณเห็นถ้าคุณลบล้าง__repr__มันก็ยังใช้อยู่__str__แต่ไม่ใช่ในทางกลับกัน

เกร็ดเล็กเกร็ดสำคัญอื่น ๆ ที่ควรรู้: __str__ในตัวเกี่ยวกับการใช้ภาชนะที่__repr__ไม่ได้__str__สำหรับรายการที่มี และแม้จะมีคำเกี่ยวกับเรื่องที่พบในเอกสารทั่วไปแทบไม่มีใครรบกวนการทำ__repr__วัตถุเป็นสตริงที่evalอาจใช้ในการสร้างวัตถุที่เท่าเทียมกัน (มันยากเกินไปและไม่รู้ว่าการนำเข้าโมดูลที่เกี่ยวข้องทำให้มันจริง แบนออกไปไม่ได้)

ดังนั้นคำแนะนำของฉัน: มุ่งเน้นที่การทำให้__str__มนุษย์อ่านได้อย่างสมเหตุสมผลและ__repr__ไม่คลุมเครือเท่าที่คุณจะทำได้แม้ว่าสิ่งนั้นจะรบกวนเป้าหมายที่ไม่สามารถบรรลุได้ของการทำ__repr__ค่าตอบแทนที่ยอมรับได้ว่าเป็นอินพุต__eval__!


34
ในการทดสอบหน่วยของฉันฉันมักจะตรวจสอบว่าประเมินถึงวัตถุเท่ากับeval(repr(foo)) fooคุณสิทธิที่จะไม่ทำงานนอกของกรณีทดสอบของฉันตั้งแต่ฉันไม่ทราบว่าโมดูลจะนำเข้า แต่ที่มั่นใจน้อยว่าการทำงานในบางบริบทที่คาดการณ์ ฉันคิดว่านี่เป็นวิธีที่ดีในการประเมินว่าผลลัพธ์ของ__repr__มันชัดเจนเพียงพอหรือไม่ การทำเช่นนี้ในการทดสอบหน่วยช่วยให้มั่นใจได้ว่าการ__repr__ติดตามการเปลี่ยนแปลงในชั้นเรียน
สตีเวนต. สไนเดอร์

4
ฉันมักจะพยายามที่จะทำให้แน่ใจว่าอย่างใดอย่างหนึ่งeval(repr(spam)) == spam(อย่างน้อยในบริบทที่เหมาะสม) หรือยกeval(repr(spam)) SyntaxErrorวิธีที่คุณหลีกเลี่ยงความสับสน (และเกือบจะเป็นจริงสำหรับ builtins และ stdlib ส่วนใหญ่ยกเว้นรายการที่เรียกซ้ำซึ่งa=[]; a.append(a); print(eval(repr(a)))ให้คุณ[[Ellipses]]... ) แน่นอนว่าฉันไม่ได้ใช้งาน จริงeval(repr(spam))ยกเว้นการตรวจสอบสติในการทดสอบหน่วย ... แต่ฉันทำบางครั้งคัดลอกและวางrepr(spam)ในเซสชันแบบโต้ตอบ
abarnert

ทำไมจะไม่ภาชนะ (รายการ tuples) ใช้ __str__สำหรับแต่ละองค์ประกอบแทน__repr__? ดูเหมือนว่าผิดปกติกับฉันเพราะฉันใช้สิ่งที่อ่านได้__str__ในวัตถุของฉันและเมื่อมันเป็นส่วนหนึ่งของรายการฉันเห็นคนอัปลักษณ์__repr__แทน
SuperGeo

เพิ่งพบข้อผิดพลาดที่น่ารำคาญที่เกี่ยวข้องกับความจริงที่ว่าeval(repr(x))ล้มเหลวแม้กระทั่งสำหรับประเภท builtin: class A(str, Enum): X = 'x'จะเปิด SyntaxError eval(repr(A.X))ขึ้น มันเศร้า แต่เข้าใจได้ BTW eval(str(A.X))ใช้งานได้จริง แต่แน่นอนถ้าclass Aอยู่ในขอบเขตเท่านั้นดังนั้นจึงอาจไม่มีประโยชน์
สูงสุด

@SuperGeo คำตอบอื่น ๆ ครอบคลุมนี้: ภาชนะstrองค์ประกอบการใช้งานreprเพราะ=![1, 2, 3] ["1", "2, 3"]
mtraceur

163

__repr__: การเป็นตัวแทนของวัตถุหลามมักจะ eval จะแปลงกลับเป็นวัตถุนั้น

__str__: เป็นสิ่งที่คุณคิดว่าเป็นวัตถุในรูปแบบข้อความ

เช่น

>>> s="""w'o"w"""
>>> repr(s)
'\'w\\\'o"w\''
>>> str(s)
'w\'o"w'
>>> eval(str(s))==s
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1
    w'o"w
       ^
SyntaxError: EOL while scanning single-quoted string
>>> eval(repr(s))==s
True

151

ในระยะสั้นเป้าหมายของ__repr__การที่จะไม่คลุมเครือและ__str__สามารถอ่านได้

นี่เป็นตัวอย่างที่ดี:

>>> import datetime
>>> today = datetime.datetime.now()
>>> str(today)
'2012-03-14 09:21:58.130922'
>>> repr(today)
'datetime.datetime(2012, 3, 14, 9, 21, 58, 130922)'

อ่านเอกสารนี้สำหรับ repr:

repr(object)

ส่งคืนสตริงที่มีการแสดงวัตถุที่พิมพ์ได้ นี่คือค่าเดียวกันที่ให้ผลโดยการแปลง (อัญประกาศย้อนกลับ) บางครั้งมีประโยชน์ที่จะสามารถเข้าถึงการดำเนินการนี้ในฐานะฟังก์ชันทั่วไป สำหรับหลาย ๆ ประเภทฟังก์ชั่นนี้จะพยายามส่งคืนสตริงที่จะให้ผลตอบแทนวัตถุที่มีค่าเดียวกันเมื่อผ่านไปeval()มิฉะนั้นการแสดงจะเป็นสตริงที่อยู่ในวงเล็บเหลี่ยมที่มีชื่อประเภทของวัตถุพร้อมกับข้อมูลเพิ่มเติม มักจะรวมถึงชื่อและที่อยู่ของวัตถุ ชั้นสามารถควบคุมสิ่งที่ฟังก์ชั่นนี้ส่งกลับสำหรับอินสแตนซ์ของมันโดยการกำหนด__repr__()วิธีการ

นี่คือเอกสารสำหรับ str:

str(object='')

ส่งคืนสตริงที่มีการแสดงวัตถุที่พิมพ์ได้อย่างสวยงาม สำหรับสตริงสิ่งนี้จะส่งคืนสตริงเอง แตกต่างกับrepr(object)เป็นสิ่งที่str(object)ไม่เคยพยายามที่จะกลับสตริงที่เป็นที่ยอมรับไปeval(); เป้าหมายคือส่งคืนสตริงที่พิมพ์ได้ ''ถ้าไม่มีข้อโต้แย้งจะได้รับผลตอบแทนสตริงว่าง


1
ความหมายของสตริงที่พิมพ์ได้ที่นี่คืออะไร? คุณช่วยอธิบายได้มั้ย
Vicrobot

115

ความแตกต่างระหว่าง__str__และ__repr__ในงูใหญ่คืออะไร?

__str__(อ่านว่า "dunder (double-underscore) string") และ__repr__(read as "dunder-repper" (สำหรับ "การแสดง")) เป็นวิธีการพิเศษที่คืนค่าสตริงตามสถานะของวัตถุ

__repr__แสดงพฤติกรรมการสำรองข้อมูลหาก__str__ขาดหายไป

ดังนั้นก่อนอื่นควรเขียน a __repr__ที่อนุญาตให้คุณสร้างวัตถุที่เทียบเท่าจากสตริงที่ส่งคืนเช่นการใช้evalหรือโดยการพิมพ์ในอักขระสำหรับอักขระใน Python shell

เมื่อใดก็ได้ในภายหลังใครสามารถเขียน__str__สำหรับการแสดงสตริงที่ผู้ใช้สามารถอ่านได้ของอินสแตนซ์เมื่อหนึ่งเชื่อว่ามันจะมีความจำเป็น

__str__

หากคุณพิมพ์วัตถุหรือผ่านไปformat, str.formatหรือstrแล้วถ้า__str__วิธีการกำหนดวิธีการที่จะถูกเรียกว่ามิฉะนั้น__repr__จะถูกนำมาใช้

__repr__

__repr__วิธีการที่เรียกว่าฟังก์ชั่นในตัวreprและเป็นสิ่งที่สะท้อนบนเปลือกหลามของคุณเมื่อมันประเมินการแสดงออกที่ส่งกลับวัตถุ

เนื่องจากมันมีการสำรองข้อมูลไว้__str__หากคุณสามารถเขียนได้เพียงหนึ่งรายการให้เริ่มด้วย__repr__

นี่คือความช่วยเหลือในตัวrepr:

repr(...)
    repr(object) -> string

    Return the canonical string representation of the object.
    For most object types, eval(repr(object)) == object.

นั่นคือสำหรับวัตถุส่วนใหญ่หากคุณพิมพ์สิ่งที่พิมพ์โดยreprคุณควรจะสามารถสร้างวัตถุที่เทียบเท่า แต่นี่ไม่ใช่การใช้งานเริ่มต้น

การใช้งานเริ่มต้นของ __repr__

วัตถุเริ่มต้น__repr__คือ ( แหล่ง C Python ) สิ่งที่ชอบ:

def __repr__(self):
    return '<{0}.{1} object at {2}>'.format(
      self.__module__, type(self).__name__, hex(id(self)))

โดยปกติแล้วคุณจะพิมพ์โมดูลที่วัตถุมาจากชื่อคลาสและการแสดงเลขฐานสิบหกของตำแหน่งในหน่วยความจำ - ตัวอย่างเช่น

<__main__.Foo object at 0x7f80665abdd0>

ข้อมูลนี้ไม่มีประโยชน์มาก แต่ไม่มีทางที่จะได้รับว่าใครจะสร้างการแสดงตัวอย่างที่ยอมรับได้อย่างถูกต้องและดีกว่าไม่มีอะไรอย่างน้อยก็บอกเราว่าเราอาจระบุตัวตนในหน่วยความจำได้อย่างไม่ซ้ำใคร

วิธีการอาจ__repr__จะมีประโยชน์หรือไม่

เรามาดูกันว่ามันมีประโยชน์อย่างไรโดยใช้ Python เชลล์และdatetimeวัตถุ ก่อนอื่นเราต้องนำเข้าdatetimeโมดูล:

import datetime

ถ้าเราเรียกใช้datetime.nowในเชลล์เราจะเห็นทุกสิ่งที่เราต้องการในการสร้างออบเจ็กต์วันที่และเวลาที่เทียบเท่า สิ่งนี้ถูกสร้างขึ้นโดย datetime __repr__:

>>> datetime.datetime.now()
datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)

หากเราพิมพ์ออบเจ็กต์วันที่และเวลาเราจะเห็นรูปแบบที่มนุษย์สามารถอ่านได้ (ในความเป็นจริง ISO) สิ่งนี้ถูกนำไปใช้โดยวันที่และเวลา__str__:

>>> print(datetime.datetime.now())
2015-01-24 20:05:44.977951

มันเป็นเรื่องง่ายที่จะสร้างวัตถุที่เราสูญเสียใหม่เพราะเราไม่ได้กำหนดให้กับตัวแปรโดยการคัดลอกและวางจาก__repr__ผลลัพธ์จากนั้นพิมพ์มันและเราได้มันในผลลัพธ์ที่มนุษย์สามารถอ่านได้เหมือนกับวัตถุอื่น:

>>> the_past = datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
>>> print(the_past)
2015-01-24 20:05:36.491180

ฉันจะใช้งานได้อย่างไร

ในขณะที่คุณกำลังพัฒนาคุณจะต้องการที่จะทำซ้ำวัตถุในสถานะเดียวกันถ้าเป็นไปได้ ตัวอย่างเช่นนี่เป็นวิธีที่วัตถุ datetime กำหนด__repr__( แหล่ง Python ) มันค่อนข้างซับซ้อนเนื่องจากคุณสมบัติทั้งหมดที่จำเป็นในการทำซ้ำวัตถุดังกล่าว:

def __repr__(self):
    """Convert to formal string, for repr()."""
    L = [self._year, self._month, self._day,  # These are never zero
         self._hour, self._minute, self._second, self._microsecond]
    if L[-1] == 0:
        del L[-1]
    if L[-1] == 0:
        del L[-1]
    s = "%s.%s(%s)" % (self.__class__.__module__,
                       self.__class__.__qualname__,
                       ", ".join(map(str, L)))
    if self._tzinfo is not None:
        assert s[-1:] == ")"
        s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
    if self._fold:
        assert s[-1:] == ")"
        s = s[:-1] + ", fold=1)"
    return s

หากคุณต้องการให้วัตถุของคุณมีการแสดงที่เป็นมนุษย์อ่านได้มากขึ้นคุณสามารถนำ__str__ไปใช้งานต่อไป นี่คือวิธีการที่วัตถุ datetime ( แหล่งที่มาของ Python ) นำไปใช้งาน__str__ซึ่งทำได้ง่ายเพราะมันมีฟังก์ชั่นที่จะแสดงมันในรูปแบบ ISO:

def __str__(self):
    "Convert to string, for str()."
    return self.isoformat(sep=' ')

ตั้งค่า__repr__ = __str__หรือไม่

__repr__ = __str__นี้เป็นคำวิจารณ์ของคำตอบที่นี่อีกที่แสดงให้เห็นการตั้งค่า

การตั้งค่า__repr__ = __str__โง่ - __repr__เป็นทางเลือกสำหรับ__str__และเขียนสำหรับการใช้งานนักพัฒนาในการแก้จุดบกพร่องควรจะเขียนขึ้นก่อนที่คุณเขียน__repr____str__

คุณต้องการ__str__เพียงเมื่อคุณต้องการแสดงข้อความของวัตถุ

ข้อสรุป

กำหนด__repr__วัตถุที่คุณเขียนเพื่อให้คุณและนักพัฒนาอื่น ๆ มีตัวอย่างที่ทำซ้ำได้เมื่อใช้ในขณะที่คุณพัฒนา กำหนด__str__เมื่อคุณต้องการการแทนค่าสตริงที่มนุษย์สามารถอ่านได้


มันควรจะเป็นบางสิ่งบางอย่างตามแนวของtype(obj).__qualname__?
โซโลมอน Ucko

@SolomonUcko ใช่ใน Python 3 ที่ดูเหมือนจะเป็นกรณีนี้ - ฉันได้ตามล่าซอร์สโค้ดที่มีการใช้งานแล้วและฉันจะอัปเดตคำตอบของฉันด้วยข้อมูลนั้นเมื่อฉันรวมมันเข้าด้วยกัน
Aaron Hall

33

ในหน้า 358 ของหนังสือPython scripting สำหรับวิทยาศาสตร์การคำนวณโดย Hans Petter Langtangen มันชัดเจนว่า

  • __repr__จุดมุ่งหมายในการแสดงสตริงสมบูรณ์ของวัตถุนั้น
  • __str__คือการกลับสตริงที่ดีสำหรับการพิมพ์

ดังนั้นฉันชอบที่จะเข้าใจพวกเขาเป็น

  • repr = ทำซ้ำ
  • str = string (การแทนค่า)

จากมุมมองของผู้ใช้แม้ว่านี่จะเป็นความเข้าใจผิดที่ฉันทำเมื่อเรียนรู้หลาม

ตัวอย่างเล็ก ๆ แต่ดีจะได้รับในหน้าเดียวกันดังต่อไปนี้:

ตัวอย่าง

In [38]: str('s')
Out[38]: 's'

In [39]: repr('s')
Out[39]: "'s'"

In [40]: eval(str('s'))
Traceback (most recent call last):

  File "<ipython-input-40-abd46c0c43e7>", line 1, in <module>
    eval(str('s'))

  File "<string>", line 1, in <module>

NameError: name 's' is not defined


In [41]: eval(repr('s'))
Out[41]: 's'

มันอยู่ที่ pg # 351
jiten

4
มันเป็นความเข้าใจผิดที่เรียกreprว่าการทำซ้ำ มันเป็นการดีกว่าที่จะคิดว่ามันเป็นตัวแทน
NelsonGon

31

นอกเหนือจากคำตอบที่ได้รับทั้งหมดฉันต้องการเพิ่มบางจุด: -

1) __repr__()ถูกเรียกใช้เมื่อคุณเขียนชื่อของวัตถุบนคอนโซล python แบบโต้ตอบแล้วกด Enter

2) __str__()ถูกเรียกใช้เมื่อคุณใช้วัตถุที่มีคำสั่งพิมพ์

3) ในกรณีที่หาก__str__หายไปให้พิมพ์และฟังก์ชั่นใด ๆ โดยใช้การstr()เรียกใช้__repr__()วัตถุ

4) __str__()ของคอนเทนเนอร์เมื่อเรียกใช้จะดำเนิน__repr__()การวิธีการขององค์ประกอบที่มีอยู่

5) str()เรียกภายใน__str__()อาจจะสามารถเรียกคืนโดยไม่มีกรณีพื้นฐานและข้อผิดพลาดเกี่ยวกับความลึกของการเรียกซ้ำสูงสุด

6) __repr__()สามารถโทรซึ่งจะพยายามที่จะหลีกเลี่ยงการเรียกซ้ำอนันต์โดยอัตโนมัติเปลี่ยนวัตถุเป็นตัวแทนที่มีอยู่แล้วrepr()...


14

หากต้องการใส่เพียง:

__str__ใช้ในการแสดงการแสดงสตริงของวัตถุของคุณเพื่อให้ผู้อื่นอ่านได้ง่าย

__repr__จะใช้ในการแสดงเป็นตัวแทนสตริงของวัตถุ

สมมติว่าฉันต้องการสร้างFractionคลาสที่การแสดงสตริงของเศษส่วนเป็น '(1/2)' และวัตถุ (คลาสเศษส่วน) จะแสดงเป็น 'เศษส่วน (1,2)'

ดังนั้นเราสามารถสร้างคลาสเศษส่วนอย่างง่าย:

class Fraction:
    def __init__(self, num, den):
        self.__num = num
        self.__den = den

    def __str__(self):
        return '(' + str(self.__num) + '/' + str(self.__den) + ')'

    def __repr__(self):
        return 'Fraction (' + str(self.__num) + ',' + str(self.__den) + ')'



f = Fraction(1,2)
print('I want to represent the Fraction STRING as ' + str(f)) # (1/2)
print('I want to represent the Fraction OBJECT as ', repr(f)) # Fraction (1,2)

13

ในความซื่อสัตย์ทั้งหมดeval(repr(obj))ไม่เคยใช้ หากคุณพบว่าคุณใช้มันคุณควรหยุดเพราะevalเป็นอันตรายและสตริงเป็นวิธีที่ไม่มีประสิทธิภาพมากในการทำให้เป็นอันดับวัตถุของคุณ (ใช้pickleแทน)

__repr__ = __str__ดังนั้นผมจะแนะนำการตั้งค่า เหตุผลก็คือการstr(list)เรียกreprใช้องค์ประกอบ (ฉันคิดว่านี่เป็นหนึ่งในข้อบกพร่องการออกแบบที่ใหญ่ที่สุดของ Python ที่ไม่ได้ระบุไว้โดย Python 3) ที่เกิดขึ้นจริงอาจจะไม่เป็นประโยชน์มากในขณะที่การส่งออกของreprprint [your, objects]

เพื่อให้มีคุณสมบัตินี้ในประสบการณ์ของฉันกรณีการใช้งานที่มีประโยชน์ที่สุดของreprฟังก์ชั่นคือการใส่สตริงไว้ในสตริงอื่น (โดยใช้การจัดรูปแบบสตริง) ด้วยวิธีนี้คุณไม่ต้องกังวลกับการหลีกหนีคำพูดหรืออะไรก็ตาม แต่โปรดทราบว่าไม่มีevalสิ่งใดเกิดขึ้นที่นี่


19
ฉันคิดว่านี่พลาดประเด็น การใช้eval(repr(obj))คือการทดสอบสติและกฎของหัวแม่มือ - ถ้าสิ่งนี้สร้างวัตถุเดิมอย่างถูกต้องแล้วคุณมีการ__repr__ใช้งานที่เหมาะสม มันไม่ได้ตั้งใจว่าคุณจะทำให้วัตถุเป็นอนุกรมในลักษณะนี้
jwg

7
evalไม่เป็นอันตรายโดยเนื้อแท้ ไม่เป็นอันตรายมากกว่าunlink, openหรือการเขียนไปยังแฟ้ม เราควรหยุดเขียนไฟล์เพราะบางทีการโจมตีที่ประสงค์ร้ายอาจใช้เส้นทางไฟล์โดยพลการเพื่อวางเนื้อหาไว้ข้างใน? ทุกอย่างเป็นอันตรายถ้าคนโง่ใช้โดยโง่ งี่เง่าเป็นอันตราย ผลของ Dunning-Kruger นั้นอันตราย evalเป็นเพียงฟังก์ชั่น
Luis Masuelli

12

จากPython อ้างอิงวิกิพีเดีย (คัดลอกถาวร)โดย effbot

__str__" คำนวณการแสดงสตริง" ไม่เป็นทางการ "ของวัตถุสิ่งนี้แตกต่างจาก__repr__ที่ไม่จำเป็นต้องเป็นนิพจน์ Python ที่ถูกต้อง: การแสดงที่สะดวกหรือกระชับอาจใช้แทนได้ "


3
__repr__ไม่จำเป็นต้องส่งคืนนิพจน์ vaild Python
นักฟิสิกส์บ้า

10

str - สร้างวัตถุสตริงใหม่จากวัตถุที่กำหนด

repr - ส่งคืนการแทนค่าสตริงแบบบัญญัติของวัตถุ

ความแตกต่าง:

STR ():

  • ทำให้วัตถุอ่านได้
  • สร้างเอาต์พุตสำหรับผู้ใช้ปลายทาง

Repr ():

  • ต้องการรหัสที่สร้างวัตถุ
  • สร้างผลลัพธ์สำหรับนักพัฒนา

8

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

  • เป้าหมายของ__str__: มนุษย์อ่านได้
  • เป้าหมายของ__repr__: ไม่คลุมเครืออาจอ่านผ่านเครื่องได้eval

น่าเสียดายที่ความแตกต่างนี้มีข้อบกพร่องเนื่องจาก Python REPL และ IPython ใช้__repr__สำหรับการพิมพ์วัตถุในคอนโซล REPL (ดูคำถามที่เกี่ยวข้องสำหรับPythonและIPython ) ดังนั้นโครงการที่มีการกำหนดเป้าหมายสำหรับงานคอนโซลแบบโต้ตอบ (เช่น Numpy หรือ Pandas) ได้เริ่มละเว้นกฎข้างต้นและจัดให้มีการใช้งานที่มนุษย์สามารถอ่านได้__repr__แทน


7

จากหนังสือFluent Python :

ข้อกำหนดพื้นฐานสำหรับวัตถุ Python คือการให้การแสดงสตริงที่ใช้งานได้ของตัวเองหนึ่งที่ใช้สำหรับการแก้จุดบกพร่องและการเข้าสู่ระบบอีกประการหนึ่งสำหรับการนำเสนอให้กับผู้ใช้ปลายทาง นั่นคือเหตุผลที่
วิธีการพิเศษ__repr__และ__str__มีอยู่ในรูปแบบข้อมูล


5

คำตอบที่ยอดเยี่ยมได้ครอบคลุมความแตกต่างระหว่าง__str__และ__repr__ซึ่งสำหรับฉันแล้วผู้คนทั่วไปสามารถอ่านได้แม้กระทั่งกับผู้ใช้ปลายทาง ระบุว่าฉันพบว่าการใช้งานเริ่มต้นของ__repr__มักจะล้มเหลวในการบรรลุเป้าหมายนี้เพราะละเว้นข้อมูลที่เป็นประโยชน์ต่อนักพัฒนา

ด้วยเหตุนี้ถ้าฉันมีความเรียบง่ายพอ__str__ฉันมักจะพยายามทำให้ดีที่สุดในโลกทั้งสองด้วยสิ่งที่ชอบ:

def __repr__(self):
    return '{0} ({1})'.format(object.__repr__(self), str(self))

4

สิ่งหนึ่งที่สำคัญที่จะเก็บไว้ในใจก็คือว่าคอนเทนเนอร์ที่__str__ใช้บรรจุวัตถุ__repr__

>>> from datetime import datetime
>>> from decimal import Decimal
>>> print (Decimal('52'), datetime.now())
(Decimal('52'), datetime.datetime(2015, 11, 16, 10, 51, 26, 185000))
>>> str((Decimal('52'), datetime.now()))
"(Decimal('52'), datetime.datetime(2015, 11, 16, 10, 52, 22, 176000))"

งูหลามโปรดปรานไม่น่าสงสัยมากกว่าการอ่านการ__str__โทรของtupleเรียกวัตถุที่มีอยู่__repr__ที่'อย่างเป็นทางการ'เป็นตัวแทนของวัตถุ แม้ว่าการเป็นตัวแทนอย่างเป็นทางการนั้นจะยากต่อการอ่านมากกว่าแบบที่ไม่เป็นทางการ แต่ก็ไม่คลุมเครือและแข็งแกร่งกว่ากับข้อบกพร่อง


มันใช้__repr__ เมื่อมัน ( __str__) ไม่ได้กำหนดไว้! ดังนั้นคุณคิดผิด
jiten

4

โดยสังเขป:

class Demo:
  def __repr__(self):
    return 'repr'
  def __str__(self):
    return 'str'

demo = Demo()
print(demo) # use __str__, output 'str' to stdout

s = str(demo) # __str__ is used, return 'str'
r = repr(demo) # __repr__ is used, return 'repr'

import logging
logger = logging.getLogger(logging.INFO)
logger.info(demo) # use __str__, output 'str' to stdout

from pprint import pprint, pformat
pprint(demo) # use __repr__, output 'repr' to stdout
result = pformat(demo) # use __repr__, result is string which value is 'str'

4
>>> print(decimal.Decimal(23) / decimal.Decimal("1.05"))
21.90476190476190476190476190
>>> decimal.Decimal(23) / decimal.Decimal("1.05")
Decimal('21.90476190476190476190476190')

เมื่อprint()ถูกเรียกบนผลลัพธ์ของdecimal.Decimal(23) / decimal.Decimal("1.05")หมายเลขดิบจะถูกพิมพ์ ผลลัพธ์นี้อยู่ในรูปแบบสตริง__str__()ซึ่งสามารถทำได้ด้วย ถ้าเราเพียงแค่ใส่แสดงออกเราได้รับdecimal.Decimalการส่งออก - ส่งออกนี้คือในแบบฟอร์มการดำเนินการ__repr__()ซึ่งสามารถทำได้ด้วย วัตถุ Python ทั้งหมดมีสองรูปแบบผลลัพธ์ รูปแบบสตริงถูกออกแบบมาให้มนุษย์อ่านได้ แบบฟอร์ม Representational ได้รับการออกแบบเพื่อผลิตผลลัพธ์ที่หากป้อนไปยังล่าม Python จะ (ทำซ้ำ) วัตถุที่เป็นตัวแทน


4

__str__สามารถเรียกใช้บนวัตถุโดยการเรียกใช้str(obj)และควรส่งคืนสตริงที่มนุษย์สามารถอ่านได้

__repr__ สามารถเรียกใช้บนวัตถุโดยการโทร repr(obj)และควรส่งคืนวัตถุภายใน (เขตข้อมูลวัตถุ / แอตทริบิวต์)

ตัวอย่างนี้อาจช่วย:

class C1:pass

class C2:        
    def __str__(self):
        return str(f"{self.__class__.__name__} class str ")

class C3:        
    def __repr__(self):        
         return str(f"{self.__class__.__name__} class repr")

class C4:        
    def __str__(self):
        return str(f"{self.__class__.__name__} class str ")
    def __repr__(self):        
         return str(f"{self.__class__.__name__} class repr")


ci1 = C1()    
ci2 = C2()  
ci3 = C3()  
ci4 = C4()

print(ci1)       #<__main__.C1 object at 0x0000024C44A80C18>
print(str(ci1))  #<__main__.C1 object at 0x0000024C44A80C18>
print(repr(ci1)) #<__main__.C1 object at 0x0000024C44A80C18>
print(ci2)       #C2 class str
print(str(ci2))  #C2 class str
print(repr(ci2)) #<__main__.C2 object at 0x0000024C44AE12E8>
print(ci3)       #C3 class repr
print(str(ci3))  #C3 class repr
print(repr(ci3)) #C3 class repr
print(ci4)       #C4 class str 
print(str(ci4))  #C4 class str 
print(repr(ci4)) #C4 class repr

3

ทำความเข้าใจ__str__และ__repr__แยกแยะความแตกต่างอย่างถาวรและอย่างสังหรณ์ใจ

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

ดูในตัวอย่าง

In [30]: str(datetime.datetime.now())
Out[30]: '2017-12-07 15:41:14.002752'
Disguised in string form

ตามที่ __repr__

In [32]: datetime.datetime.now()
Out[32]: datetime.datetime(2017, 12, 7, 15, 43, 27, 297769)
Presence in real body which allows to be manipulated directly.

เราสามารถทำการคำนวณทางคณิตศาสตร์กับ__repr__ผลลัพธ์ได้อย่างสะดวก

In [33]: datetime.datetime.now()
Out[33]: datetime.datetime(2017, 12, 7, 15, 47, 9, 741521)
In [34]: datetime.datetime(2017, 12, 7, 15, 47, 9, 741521) - datetime.datetime(2
    ...: 017, 12, 7, 15, 43, 27, 297769)
Out[34]: datetime.timedelta(0, 222, 443752)

ถ้าใช้การดำเนินการบน __str__

In [35]: '2017-12-07 15:43:14.002752' - '2017-12-07 15:41:14.002752'
TypeError: unsupported operand type(s) for -: 'str' and 'str'

ไม่ส่งคืนยกเว้นข้อผิดพลาด

ตัวอย่างอื่น.

In [36]: str('string_body')
Out[36]: 'string_body' # in string form

In [37]: repr('real_body')
Out[37]: "'real_body'" #its real body hide inside

หวังว่านี่จะช่วยคุณสร้างพื้นคอนกรีตเพื่อสำรวจคำตอบเพิ่มเติม


3
  1. __str__ต้องส่งคืนวัตถุสตริงในขณะที่__repr__สามารถส่งคืนการแสดงออกของหลามใด ๆ
  2. หาก__str__การใช้งานหายไป__repr__ฟังก์ชันจะใช้เป็นทางเลือก ไม่มีทางเลือกหาก__repr__การใช้ฟังก์ชันหายไป
  3. หาก__repr__ฟังก์ชันส่งคืนการแทนค่าสตริงของวัตถุเราสามารถข้ามการนำ__str__ฟังก์ชันไปใช้

ที่มา: https://www.journaldev.com/22460/python-str-repr-functions


2

__repr__มีการใช้ทุกที่ยกเว้นโดยprintและstrวิธีการ (เมื่อมีการ__str__กำหนด!)

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