2013-04-03 31 views
6

Tôi đang viết một chương trình python có các trường hợp trên tất cả đầu vào (một thay thế cho không hoạt động tr '[:lowers:]' '[:upper:]'). Ngôn ngữ là ru_RU.UTF-8 và tôi sử dụng PYTHONIOENCODING=UTF-8 để đặt mã hóa STDIN/STDOUT. Điều này đặt chính xác sys.stdin.encoding. Vì vậy, tại sao tôi vẫn cần phải tạo rõ ràng trình bao bọc giải mã nếu sys.stdin đã biết mã hóa? Nếu tôi không tạo trình đọc gói, hàm .upper() không hoạt động chính xác (không làm gì đối với các ký tự không phải ASCII).Tại sao tôi phải làm `sys.stdin = codecs.getreader (sys.stdin.encoding) (sys.stdin)`?

import sys, codecs 
sys.stdin = codecs.getreader(sys.stdin.encoding)(sys.stdin) #Why do I need this? 
for line in sys.stdin: 
    sys.stdout.write(line.upper()) 

Tại sao stdin.encoding nếu nó không sử dụng?

+0

Phiên bản python nào? thử 'line.decode (your_encoding) .upper()' – JBernardo

+0

Câu trả lời ngắn gọn: Vì bạn đang sử dụng phiên bản Python lỗi thời đầy hành lý lịch sử. – phihag

+0

@JBernardo Python phiên bản là 2.7.3 (theo FreeBSD 9) 'line.decode (sys.stdin.encoding) .upper()' làm việc của khóa học. Nhưng câu hỏi của tôi là tại sao chúng ta cần tất cả điều này? –

Trả lời

10

Để trả lời "tại sao", chúng ta cần phải hiểu được loại 1.được xây dựng sẵn của Python 2.x, file.encoding và mối quan hệ của chúng.

Giao diện đối tượng được xây dựng trong file với byte nguyên --- luôn đọc và ghi byte thô.

Thuộc tính encoding mô tả mã hóa byte nguyên trong luồng. Thuộc tính này có thể có hoặc không có mặt và thậm chí có thể không đáng tin cậy (ví dụ: chúng tôi đặt PYTHONIOENCODING không chính xác trong trường hợp luồng chuẩn).

Thời gian duy nhất bất kỳ chuyển đổi tự động nào được thực hiện bởi file đối tượng là khi viết đối tượng unicode cho luồng đó. Trong trường hợp đó, nó sẽ sử dụng file.encoding nếu có sẵn để thực hiện chuyển đổi.

Trong trường hợp đọc dữ liệu, đối tượng tệp sẽ không thực hiện bất kỳ chuyển đổi nào vì nó trả về byte thô. Thuộc tính encoding trong trường hợp này là gợi ý để người dùng thực hiện chuyển đổi theo cách thủ công.

file.encoding được đặt trong trường hợp của bạn vì bạn đặt biến số PYTHONIOENCODING và thuộc tính'encoding được đặt tương ứng. Để có được một dòng văn bản, chúng ta phải quấn nó theo cách thủ công như bạn đã làm trong mã ví dụ của bạn.

Để suy nghĩ về cách khác, hãy tưởng tượng rằng chúng tôi không có loại văn bản riêng biệt (như là unicode hoặc Python 3's str). Chúng tôi vẫn có thể làm việc với văn bản bằng cách sử dụng byte thô, nhưng vẫn theo dõi mã hóa được sử dụng. Đây là loại cách file.encoding có nghĩa là để được sử dụng (được sử dụng để theo dõi mã hóa). Trình bao bọc trình đọc mà chúng tôi tạo tự động thực hiện theo dõi và chuyển đổi cho chúng tôi.

Tất nhiên, tự động gói sys.stdin sẽ đẹp hơn (và đó là Python 3.x), nhưng thay đổi hành vi mặc định là sys.stdin bằng Python 2.x sẽ phá vỡ tính tương thích ngược.

Sau đây là một so sánh của sys.stdin bằng Python 2.x và 3.x:

# Python 2.7.4 
>>> import sys 
>>> type(sys.stdin) 
<type 'file'> 
>>> sys.stdin.encoding 
'UTF-8' 
>>> w = sys.stdin.readline() 
## ... type stuff - enter 
>>> type(w) 
<type 'str'>   # In Python 2.x str is just raw bytes 
>>> import locale 
>>> locale.getdefaultlocale() 
('en_US', 'UTF-8') 

Các io.TextIOWrapper class là một phần của thư viện chuẩn từ Python 2.6. Lớp này có thuộc tính encoding được sử dụng để chuyển đổi byte thô thành Unicode từ và đến.

# Python 3.3.1 
>>> import sys 
>>> type(sys.stdin) 
<class '_io.TextIOWrapper'> 
>>> sys.stdin.encoding 
'UTF-8' 
>>> w = sys.stdin.readline() 
## ... type stuff - enter 
>>> type(w) 
<class 'str'>  # In Python 3.x str is Unicode 
>>> import locale 
>>> locale.getdefaultlocale() 
('en_US', 'UTF-8') 

Thuộc tính buffer cung cấp quyền truy cập vào luồng luồng byte nguyên stdin; đây thường là BufferedReader. Lưu ý dưới đây rằng nó không có thuộc tính encoding.

# Python 3.3.1 again 
>>> type(sys.stdin.buffer) 
<class '_io.BufferedReader'> 
>>> w = sys.stdin.buffer.readline() 
## ... type stuff - enter 
>>> type(w) 
<class 'bytes'>  # bytes is (kind of) equivalent to Python 2 str 
>>> sys.stdin.buffer.encoding 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: '_io.BufferedReader' object has no attribute 'encoding' 

Trong Python 3 sự có mặt hoặc vắng mặt của thuộc tính được sử dụng.

+0

Cảm ơn câu trả lời. Nó khẳng định niềm tin của tôi rằng thiết kế của 'Python 2' là xấu. Các đối tượng (trừ khi chúng là các cấu trúc chỉ lưu trữ dữ liệu đơn giản) không nên chứa dữ liệu mà chúng không sử dụng. Lớp 'file' không nên sử dụng thuộc tính' .encoding' của nó hoặc loại bỏ nó. Lỗ hổng thiết kế này đã được sửa trong 'Python 3'. .Net xử lý điều này theo cùng một cách: có 'Stream' dựa trên byte (bạn chỉ có thể viết các byte cho chúng) và các lớp trình bao bọc có nguồn gốc 'TextReader' /' TextWriter' có mã hóa. Bạn có thể sử dụng 'StreamReader.BaseStream' để truy cập vào các byte cơ bản. 'Console.In' là một' TextReader' (nhận dạng mã hóa). –

+0

Tốt để biết rằng 'Python 3' dường như cũng đã loại bỏ các chuỗi không phải Unicode (mặc dù vẫn còn những thứ như' BufferedReader.readline() '). –

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