Python __str__ và danh sách


107

Trong Java, nếu tôi gọi List.toString (), nó sẽ tự động gọi phương thức toString () trên mỗi đối tượng bên trong Danh sách. Ví dụ: nếu danh sách của tôi chứa các đối tượng o1, o2 và o3, list.toString () sẽ trông giống như sau:

"[" + o1.toString() + ", " + o2.toString() + ", " + o3.toString() + "]"

Có cách nào để có được hành vi tương tự trong Python không? Tôi đã triển khai phương thức __str __ () trong lớp của mình, nhưng khi tôi in ra danh sách các đối tượng, sử dụng:

print 'my list is %s'%(list)

nó trông giống như thế này:

[<__main__.cell instance at 0x2a955e95f0>, <__main__.cell instance at 0x2a955e9638>, <__main__.cell instance at 0x2a955e9680>]

làm cách nào để python tự động gọi __str__ của tôi cho từng phần tử bên trong danh sách (hoặc dict cho vấn đề đó)?


Chỉ để tham khảo, có PEP 3140: "str (container) nên gọi str (item), không phải repr (item)" , đã bị từ chối.
Alexey

Câu trả lời:


133

Gọi chuỗi trên danh sách python gọi __repr__phương thức trên mỗi phần tử bên trong. Đối với một số mặt hàng, __str____repr__đều giống nhau. Nếu bạn muốn hành vi đó, hãy làm:

def __str__(self):
    ...
def __repr__(self):
    return self.__str__()

7
Việc xác định __str__với __repr__thường không đồng ý với mô hình dữ liệu Python , vì vậy giải pháp hiểu danh sách do @ daniel-lew đề xuất là khó hiểu hơn.
Ioannis Filippidis

2
Không tranh luận. Tôi đã trả lời câu hỏi như được hỏi, đây thường là cách một người mới làm quen với python muốn nghĩ về vấn đề này, nhưng điều đó không có nghĩa đó là cách tốt nhất để trả lời.
David Berger

1
Python phải nhất quán với mô hình dữ liệu của riêng nó và làm điều tương tự cho tất cả các nguyên thủy và tổng hợp.
Terrence Brannon

2
Tôi nghĩ rằng hành vi mặc định cho danh sách python rõ ràng là sai. Tôi mong đợi điều đó str()trên một danh sách được trả về str()cho từng phần tử riêng lẻ bên trong.
SuperGeo

21

Bạn có thể sử dụng khả năng hiểu danh sách để tạo một danh sách mới với mỗi mục str () 'd một cách tự động:

print([str(item) for item in mylist])

6
Hoặc chỉ print(map(str, mylist))- nó ngắn hơn một chút
anula

4
Một vấn đề với điều này là nếu mục trong mylist cũng có thể là một danh sách
Breandán Dalton

7

Hai điều dễ dàng bạn có thể làm, sử dụng mapchức năng hoặc sử dụng một cách hiểu.

Nhưng điều đó giúp bạn có một danh sách các chuỗi, không phải một chuỗi. Vì vậy, bạn cũng phải nối các chuỗi lại với nhau.

s= ",".join( map( str, myList ) )

hoặc là

s= ",".join( [ str(element) for element in myList ] )

Sau đó, bạn có thể in đối tượng chuỗi tổng hợp này.

print 'my list is %s'%( s )

4

Tùy thuộc vào những gì bạn muốn sử dụng đầu ra đó, có lẽ __repr__có thể thích hợp hơn:

import unittest

class A(object):
    def __init__(self, val):
        self.val = val

    def __repr__(self):
        return repr(self.val)

class Test(unittest.TestCase):
    def testMain(self):
        l = [A('a'), A('b')]
        self.assertEqual(repr(l), "['a', 'b']")

if __name__ == '__main__':
    unittest.main()

3

Tôi đồng ý với câu trả lời trước đó về việc sử dụng khả năng hiểu danh sách để làm điều này, nhưng bạn chắc chắn có thể ẩn điều đó đằng sau một hàm, nếu đó là thứ làm nổi con thuyền của bạn.

def is_list(value):
    if type(value) in (list, tuple): return True
    return False

def list_str(value):
    if not is_list(value): return str(value)
    return [list_str(v) for v in value]

Chỉ cho vui thôi, tôi tạo list_str () đệ quy str () mọi thứ có trong danh sách.


1 này rất hữu ích khi triển khai __str____repr__riêng biệt
vincent Gravitas


0

Điều này là đủ.

Khi in danh sách cũng như các lớp vùng chứa khác, các phần tử được chứa sẽ được in bằng cách sử dụng __repr__, vì __repr__nó được dùng để biểu diễn đối tượng bên trong. Nếu chúng tôi gọi: help(object.__repr__)nó sẽ cho chúng tôi biết:

Help on wrapper_descriptor:

__repr__(self, /)
    Return repr(self).

Và nếu chúng ta gọi help(repr)nó sẽ xuất ra:

Help on built-in function repr in module builtins:

repr(obj, /)
    Return the canonical string representation of the object.

    For many object types, including most builtins, eval(repr(obj)) == obj.

Nếu __str__được triển khai cho một đối tượng và __repr__không được triển khai repr(obj)sẽ xuất ra đầu ra mặc định, giống như print(obj)khi các đối tượng không được thực thi.

Vì vậy, cách duy nhất là thực hiện __repr__cho lớp của bạn. Một cách có thể để làm điều đó là:

class C:           
    def __str__(self):
        return str(f"{self.__class__.__name__} class str ")

C.__repr__=C.__str__       
ci = C()    


print(ci)       #C class str 
print(str(ci))  #C class str 
print(repr(ci)) #C class str 

-3

Đầu ra bạn nhận được chỉ là tên mô-đun, tên lớp của đối tượng và sau đó là địa chỉ bộ nhớ ở dạng thập lục phân vì __repr__hàm không bị ghi đè.

__str__được sử dụng để biểu diễn chuỗi của một đối tượng khi sử dụng print. Nhưng vì bạn đang in danh sách các đối tượng và không lặp lại danh sách để gọi strphương thức cho từng mục, nó sẽ in ra biểu diễn đối tượng.

Để __str__gọi hàm, bạn cần phải làm như sau:

'my list is %s' % [str(x) for x in myList]

Nếu bạn ghi đè __repr__hàm, bạn có thể sử dụng phương thức in như trước đây:

class cell:
    def __init__(self, id):
        self.id = id
    def __str__(self):
        return str(self.id) # Or whatever
    def __repr__(self):
        return str(self) # function invoked when you try and print the whole list.

myList = [cell(1), cell(2), cell(3)]
'my list is %s' % myList

Sau đó, bạn sẽ nhận được " my list is [1, 2, 3]" làm đầu ra của mình.


Câu trả lời này dường như đang trả lời một câu hỏi hoàn toàn không liên quan. Bạn có chắc rằng bạn đã đặt nó vào đúng vị trí?
Blckknght

vâng Blckknght trang này mà tôi muốn đưa ra câu trả lời của mình có một liên kết đến trang này từ một bài đăng khác. vì vậy nó đã hướng dẫn tôi ở đây và tôi trả lời ở đây, giả sử rằng người đặt câu hỏi sẽ lại đây và xem câu trả lời của tôi..xin lỗi vì sự bất khả tư nghị !!!
panagiwtis koligas

Nếu câu hỏi kia được đóng lại là một bản sao của câu hỏi này, thì có thể giả định rằng các câu trả lời hiện có ở đây nên đã giải quyết cho câu hỏi kia. Nếu không đúng như vậy, thì bạn nên gắn cờ để mở lại câu hỏi đó, thay vì đăng một câu trả lời khó hiểu ở đây, câu trả lời đó gần như chắc chắn sẽ bị xóa. Bây giờ, có thể bạn có điều gì đó để nói mà một trong 8 câu trả lời khác ở đây không đề cập đến, nhưng bạn cần phải làm cho câu trả lời của mình có ý nghĩa trong ngữ cảnh của trang này, vì đây là câu hỏi bạn đang trả lời. Và đừng đăng hai câu trả lời giống nhau!
Blckknght

1
Ồ, mặc dù bây giờ tôi nhìn lại nó, có vẻ như @charliebeckwith đã chỉnh sửa bài đăng của bạn thành một bài hoàn toàn khác, thay vì đăng câu trả lời của riêng họ, vì một số lý do không thể giải thích được. Đó không phải là bình thường như thế nào chỉnh sửa công việc ...
Blckknght

@blckknght Tôi đã bắt đầu chỉnh sửa nó trước khi tôi nhận ra câu trả lời sai như thế nào. Hoàn toàn không thể giải thích tại sao tôi tiếp tục đi.
charliebeckwith
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.