วิธีการสร้างการแสดงสตริงที่กำหนดเองสำหรับวัตถุคลาส?


202

พิจารณาคลาสนี้:

class foo(object):
    pass

การแทนค่าสตริงเริ่มต้นมีลักษณะดังนี้:

>>> str(foo)
"<class '__main__.foo'>"

ฉันจะทำให้สตริงนี้แสดงเป็นสตริงที่กำหนดเองได้อย่างไร

คำตอบ:


272

นำไปใช้__str__()หรือ__repr__()ใน metaclass ของคลาส

class MC(type):
  def __repr__(self):
    return 'Wahaha!'

class C(object):
  __metaclass__ = MC

print C

ใช้__str__ถ้าคุณหมายถึงการทำให้เป็นสตริงที่อ่านได้ใช้__repr__สำหรับการรับรองที่ชัดเจน


2
ฉันต้องการสร้างมัณฑนากรชั้นเรียนบางประเภทดังนั้นฉันสามารถตั้งค่าการนำเสนอสตริงแบบกำหนดเองสำหรับชั้นเรียนของฉันได้อย่างง่ายดายโดยไม่ต้องเขียน metaclass สำหรับแต่ละคน ฉันไม่คุ้นเคยกับ metaclasses ของ Python ดังนั้นคุณสามารถให้คำแนะนำกับฉันได้ไหม?
Björn Pollex

น่าเสียดายที่สิ่งนี้ไม่สามารถทำได้กับผู้ตกแต่งชั้นเรียน จะต้องตั้งค่าเมื่อมีการกำหนดชั้นเรียน
Ignacio Vazquez-Abrams

10
@ Space_C0wb0y: คุณสามารถเพิ่มสตริงที่ชอบ_representationให้กับคลาสของร่างกายและreturn self._representationใน__repr__()เมธอดของ metaclass
Sven Marnach

@ BjörnPollexคุณอาจจะดึงสิ่งนี้ด้วยมัณฑนากร แต่ฉันคาดว่าคุณจะต้องต่อสู้กับภาษาย่อย ๆ ของภาษา และแม้ว่าคุณจะทำคุณยังคงผูกพันกับการใช้ metaclass ในหรืออีกวิธีหนึ่งเพราะคุณไม่ต้องการที่จะใช้ค่าเริ่มต้นที่จะเป็นตัวแทน__repr__ Cอีกทางเลือกหนึ่งในการมี_representationสมาชิกคือการสร้างโรงงาน metaclass ที่ผลิต metaclass ที่เหมาะสม__repr__(ซึ่งอาจจะดีถ้าคุณใช้สิ่งนี้มาก)
skyking


22
class foo(object):
    def __str__(self):
        return "representation"
    def __unicode__(self):
        return u"representation"

10
สิ่งนี้เปลี่ยนการแสดงสตริงสำหรับinstancesคลาสไม่ใช่สำหรับคลาสเอง
tauran

ขออภัยไม่เห็นส่วนที่สองของโพสต์ของคุณ ใช้วิธีการด้านบน
Andrey Gubarev

6
@RobertSiemer ทำไม แม้ว่าคำตอบของเขาจะไม่เจาะจงไปที่คำถามของ OP แต่ก็ยังมีประโยชน์ มันช่วยฉัน และอย่างรวดเร็วฉันไม่เห็นคำถามใด ๆ สำหรับการใช้งานอินสแตนซ์ ดังนั้นผู้คนอาจมาที่หน้านี้ก่อน
akinuri

14

หากคุณต้องเลือกระหว่าง__repr__หรือ__str__ไปหาคนแรกเช่นโดยการเริ่มต้นใช้งาน__str__สาย__repr__เมื่อมันไม่ได้กำหนด

ตัวอย่าง Vector3 ที่กำหนดเอง:

class Vector3(object):
    def __init__(self, args):
        self.x = args[0]
        self.y = args[1]
        self.z = args[2]

    def __repr__(self):
        return "Vector3([{0},{1},{2}])".format(self.x, self.y, self.z)

    def __str__(self):
        return "x: {0}, y: {1}, z: {2}".format(self.x, self.y, self.z)

ในตัวอย่างนี้reprส่งคืนสตริงที่สามารถใช้ / เรียกใช้โดยตรงอีกครั้งในขณะที่strมีประโยชน์มากกว่าเป็นเอาต์พุตดีบัก

v = Vector3([1,2,3])
print repr(v)    #Vector3([1,2,3])
print str(v)     #x:1, y:2, z:3

1
ในขณะที่ประเด็นเกี่ยวกับ__repr__vs ของคุณ__str__ถูกต้องสิ่งนี้จะไม่ตอบคำถามจริงซึ่งเกี่ยวกับคลาสของออบเจ็กต์ไม่ใช่อินสแตนซ์
Björn Pollex

ขอบคุณสำหรับคำติชมดูแลอย่างสมบูรณ์ ให้ฉันตรวจสอบคำตอบของฉัน
1767754

ฉันคิดว่าคุณใช้งานสำหรับ repr และ STR ถูกสับเปลี่ยน
jspencer

4

คำตอบที่ได้รับการอนุมัติของ Ignacio Vazquez-Abramsค่อนข้างถูกต้อง อย่างไรก็ตามมันมาจาก Python 2 generation การอัปเดตสำหรับ Python 3 ในปัจจุบันจะเป็น:

class MC(type):
  def __repr__(self):
    return 'Wahaha!'

class C(object, metaclass=MC):
    pass

print(C)

หากคุณต้องการโค้ดที่ทำงานได้ทั้ง Python 2 และ Python 3 โมดูลทั้งหกนี้ครอบคลุม:

from __future__ import print_function
from six import with_metaclass

class MC(type):
  def __repr__(self):
    return 'Wahaha!'

class C(with_metaclass(MC)):
    pass

print(C)

ท้ายที่สุดถ้าคุณมีคลาสหนึ่งที่คุณต้องการให้มีการพิมพ์สแตติกแบบกำหนดเองวิธีการตามคลาสที่ใช้งานได้ดี แต่ถ้าคุณมีหลาย ๆ อันคุณต้องสร้างเมตากลาสคล้าย ๆ กันMCและนั่นอาจทำให้คุณเบื่อหน่าย ในกรณีดังกล่าวการใช้โปรแกรมเมตาโปรแกรมของคุณอีกขั้นหนึ่งและสร้างโรงงาน metaclass ทำให้สิ่งต่าง ๆ สะอาดขึ้น:

from __future__ import print_function
from six import with_metaclass

def custom_class_repr(name):
    """
    Factory that returns custom metaclass with a class ``__repr__`` that
    returns ``name``.
    """
    return type('whatever', (type,), {'__repr__': lambda self: name})

class C(with_metaclass(custom_class_repr('Wahaha!'))): pass

class D(with_metaclass(custom_class_repr('Booyah!'))): pass

class E(with_metaclass(custom_class_repr('Gotcha!'))): pass

print(C, D, E)

พิมพ์:

Wahaha! Booyah! Gotcha!

Metaprogramming ไม่ใช่สิ่งที่คุณต้องการโดยทั่วไปทุกวัน แต่เมื่อคุณต้องการมันเป็นจุดที่ยอดเยี่ยมจริงๆ!


0

เพียงเพิ่มคำตอบที่ดีทั้งหมดเวอร์ชันของฉันพร้อมการตกแต่ง:

from __future__ import print_function
import six

def classrep(rep):
    def decorate(cls):
        class RepMetaclass(type):
            def __repr__(self):
                return rep

        class Decorated(six.with_metaclass(RepMetaclass, cls)):
            pass

        return Decorated
    return decorate


@classrep("Wahaha!")
class C(object):
    pass

print(C)

stdout:

Wahaha!

ด้านลง:

  1. คุณไม่สามารถประกาศได้Cหากไม่มีซูเปอร์คลาส (ไม่class C:)
  2. Cอินสแตนซ์จะเป็นอินสแตนซ์ของความแปลกประหลาดบางอย่างดังนั้นจึงควรเพิ่ม__repr__อินสแตนซ์สำหรับอินสแตนซ์ด้วย
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.