ความแตกต่างระหว่าง__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) ที่เกิดขึ้นจริงอาจจะไม่เป็นประโยชน์มากในขณะที่การส่งออกของreprprint [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__กำหนด!)