2010-02-22 44 views
13

Điều gì có thể tạo ra hành vi sau đây?nội suy chuỗi python

>>> print str(msg) 
my message 
>>> print unicode(msg) 
my message 

Nhưng:

>>> print '%s' % msg 
another message 

Thông tin thêm:

  • đối tượng msg tôi được thừa hưởng từ unicode.
  • các phương pháp __str__/__unicode__/__repr__ phương pháp được ghi đè để trả lại chuỗi 'my message'.
  • đối tượng msg được khởi tạo bằng chuỗi 'another message'.
  • này đang chạy trên python 2.5
  • biến msg đã không thay đổi giữa các bài kiểm tra
  • này thực sự là doctest thực sự mà thực sự là cho những kết quả này.

Tôi muốn một giải pháp phù hợp với doctest này, với fuss tối thiểu (đặc biệt là xung quanh thừa kế thực tế):

>>> print '%s' % msg 
my message 

Cảm ơn tất cả lời đề nghị.

Tôi không cảm thấy điều này sẽ giúp nhiều hơn, nhưng đối với độc giả tò mò (và pythonist mạo hiểm), đây là việc thực hiện các đối tượng:

class Message(zope.i18nmessageid.Message): 

    def __repr__(self): 
     return repr(zope.i18n.interpolate(self.default, self.mapping)) 

    def __str__(self): 
     return zope.i18n.interpolate(self.default, self.mapping) 

    def __unicode__(self): 
     return zope.i18n.interpolate(self.default, self.mapping) 

Đây là cách chúng ta tạo ra các đối tượng msg:

>>> msg = Message('another message', 'mydomain', default='my message') 

Zope gói phiên bản và mã được sử dụng là:

EDIT INFO:

  • thêm/cập nhật tên của các phương pháp đã được overriden
  • thêm một số thông tin hơn (phiên bản python, và thông tin nhỏ)
  • cập nhật một số thông tin sai (lớp của `msg` được dựa trên lớp` unicode` chứ không phải `basestring`)
  • thêm cài đặt thực tế ion của lớp sử dụng
+3

@extraneon: đó là python 2 .x: 'print' là một câu lệnh, basestring, unicode! – SilentGhost

+1

thay đổi giá trị của biến 'msg' giữa' print' s sẽ giải thích nó – van

+1

Bạn có mã thực sự cho đối tượng đó không? (Hoặc đúng hơn là lớp của nó.) Sẽ hữu ích nếu bạn có thể dán nó vào đây ... –

Trả lời

8

Cập nhật 2: Hãy tìm câu trả lời ban đầu, bao gồm một ví dụ đơn giản của một lớp trưng bày các hành vi được mô tả bởi các OP, bên dưới thanh ngang. Đối với những gì tôi đã có thể phỏng đoán trong quá trình truy vấn của tôi vào các nguồn của Python (v. 2.6.4):

Tệp Include/unicodeobject.h chứa các dòng sau đây (nos.436-7 trong tôi (hơi cũ) thanh toán):

#define PyUnicode_AS_UNICODE(op) \            
     (((PyUnicodeObject *)(op))->str) 

này được sử dụng khắp nơi trên diễn ra trong mã định dạng, trong đó, như xa như tôi có thể nói, có nghĩa là trong khi định dạng chuỗi, bất kỳ đối tượng mà được thừa hưởng từ unicode sẽ được đưa vào để bộ đệm chuỗi unicode của nó có thể được sử dụng trực tiếp, mà không cần gọi bất kỳ phương thức Python nào. Đó là tốt như xa như hiệu suất là có liên quan, tôi chắc chắn (và rất nhiều phù hợp với phỏng đoán của Juergen trong một bình luận về câu trả lời này). Đối với câu hỏi của OP, điều này có thể có nghĩa là làm cho mọi thứ hoạt động theo cách mà OP muốn họ chỉ có thể thực hiện được nếu ý tưởng lớp bọc của Anurag Uniyal được chấp nhận cho trường hợp sử dụng cụ thể này. Nếu nó không phải là, điều duy nhất mà đến với tâm trí của tôi bây giờ là để bọc các đối tượng của lớp này trong str/unicode bất cứ nơi nào chúng được interpolated vào một chuỗi ... ugh. (Tôi chân thành hy vọng Tôi chỉ thiếu một giải pháp sạch hơn mà ai đó sẽ chỉ ra trong một phút!)


(Cập nhật: này đã được đăng khoảng một phút trước khi OP bao gồm mã lớp học của mình, nhưng dù sao tôi cũng để nó ở đây (1) để phỏng đoán/cố gắng ban đầu ở giải thích bên dưới mã, (2) cho một ví dụ đơn giản về cách tạo ra hành vi này (Anurag Uniyal đã cung cấp một số khác gọi hàm tạo của unicode) trực tiếp, trái ngược với thông qua super), (3) với hy vọng sau này có thể chỉnh sửa một cái gì đó để giúp OP có được hành vi mong muốn.)

Dưới đây là một ví dụ về một lớp học mà thực sự hoạt động như những gì OP mô tả (Python 2.6.4, nó tạo ra một cảnh báo deprecation - /usr/bin/ipython:3: DeprecationWarning: object.__init__() takes no parameters):

class Foo(unicode): 
    def __init__(self, msg): 
     super(unicode, self).__init__(msg) 
    def __str__(self): return 'str msg' 
    def __repr__(self): return 'repr msg' 
    def __unicode__(self): return u'unicode msg' 

Một vài tương tác trong IPython:

In [12]: print(Foo("asdf")) 
asdf 

In [13]: str(Foo("asdf")) 
Out[13]: 'str msg' 

In [14]: print str(Foo("asdf")) 
-------> print(str(Foo("asdf"))) 
str msg 

In [15]: print(str(Foo("asdf"))) 
str msg 

In [16]: print('%s' % Foo("asdf")) 
asdf 

Rõ ràng chuỗi nội suy xử lý đối tượng này như là một thể hiện của unicode (trực tiếp gọi unicode thực hiện __str__), trong khi các chức năng khác coi nó như là một thể hiện của Foo. Làm thế nào điều này xảy ra trong nội bộ và tại sao nó hoạt động như thế này và cho dù đó là một lỗi hoặc một tính năng, tôi thực sự không biết.

Còn cách khắc phục đối tượng OP ... Làm sao tôi biết mà không nhìn thấy mã của nó ??? Hãy cho tôi mã và tôi hứa sẽ nghĩ về nó! Ok, tôi đang suy nghĩ về nó ... Không có ý tưởng cho đến nay.

+0

Có vẻ như tôi, vì in đã tạo ra một số phím tắt - để tăng tốc mọi thứ, tôi nghĩ vậy. Python có giao diện bên trong (tương đối nhanh) và giao diện bên ngoài (tương đối chậm). Tôi đoán, rằng ai đó đã cố gắng tránh các chi phí ... – Juergen

+0

@Juergen: Bao gồm một số thông tin về những gì các nguồn trông giống như trong câu trả lời ngay bây giờ ... Nó chắc chắn có vẻ như bạn đang phải. –

+0

@Michal: Cảm ơn bạn đã thông tin! Python là khá sạch sẽ như một hệ thống, nhưng (như tôi hiểu nó và cũng đã thấy một chút) đôi khi một số phím tắt được thực hiện trong nội bộ, nơi một lợi thế tốc độ lớn có thể đạt được. Điều này là ổn trong quan điểm của tôi, vì các phím tắt đó không hiển thị trong 99% của tất cả các trường hợp ... trong 1% khác, một giải pháp phải được thực hiện như trong trường hợp này. Tất nhiên, khi stumpling trên một, nó có thể được khá đáng ngạc nhiên hoặc thậm chí gây phiền nhiễu ... – Juergen

6

Vì vậy, vấn đề là lớp như một cái gì đó dưới hoạt động thật là thú vị

class Msg(unicode): 
    def __init__(self, s): 
     unicode.__init__(self, s) 

    __unicode__ = __repr__ = __str__ = lambda self: "my message" 

msg = Msg("another message") 
print str(msg) 
print unicode(msg) 
print "%s"%msg 

này in

my message 
my message 
another message 

Tôi không chắc chắn lý do tại sao điều này xảy ra hoặc làm thế nào để sửa chữa nó, nhưng là một nỗ lực rất thô bằng cách gói Msg, nhưng không chắc chắn nó sẽ giúp đỡ trong vấn đề của OP

class MsgX(object): 
    def __init__(self, s): 
     self._msg = Msg(s) 

    __unicode__ = __repr__ = __str__ = lambda self: repr(self._msg) 

msg = MsgX("another message") 
print str(msg) 
print unicode(msg) 
print "%s"%msg 

output:

my message 
my message 
my message 
+0

Tôi không thể thay đổi tài sản kế thừa đối với unicode. Tuy nhiên, cảm ơn cho bạn ví dụ đơn giản. – vaab

+0

@vaab: nếu bạn nhìn vào câu trả lời mở rộng mà tôi đưa ra, việc bổ sung '__getattr__' sẽ chuyển tiếp tất cả các trình truy cập * sẽ * đã được giải quyết bằng cách thừa kế thuộc tính .msg chứa. Đây là một thành ngữ rất mạnh mẽ trong Python, và đặt bọc-và-delegate ngang bằng với thừa kế, với ít khớp nối. – PaulMcG

3

Tôi nghĩ rằng vấn đề của bạn là bạn đang cố gắng mở rộng tích hợp sẵn. Các phương thức Magic __ không được gọi cho các nội trang dựng sẵn.Tôi nghĩ rằng bạn sẽ phải làm một số loại bọc-and-đại biểu, như thế này (chưa được kiểm tra) (có thể Anurag đánh tôi vào punch):

class Message(object): 

    def __init__(self, strvalue, domain, default='my message'): 
     self.msg = zope.i18nmessageid.Message(strvalue,domain,default) 

    def __getattr__(self,attr): 
     return getattr(self.msg,attr) 

    def __repr__(self): 
     return repr(zope.i18n.interpolate(self.msg.default, self.msg.mapping)) 

    def __str__(self): 
     return zope.i18n.interpolate(self.msg.default, self.msg.mapping) 

    def __unicode__(self): 
     return zope.i18n.interpolate(self.msg.default, self.msg.mapping) 

Cập nhật 1 - có vẻ như __ phương pháp làm được gọi cho lớp con của builtins

>>> class Z(int): 
... def __add__(self,other): return self*other 
... def __str__(self): return "***" 
... 
>>> a = Z(100) 
>>> a + 2 
200 
>>> a 
100 
>>> str(a) 
'***' 
>>> "%s" % a 
'***' 

vì vậy, chắc chắn là một số mâu thuẫn xảy ra ...

+0

Ý tưởng tuyệt vời, nhưng điều này không hoạt động! ;) Vâng nó hoạt động cho doctest nhất định, nhưng thực tế lớp này không còn là một thể hiện của 'chuỗi' phá vỡ một số kiểm tra C khác trong Python thư viện phổ biến mà tôi sử dụng và cần phải sử dụng. Tôi sẽ rõ ràng hơn vào ngày mai. – vaab

+0

Ah, bạn (hoặc những libs) đang sử dụng isinstance, có lẽ? Và bây giờ lớp này không còn kế thừa từ basestring? Hmmm, những kiểm tra isinstance sẽ không xảy ra để thực hiện xác nhận thông số đúng không? Đây là một trường hợp tuyệt vời cho thấy tại sao việc kiểm tra tham số isinstance không phải lúc nào cũng là ý tưởng tốt nhất trong Python. – PaulMcG