พิจารณาคลาสนี้:
class foo(object):
pass
การแทนค่าสตริงเริ่มต้นมีลักษณะดังนี้:
>>> str(foo)
"<class '__main__.foo'>"
ฉันจะทำให้สตริงนี้แสดงเป็นสตริงที่กำหนดเองได้อย่างไร
พิจารณาคลาสนี้:
class foo(object):
pass
การแทนค่าสตริงเริ่มต้นมีลักษณะดังนี้:
>>> str(foo)
"<class '__main__.foo'>"
ฉันจะทำให้สตริงนี้แสดงเป็นสตริงที่กำหนดเองได้อย่างไร
คำตอบ:
นำไปใช้__str__()
หรือ__repr__()
ใน metaclass ของคลาส
class MC(type):
def __repr__(self):
return 'Wahaha!'
class C(object):
__metaclass__ = MC
print C
ใช้__str__
ถ้าคุณหมายถึงการทำให้เป็นสตริงที่อ่านได้ใช้__repr__
สำหรับการรับรองที่ชัดเจน
_representation
ให้กับคลาสของร่างกายและreturn self._representation
ใน__repr__()
เมธอดของ metaclass
__repr__
C
อีกทางเลือกหนึ่งในการมี_representation
สมาชิกคือการสร้างโรงงาน metaclass ที่ผลิต metaclass ที่เหมาะสม__repr__
(ซึ่งอาจจะดีถ้าคุณใช้สิ่งนี้มาก)
class foo(object):
def __str__(self):
return "representation"
def __unicode__(self):
return u"representation"
instances
คลาสไม่ใช่สำหรับคลาสเอง
หากคุณต้องเลือกระหว่าง__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
__repr__
vs ของคุณ__str__
ถูกต้องสิ่งนี้จะไม่ตอบคำถามจริงซึ่งเกี่ยวกับคลาสของออบเจ็กต์ไม่ใช่อินสแตนซ์
คำตอบที่ได้รับการอนุมัติของ 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 ไม่ใช่สิ่งที่คุณต้องการโดยทั่วไปทุกวัน แต่เมื่อคุณต้องการมันเป็นจุดที่ยอดเยี่ยมจริงๆ!
เพียงเพิ่มคำตอบที่ดีทั้งหมดเวอร์ชันของฉันพร้อมการตกแต่ง:
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!
ด้านลง:
C
หากไม่มีซูเปอร์คลาส (ไม่class C:
)C
อินสแตนซ์จะเป็นอินสแตนซ์ของความแปลกประหลาดบางอย่างดังนั้นจึงควรเพิ่ม__repr__
อินสแตนซ์สำหรับอินสแตนซ์ด้วย