วิธีพิมพ์อินสแตนซ์ของคลาสโดยใช้ print ()


538

ฉันกำลังเรียนรู้เชือกในงูหลาม เมื่อฉันพยายามพิมพ์วัตถุของคลาสFoobarโดยใช้print()ฟังก์ชั่นฉันจะได้ผลลัพธ์เช่นนี้

<__main__.Foobar instance at 0x7ff2a18c>

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

หากคุณคุ้นเคยกับคลาส C ++ สามารถทำได้ตามมาตรฐานด้านบนostreamโดยการเพิ่มfriend ostream& operator << (ostream&, const Foobar&)เมธอดสำหรับคลาส

คำตอบ:


628
>>> class Test:
...     def __repr__(self):
...         return "Test()"
...     def __str__(self):
...         return "member of Test"
... 
>>> t = Test()
>>> t
Test()
>>> print(t)
member of Test

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

หากไม่มี__str__วิธีใดที่ระบุไว้ Python จะพิมพ์ผลลัพธ์__repr__แทน หากคุณกำหนด__str__แต่ไม่ใช่__repr__Python จะใช้สิ่งที่คุณเห็นด้านบนเป็น__repr__แต่ยังใช้__str__สำหรับการพิมพ์


11
นอกจากนี้ยังมีวิธีการUnicodeซึ่งคุณสามารถใช้แทนStr ; โปรดทราบว่ามันควรจะส่งคืนวัตถุ Unicode ไม่ใช่สตริง (แต่ถ้าคุณส่งคืนสตริงการแปลงเป็น Unicode จะต้องดำเนินการต่อไป ... )
kender

@kender - ฉันไม่รู้เกี่ยวกับมัน แต่ในการหวนกลับมันทำให้รู้สึกสมบูรณ์แบบเนื่องจากการจัดการ Unicode ที่หักของ Python 2.x
คริสลัทซ์

11
ฉันคิดว่าคำตอบนี้ไม่สามารถดำเนินการให้เสร็จสิ้นได้หากไม่มีลิงค์ไปยังที่อื่น !
tnotstar

ช่วยฉันด้วย! อย่างไรก็ตามหลังจากนำวิธีการ __repr __ (ตัวเอง) ไปใช้อีกครั้งการพิมพ์จะทำให้ผู้ใช้เข้าใจผิด คุณรู้วิธีปฏิบัติที่ดีที่สุดในเรื่องนี้หรือไม่?
เวียต

10
สำหรับโปรแกรมเมอร์ Java: __str __ (ตัวเอง) เปรียบเสมือน toString () ของโลกหลาม
Janac Meena

134

ดังที่ Chris Lutz พูดถึงสิ่งนี้ถูกกำหนดโดย__repr__วิธีการในชั้นเรียนของคุณ

จากเอกสารของrepr():

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

รับการทดสอบระดับต่อไปนี้:

class Test:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __repr__(self):
        return "<Test a:%s b:%s>" % (self.a, self.b)

    def __str__(self):
        return "From str method of Test: a is %s, b is %s" % (self.a, self.b)

..it จะทำหน้าที่ดังต่อไปนี้ใน Python shell:

>>> t = Test(123, 456)
>>> t
<Test a:123 b:456>
>>> print repr(t)
<Test a:123 b:456>
>>> print(t)
From str method of Test: a is 123, b is 456
>>> print(str(t))
From str method of Test: a is 123, b is 456

หากไม่มี__str__การกำหนดวิธีการprint(t)(หรือprint(str(t))) จะใช้ผลลัพธ์__repr__แทน

หากไม่มี__repr__การกำหนดเมธอดจะใช้ค่าเริ่มต้นซึ่งเทียบเท่ากับ ..

def __repr__(self):
    return "<%s instance at %s>" % (self.__class__.__name__, id(self))

+1 แต่รหัสชั้นเรียนของคุณ__str__แตกต่างจากผลลัพธ์ของเปลือกโต้ตอบที่คุณให้ : P
Chris Lutz

1
เอ่อโอ๊ะโอ .. การแก้ไขเอาต์พุต REPL แบบแมนวลไม่สิ้นสุด ฉันควรจะประกาศข้อความของฉัน: P
dbr

1
การ%จัดรูปแบบสตริงไม่ได้ถูกคัดค้านจากdocs.python.org/whatsnew/2.6.html "ตัวดำเนินการ% ถูกเสริมด้วยวิธีการจัดรูปแบบสตริงที่มีประสิทธิภาพยิ่งขึ้นรูปแบบ ()"
dbr

4
Dbr: นั่นเป็นเรื่องจริง อย่าลืมว่า "มีอะไรใหม่ใน Python 3.0" doc ยังระบุว่า "format () วิธีการ [... ] แผนจะทำให้ API นี้เป็น API สำหรับการจัดรูปแบบสตริงในที่สุดและเพื่อเริ่มลดการดำเนินการ% ใน Python 3.1"
Ashwin Nanjappa

1
พิตตี้%สะดวกมาก
Janusz Lenar

52

วิธีทั่วไปที่สามารถนำไปใช้กับคลาสใดก็ได้โดยไม่มีการจัดรูปแบบเฉพาะสามารถทำได้ดังนี้:

class Element:
    def __init__(self, name, symbol, number):
        self.name = name
        self.symbol = symbol
        self.number = number

    def __str__(self):
        return str(self.__class__) + ": " + str(self.__dict__)

จากนั้น

elem = Element('my_name', 'some_symbol', 3)
print(elem)

ผลิต

__main__.Element: {'symbol': 'some_symbol', 'name': 'my_name', 'number': 3}

23

หากคุณอยู่ในสถานการณ์เช่น@Keithคุณสามารถลอง:

print a.__dict__

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


คุณจะรู้ได้อย่างไรว่าคีย์ dict มีวัตถุในค่าหรือไม่
pranaygoyal02

1
@HadoopEvangelist คุณกำลังถามถึงวิธีการพิมพ์วัตถุเหล่านั้นซ้ำ ๆ ด้วยหรือไม่หรือดูว่ามีวัตถุหรือไม่
จอห์น

13

เพียงเพิ่มสองเซนต์ของฉันไปที่คำตอบของ @ dbr ต่อไปนี้เป็นตัวอย่างของวิธีการใช้ประโยคนี้จากเอกสารอย่างเป็นทางการที่เขาอ้างถึง:

"[... ] เพื่อส่งคืนสตริงที่จะให้ผลลัพธ์วัตถุที่มีค่าเดียวกันเมื่อส่งผ่านไปยัง eval (), [... ]"

ให้นิยามคลาสนี้:

class Test(object):
    def __init__(self, a, b):
        self._a = a
        self._b = b

    def __str__(self):
        return "An instance of class Test with state: a=%s b=%s" % (self._a, self._b)

    def __repr__(self):
        return 'Test("%s","%s")' % (self._a, self._b)

ตอนนี้เป็นเรื่องง่ายที่จะทำให้เป็นอินสแตนซ์ของTestคลาส:

x = Test('hello', 'world')
print 'Human readable: ', str(x)
print 'Object representation: ', repr(x)
print

y = eval(repr(x))
print 'Human readable: ', str(y)
print 'Object representation: ', repr(y)
print

ดังนั้นเมื่อรันโค้ดชิ้นสุดท้ายเราจะได้รับ:

Human readable:  An instance of class Test with state: a=hello b=world
Object representation:  Test("hello","world")

Human readable:  An instance of class Test with state: a=hello b=world
Object representation:  Test("hello","world")

แต่อย่างที่ฉันพูดในความคิดเห็นล่าสุดของฉัน: ข้อมูลเพิ่มเติมอยู่ที่นี่ !


12

__repr__คุณจำเป็นต้องใช้ __init__นี้เป็นฟังก์ชั่นมาตรฐานเช่น ตัวอย่างเช่น:

class Foobar():
    """This will create Foobar type object."""

    def __init__(self):
        print "Foobar object is created."

    def __repr__(self):
        return "Type what do you want to see here."

a = Foobar()

print a

2
reprและstrมี semantics ที่แตกต่างกัน: reprควรเป็นแหล่ง Python ที่ (อีกครั้ง) จะสร้างวัตถุเดียวกัน - นี่คือการนำเสนอของreprในโค้ด strควรเป็นสตริงของวัตถุที่น่าสนใจ
Eric Towers

12

รุ่นที่ตอบสนองดีขึ้นโดย @ user394430

class Element:
    def __init__(self, name, symbol, number):
        self.name = name
        self.symbol = symbol
        self.number = number

    def __str__(self):
        return  str(self.__class__) + '\n'+ '\n'.join(('{} = {}'.format(item, self.__dict__[item]) for item in self.__dict__))

elem = Element('my_name', 'some_symbol', 3)
print(elem)

สร้างรายการชื่อและค่าที่ดีทางสายตา

<class '__main__.Element'>
name = my_name
symbol = some_symbol
number = 3

รุ่นที่ยิ่งนัก (ขอบคุณ Ruud) จัดเรียงรายการ:

def __str__(self):
    return  str(self.__class__) + '\n' + '\n'.join((str(item) + ' = ' + str(self.__dict__[item]) for item in sorted(self.__dict__)))

8

สำหรับ Python 3:

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

แรงบันดาลใจจากคำตอบนี้

class Printable:
    def __repr__(self):
        from pprint import pformat
        return "<" + type(self).__name__ + "> " + pformat(vars(self), indent=4, width=1)

# Example Usage
class MyClass(Printable):
    pass

my_obj = MyClass()
my_obj.msg = "Hello"
my_obj.number = "46"
print(my_obj)

1

มีคำตอบมากมายในหัวข้อนี้ แต่ไม่มีคำตอบใดที่ช่วยฉันได้ฉันต้องทำงานด้วยตัวเองดังนั้นฉันหวังว่าอันนี้จะให้ข้อมูลมากกว่านี้เล็กน้อย

คุณเพียงแค่ต้องให้แน่ใจว่าคุณมีวงเล็บในตอนท้ายของชั้นเรียนของคุณเช่น:

print(class())

นี่คือตัวอย่างของรหัสจากโครงการที่ฉันทำงาน:

class Element:
    def __init__(self, name, symbol, number):
        self.name = name
        self.symbol = symbol
        self.number = number
    def __str__(self):
        return "{}: {}\nAtomic Number: {}\n".format(self.name, self.symbol, self.number

class Hydrogen(Element):
    def __init__(self):
        super().__init__(name = "Hydrogen", symbol = "H", number = "1")

ในการพิมพ์ชั้นไฮโดรเจนของฉันฉันใช้สิ่งต่อไปนี้:

print(Hydrogen())

โปรดทราบว่านี่จะไม่ทำงานหากไม่มีวงเล็บในตอนท้ายของไฮโดรเจน พวกเขามีความจำเป็น

หวังว่านี่จะช่วยได้โปรดแจ้งให้เราทราบหากคุณมีคำถามอีกต่อไป

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