2012-07-03 36 views
9

Tôi đã được hiểu rằng gọi số print obj sẽ gọi obj.__str__() để lần lượt trả về một chuỗi để in trên bảng điều khiển. Bây giờ tôi gặp vấn đề với Unicode, nơi tôi không thể in bất kỳ ký tự không phải ascii nào. Tôi nhận được công cụ "ascii ngoài phạm vi" điển hình.Sự khác biệt về Python giữa obj in và in obj .__ str __() [ít nhất với Unicode?]

Trong khi thực hiện thí điểm làm việc sau đây:

print obj.__str__() 
print obj.__repr__() 

Với cả hai chức năng làm giống hệt nhau (__str__() chỉ trả self.__repr__()). Những gì không hoạt động:

print obj 

Sự cố chỉ xảy ra khi sử dụng ký tự trong phạm vi ascii. Giải pháp cuối cùng là để sau đây trong __str__():

return self.__repr__().encode(sys.stdout.encoding) 

Bây giờ nó hoạt động cho tất cả các bộ phận. Câu hỏi của tôi bây giờ là: Sự khác biệt ở đâu? Tại sao nó hoạt động ngay bây giờ? Tôi nhận được nếu không có gì làm việc, tại sao điều này hoạt động ngay bây giờ. Nhưng tại sao chỉ phần trên cùng hoạt động, chứ không phải phần dưới cùng.

Hệ điều hành là Windows 7 x64 với dấu nhắc lệnh Windows mặc định. Mã hóa cũng được báo cáo là cp850. Đây là một câu hỏi chung để hiểu python. Vấn đề của tôi đã được giải quyết, nhưng tôi không hạnh phúc 100%, chủ yếu là vì bây giờ gọi str(obj) sẽ mang lại một chuỗi không được mã hóa theo cách tôi muốn.

# -*- coding: utf-8 -*- 
class Sample(object): 

    def __init__(self): 
     self.name = u"üé" 

    def __repr__(self): 
     return self.name 

    def __str__(self): 
     return self.name 

obj = Sample() 
print obj.__str__(), obj.__repr__(), obj 

Xóa cuối cùng obj và hoạt động. Giữ nó và nó bị treo với

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128) 
+0

gì Python phiên bản là bạn đang chạy? –

+0

Hiển thị ví dụ tối thiểu về lớp của obj với các mẫu của chuỗi bạn in. –

+2

Bạn có thể tìm kiếm 'obj .__ unicode __()'? –

Trả lời

4

đoán của tôi là in làm điều gì đó như sau cho một đối tượng obj nó có nghĩa là in:

  1. Kiểm tra xem obj có phải là unicode không. Nếu vậy, hãy mã hóa nó thành sys.stdout.encoding và in.
  2. Kiểm tra xem obj có phải là str không. Nếu vậy, hãy in trực tiếp.
  3. Nếu obj là bất kỳ điều gì khác, hãy gọi str(obj) và in điều đó.

Bước 1 là lý do tại sao print obj.__str__() hoạt động trong trường hợp của bạn.

Bây giờ, những gì str(obj) làm là:

  1. Gọi obj.__str__().
  2. Nếu kết quả là một str, trả lại
  3. Nếu kết quả là một unicode, mã hóa nó để "ascii" và trở về mà
  4. Nếu không, một cái gì đó hầu như vô dụng.

Gọi điện trực tiếp bỏ qua bước 2-3, đó là lý do bạn không nhận được lỗi mã hóa.

Sự cố không phải do cách hoạt động của print, do cách hoạt động của str(). str() bỏ qua sys.stdout.encoding. Vì nó không biết bạn muốn làm gì với chuỗi kết quả, mã hóa mặc định nó sử dụng có thể được coi là tùy ý; ascii là lựa chọn tốt hay xấu.

Để ngăn chặn lỗi này, hãy đảm bảo bạn trả lại str từ __str__() khi tài liệu hướng dẫn bạn thực hiện. Một mô hình bạn có thể sử dụng cho Python 2.x có thể là:

class Foo(): 
    def __unicode__(self): 
     return u'whatever' 
    def __str__(self): 
     return unicode(self).encode(sys.stdout.encoding) 

(Nếu bạn chắc chắn bạn không cần str() đại diện cho bất cứ điều gì nhưng in ra cửa sổ Console.)

+0

Cảm ơn bạn đó là lời giải thích hoàn hảo mà tôi đang tìm kiếm. Điều này chắc chắn giải thích vấn đề của tôi. Bây giờ những gì nếu tôi * làm * muốn có nhiều hơn chỉ là đầu ra giao diện điều khiển. Điều gì sẽ là một giải pháp tốt? Cách tiếp cận của tôi là xác định tham số thứ hai như sau: '__str __ (self, encoding = sys.stdout.encoding)'. Điều này có vẻ như là một ý tưởng hay không? – javex

+1

@ user1461135 Không thực sự là một tình huống mà bạn sẽ vượt qua các tham số thêm vào '__str __()', nhìn thấy như bạn không có nghĩa là để gọi nó trực tiếp. Tôi chỉ sử dụng 'unicode (obj) .encode ('yadda')' bất cứ nơi nào bạn muốn gọi 'obj .__ str __ (encoding = 'yadda')', nó ít có khả năng gây bất ngờ cho mọi người. – millimoose

+0

Cảm ơn bạn ** rất nhiều **! – javex

1

Thứ nhất, nếu bạn nhìn vào the online documentation, __str____repr__ có mục đích khác nhau và nên tạo đầu ra khác nhau. Vì vậy, gọi số __repr__ từ __str__ không phải là giải pháp tốt nhất.

Thứ hai, print sẽ gọi __str__ và sẽ không mong đợi nhận các ký tự không phải ascii, vì, tốt, print không thể đoán cách chuyển đổi ký tự không phải ascii.

Cuối cùng, trong các phiên bản gần đây của Python 2.x, __unicode__ là phương pháp ưu tiên tạo biểu diễn chuỗi cho một đối tượng. Có một lời giải thích thú vị trong Python str versus unicode.

Vì vậy, để cố gắng và thực sự trả lời câu hỏi, bạn có thể làm một cái gì đó như:

class Sample(object): 

    def __init__(self): 
     self.name = u"\xfc\xe9" 

    # No need to implement __repr__. Let Python create the object repr for you 

    def __str__(self): 
     return unicode(self).encode('utf-8') 

    def __unicode__(self): 
     return self.name 
+1

Về mặt kỹ thuật, trong các phiên bản gần đây của Python (3.x), sự khác biệt không tồn tại nữa. – millimoose

+0

@millimoose Bạn nói đúng. Tôi đang xem xét Python 2.6+ – Rodrigue

+0

'__unicode__' thực sự có thể còn lớn hơn 2.6 – Rodrigue

Các vấn đề liên quan