Làm thế nào để tạo một biểu diễn chuỗi tùy chỉnh cho một đối tượng lớp?


202

Hãy xem xét lớp này:

class foo(object):
    pass

Biểu diễn chuỗi mặc định trông giống như thế này:

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

Làm thế nào tôi có thể làm cho màn hình này hiển thị một chuỗi tùy chỉnh?

Câu trả lời:


272

Thực hiện __str__()hoặc __repr__()trong siêu dữ liệu của lớp.

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

class C(object):
  __metaclass__ = MC

print C

Sử dụng __str__nếu bạn có nghĩa là một chuỗi sắp xếp có thể đọc được, sử dụng __repr__cho các biểu diễn rõ ràng.


2
Tôi muốn tạo một số loại trang trí lớp, vì vậy tôi có thể dễ dàng thiết lập các biểu diễn chuỗi tùy chỉnh cho các lớp của mình mà không phải viết siêu dữ liệu cho mỗi lớp. Tôi không rành lắm về siêu dữ liệu của Python, vậy bạn có thể cho tôi bất kỳ gợi ý nào ở đó không?
Bjorn Pollex

Thật không may, điều này không thể được thực hiện với các nhà trang trí lớp; nó phải được đặt khi lớp được định nghĩa.
Ignacio Vazquez-Abrams

10
@ Space_C0wb0y: Bạn có thể thêm một chuỗi như _representationvào thân lớp và return self._representationtrong __repr__()phương thức của siêu dữ liệu.
Sven Marnach

@ BjornPollex Bạn có thể sử dụng công cụ trang trí này, nhưng tôi hy vọng bạn phải vật lộn với rất nhiều sự tinh tế của ngôn ngữ. Và ngay cả khi bạn vẫn bị ràng buộc sử dụng siêu dữ liệu theo cách này hay cách khác vì bạn không muốn sử dụng mặc định __repr__để đại diện C. Một cách khác để có một _representationthành viên là tạo ra một nhà máy siêu dữ liệu sản xuất một siêu dữ liệu phù hợp __repr__(điều này có thể tốt nếu bạn sử dụng nhiều thứ này).
skyking


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

10
Điều này thay đổi biểu diễn chuỗi cho instanceslớp, không phải cho chính lớp đó.
tauran

xin lỗi, không thấy phần thứ hai của bài viết của bạn Sử dụng phương pháp trên.
Andrey Gubarev

6
@RobertSiemer Tại sao? Mặc dù câu trả lời của anh ấy không nhắm mục tiêu cụ thể vào câu hỏi của OP, nhưng nó vẫn hữu ích. Nó đã giúp đỡ tôi. Và trong nháy mắt, tôi không thấy bất kỳ câu hỏi yêu cầu thực hiện ví dụ. Vì vậy, có lẽ mọi người hạ cánh trên trang này đầu tiên.
akinuri

14

Nếu bạn phải chọn giữa __repr__hoặc __str__chọn cái đầu tiên, như mặc định sẽ thực hiện __str__các cuộc gọi __repr__khi nó không được xác định.

Ví dụ về Vector3 tùy chỉnh:

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)

Trong ví dụ này, reprtrả về một chuỗi có thể được tiêu thụ / thực thi trực tiếp, trong khi đó lại strhữu ích hơn như một đầu ra gỡ lỗi.

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

1
Mặc dù quan điểm của bạn về __repr__vs __str__là đúng, nhưng điều này không trả lời câu hỏi thực tế, đó là về các đối tượng lớp, không phải các trường hợp.
Bjorn Pollex

Cảm ơn các phản hồi, hoàn toàn giám sát điều đó. Hãy để tôi xem lại câu trả lời của tôi.
dùng1767754

Tôi nghĩ rằng bạn thực hiện cho repr và str được hoán đổi.
jspencer

4

Câu trả lời được chấp thuận của Ignacio Vazquez-Abrams là hoàn toàn đúng. Tuy nhiên, đó là từ thế hệ Python 2. Một bản cập nhật cho Python 3 hiện tại sẽ là:

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

class C(object, metaclass=MC):
    pass

print(C)

Nếu bạn muốn mã chạy trên cả Python 2 và Python 3, mô-đun sáu đã bảo vệ bạn:

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)

Cuối cùng, nếu bạn có một lớp mà bạn muốn có một repr tĩnh tùy chỉnh, cách tiếp cận dựa trên lớp ở trên hoạt động rất tốt. Nhưng nếu bạn có một số, bạn sẽ phải tạo ra một siêu dữ liệu tương tự MCcho từng loại và điều đó có thể gây mệt mỏi. Trong trường hợp đó, việc lập trình siêu dữ liệu của bạn tiến thêm một bước và tạo một nhà máy siêu dữ liệu giúp mọi thứ sạch sẽ hơn một chút:

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)

in:

Wahaha! Booyah! Gotcha!

Metaprogramming không phải là thứ bạn thường cần hàng ngày nhưng khi bạn cần nó, nó thực sự đạt đến vị trí!


0

Chỉ cần thêm vào tất cả các câu trả lời tốt, phiên bản của tôi với trang trí:

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)

xuất sắc:

Wahaha!

Mặt trái:

  1. Bạn không thể khai báo Cmà không có siêu hạng (không class C:)
  2. Ccác trường hợp sẽ là các trường hợp của một số dẫn xuất lạ, vì vậy có lẽ cũng nên thêm một __repr__ví dụ.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.