ความแตกต่างระหว่าง__str__
และ__repr__
ในงูใหญ่คืออะไร?
ความแตกต่างระหว่าง__str__
และ__repr__
ในงูใหญ่คืออะไร?
คำตอบ:
อเล็กซ์สรุปได้ดี แต่น่าแปลกใจที่รวบรัดเกินไป
ก่อนอื่นให้ฉันย้ำประเด็นหลักในการโพสต์ของ 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__
ถ้าคุณคิดว่ามันจะมีประโยชน์ที่จะมีรุ่นสตริงที่ผิดพลาดในด้านของการอ่าน
__repr__
ว่าเป็นสิ่งที่ฉันต้องการสำหรับการดีบัก ขอขอบคุณสำหรับความช่วยเหลือของคุณ.
กฎง่ายๆของฉัน: __repr__
สำหรับนักพัฒนา__str__
สำหรับลูกค้า
__str__
นักพัฒนาปกติที่มีวัตถุที่อ่านได้ ในทางตรงกันข้าม__repr__
สำหรับนักพัฒนา SDK เอง
ถ้าคุณไม่ทำอย่างนั้นเป็นพิเศษคลาสส่วนใหญ่จะไม่มีผลลัพธ์ที่เป็นประโยชน์สำหรับ:
>>> 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__
!
eval(repr(foo))
foo
คุณสิทธิที่จะไม่ทำงานนอกของกรณีทดสอบของฉันตั้งแต่ฉันไม่ทราบว่าโมดูลจะนำเข้า แต่ที่มั่นใจน้อยว่าการทำงานในบางบริบทที่คาดการณ์ ฉันคิดว่านี่เป็นวิธีที่ดีในการประเมินว่าผลลัพธ์ของ__repr__
มันชัดเจนเพียงพอหรือไม่ การทำเช่นนี้ในการทดสอบหน่วยช่วยให้มั่นใจได้ว่าการ__repr__
ติดตามการเปลี่ยนแปลงในชั้นเรียน
eval(repr(spam)) == spam
(อย่างน้อยในบริบทที่เหมาะสม) หรือยกeval(repr(spam))
SyntaxError
วิธีที่คุณหลีกเลี่ยงความสับสน (และเกือบจะเป็นจริงสำหรับ builtins และ stdlib ส่วนใหญ่ยกเว้นรายการที่เรียกซ้ำซึ่งa=[]; a.append(a); print(eval(repr(a)))
ให้คุณ[[Ellipses]]
... ) แน่นอนว่าฉันไม่ได้ใช้งาน จริงeval(repr(spam))
ยกเว้นการตรวจสอบสติในการทดสอบหน่วย ... แต่ฉันทำบางครั้งคัดลอกและวางrepr(spam)
ในเซสชันแบบโต้ตอบ
__str__
สำหรับแต่ละองค์ประกอบแทน__repr__
? ดูเหมือนว่าผิดปกติกับฉันเพราะฉันใช้สิ่งที่อ่านได้__str__
ในวัตถุของฉันและเมื่อมันเป็นส่วนหนึ่งของรายการฉันเห็นคนอัปลักษณ์__repr__
แทน
eval(repr(x))
ล้มเหลวแม้กระทั่งสำหรับประเภท builtin: class A(str, Enum): X = 'x'
จะเปิด SyntaxError eval(repr(A.X))
ขึ้น มันเศร้า แต่เข้าใจได้ BTW eval(str(A.X))
ใช้งานได้จริง แต่แน่นอนถ้าclass A
อยู่ในขอบเขตเท่านั้นดังนั้นจึงอาจไม่มีประโยชน์
str
องค์ประกอบการใช้งานrepr
เพราะ=![1, 2, 3]
["1", "2, 3"]
__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
ในระยะสั้นเป้าหมายของ
__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()
; เป้าหมายคือส่งคืนสตริงที่พิมพ์ได้''
ถ้าไม่มีข้อโต้แย้งจะได้รับผลตอบแทนสตริงว่าง
ความแตกต่างระหว่าง
__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__
?
ในหน้า 358 ของหนังสือPython scripting สำหรับวิทยาศาสตร์การคำนวณโดย Hans Petter Langtangen มันชัดเจนว่า
__repr__
จุดมุ่งหมายในการแสดงสตริงสมบูรณ์ของวัตถุนั้น__str__
คือการกลับสตริงที่ดีสำหรับการพิมพ์ดังนั้นฉันชอบที่จะเข้าใจพวกเขาเป็น
จากมุมมองของผู้ใช้แม้ว่านี่จะเป็นความเข้าใจผิดที่ฉันทำเมื่อเรียนรู้หลาม
ตัวอย่างเล็ก ๆ แต่ดีจะได้รับในหน้าเดียวกันดังต่อไปนี้:
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'
repr
ว่าการทำซ้ำ มันเป็นการดีกว่าที่จะคิดว่ามันเป็นตัวแทน
นอกเหนือจากคำตอบที่ได้รับทั้งหมดฉันต้องการเพิ่มบางจุด: -
1) __repr__()
ถูกเรียกใช้เมื่อคุณเขียนชื่อของวัตถุบนคอนโซล python แบบโต้ตอบแล้วกด Enter
2) __str__()
ถูกเรียกใช้เมื่อคุณใช้วัตถุที่มีคำสั่งพิมพ์
3) ในกรณีที่หาก__str__
หายไปให้พิมพ์และฟังก์ชั่นใด ๆ โดยใช้การstr()
เรียกใช้__repr__()
วัตถุ
4) __str__()
ของคอนเทนเนอร์เมื่อเรียกใช้จะดำเนิน__repr__()
การวิธีการขององค์ประกอบที่มีอยู่
5) str()
เรียกภายใน__str__()
อาจจะสามารถเรียกคืนโดยไม่มีกรณีพื้นฐานและข้อผิดพลาดเกี่ยวกับความลึกของการเรียกซ้ำสูงสุด
6) __repr__()
สามารถโทรซึ่งจะพยายามที่จะหลีกเลี่ยงการเรียกซ้ำอนันต์โดยอัตโนมัติเปลี่ยนวัตถุเป็นตัวแทนที่มีอยู่แล้วrepr()
...
หากต้องการใส่เพียง:
__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)
ในความซื่อสัตย์ทั้งหมดeval(repr(obj))
ไม่เคยใช้ หากคุณพบว่าคุณใช้มันคุณควรหยุดเพราะeval
เป็นอันตรายและสตริงเป็นวิธีที่ไม่มีประสิทธิภาพมากในการทำให้เป็นอันดับวัตถุของคุณ (ใช้pickle
แทน)
__repr__ = __str__
ดังนั้นผมจะแนะนำการตั้งค่า เหตุผลก็คือการstr(list)
เรียกrepr
ใช้องค์ประกอบ (ฉันคิดว่านี่เป็นหนึ่งในข้อบกพร่องการออกแบบที่ใหญ่ที่สุดของ Python ที่ไม่ได้ระบุไว้โดย Python 3) ที่เกิดขึ้นจริงอาจจะไม่เป็นประโยชน์มากในขณะที่การส่งออกของrepr
print [your, objects]
เพื่อให้มีคุณสมบัตินี้ในประสบการณ์ของฉันกรณีการใช้งานที่มีประโยชน์ที่สุดของrepr
ฟังก์ชั่นคือการใส่สตริงไว้ในสตริงอื่น (โดยใช้การจัดรูปแบบสตริง) ด้วยวิธีนี้คุณไม่ต้องกังวลกับการหลีกหนีคำพูดหรืออะไรก็ตาม แต่โปรดทราบว่าไม่มีeval
สิ่งใดเกิดขึ้นที่นี่
eval(repr(obj))
คือการทดสอบสติและกฎของหัวแม่มือ - ถ้าสิ่งนี้สร้างวัตถุเดิมอย่างถูกต้องแล้วคุณมีการ__repr__
ใช้งานที่เหมาะสม มันไม่ได้ตั้งใจว่าคุณจะทำให้วัตถุเป็นอนุกรมในลักษณะนี้
eval
ไม่เป็นอันตรายโดยเนื้อแท้ ไม่เป็นอันตรายมากกว่าunlink
, open
หรือการเขียนไปยังแฟ้ม เราควรหยุดเขียนไฟล์เพราะบางทีการโจมตีที่ประสงค์ร้ายอาจใช้เส้นทางไฟล์โดยพลการเพื่อวางเนื้อหาไว้ข้างใน? ทุกอย่างเป็นอันตรายถ้าคนโง่ใช้โดยโง่ งี่เง่าเป็นอันตราย ผลของ Dunning-Kruger นั้นอันตราย eval
เป็นเพียงฟังก์ชั่น
จากPython อ้างอิงวิกิพีเดีย (คัดลอกถาวร)โดย effbot
__str__
" คำนวณการแสดงสตริง" ไม่เป็นทางการ "ของวัตถุสิ่งนี้แตกต่างจาก__repr__
ที่ไม่จำเป็นต้องเป็นนิพจน์ Python ที่ถูกต้อง: การแสดงที่สะดวกหรือกระชับอาจใช้แทนได้ "
__repr__
ไม่จำเป็นต้องส่งคืนนิพจน์ vaild Python
str
- สร้างวัตถุสตริงใหม่จากวัตถุที่กำหนด
repr
- ส่งคืนการแทนค่าสตริงแบบบัญญัติของวัตถุ
ความแตกต่าง:
STR ():
Repr ():
แง่มุมหนึ่งที่ขาดหายไปในคำตอบอื่น ๆ เป็นเรื่องจริงที่โดยทั่วไปแล้วรูปแบบคือ:
__str__
: มนุษย์อ่านได้__repr__
: ไม่คลุมเครืออาจอ่านผ่านเครื่องได้eval
น่าเสียดายที่ความแตกต่างนี้มีข้อบกพร่องเนื่องจาก Python REPL และ IPython ใช้__repr__
สำหรับการพิมพ์วัตถุในคอนโซล REPL (ดูคำถามที่เกี่ยวข้องสำหรับPythonและIPython ) ดังนั้นโครงการที่มีการกำหนดเป้าหมายสำหรับงานคอนโซลแบบโต้ตอบ (เช่น Numpy หรือ Pandas) ได้เริ่มละเว้นกฎข้างต้นและจัดให้มีการใช้งานที่มนุษย์สามารถอ่านได้__repr__
แทน
จากหนังสือFluent Python :
ข้อกำหนดพื้นฐานสำหรับวัตถุ Python คือการให้การแสดงสตริงที่ใช้งานได้ของตัวเองหนึ่งที่ใช้สำหรับการแก้จุดบกพร่องและการเข้าสู่ระบบอีกประการหนึ่งสำหรับการนำเสนอให้กับผู้ใช้ปลายทาง นั่นคือเหตุผลที่
วิธีการพิเศษ__repr__
และ__str__
มีอยู่ในรูปแบบข้อมูล
คำตอบที่ยอดเยี่ยมได้ครอบคลุมความแตกต่างระหว่าง__str__
และ__repr__
ซึ่งสำหรับฉันแล้วผู้คนทั่วไปสามารถอ่านได้แม้กระทั่งกับผู้ใช้ปลายทาง ระบุว่าฉันพบว่าการใช้งานเริ่มต้นของ__repr__
มักจะล้มเหลวในการบรรลุเป้าหมายนี้เพราะละเว้นข้อมูลที่เป็นประโยชน์ต่อนักพัฒนา
ด้วยเหตุนี้ถ้าฉันมีความเรียบง่ายพอ__str__
ฉันมักจะพยายามทำให้ดีที่สุดในโลกทั้งสองด้วยสิ่งที่ชอบ:
def __repr__(self):
return '{0} ({1})'.format(object.__repr__(self), str(self))
สิ่งหนึ่งที่สำคัญที่จะเก็บไว้ในใจก็คือว่าคอนเทนเนอร์ที่
__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__
) ไม่ได้กำหนดไว้! ดังนั้นคุณคิดผิด
โดยสังเขป:
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'
>>> 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 จะ (ทำซ้ำ) วัตถุที่เป็นตัวแทน
__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
ทำความเข้าใจ__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
หวังว่านี่จะช่วยคุณสร้างพื้นคอนกรีตเพื่อสำรวจคำตอบเพิ่มเติม
__str__
ต้องส่งคืนวัตถุสตริงในขณะที่__repr__
สามารถส่งคืนการแสดงออกของหลามใด ๆ__str__
การใช้งานหายไป__repr__
ฟังก์ชันจะใช้เป็นทางเลือก ไม่มีทางเลือกหาก__repr__
การใช้ฟังก์ชันหายไป__repr__
ฟังก์ชันส่งคืนการแทนค่าสตริงของวัตถุเราสามารถข้ามการนำ__str__
ฟังก์ชันไปใช้ที่มา: https://www.journaldev.com/22460/python-str-repr-functions
__repr__
มีการใช้ทุกที่ยกเว้นโดยprint
และstr
วิธีการ (เมื่อมีการ__str__
กำหนด!)