2010-08-06 38 views
11

Như chúng ta đã biết bây giờ (tôi hy vọng), Python 3 đang dần dần bắt đầu thay thế Python 2.x. Tất nhiên nó sẽ được nhiều MANY năm trước khi hầu hết các mã hiện tại cuối cùng đã được chuyển, nhưng có những điều chúng ta có thể làm ngay bây giờ trong phiên bản 2.x mã của chúng tôi để làm cho việc chuyển đổi dễ dàng hơn.Sẵn sàng chuyển đổi từ Python 2.x thành 3.x

Rõ ràng hãy xem what's new trong 3.x sẽ hữu ích, nhưng một số điều chúng tôi có thể làm ngay bây giờ là làm cho chuyển đổi sắp tới không gây đau đớn (cũng như giúp bạn dễ dàng cập nhật các phiên bản đồng thời hơn))? Tôi đang suy nghĩ cụ thể về các dòng, chúng tôi có thể bắt đầu các kịch bản của chúng tôi với điều đó sẽ làm cho các phiên bản trước của Python tương tự như 3.x, mặc dù các thói quen khác cũng được hoan nghênh.

Mã rõ ràng nhất để thêm vào phía trên cùng của kịch bản mà tôi có thể nghĩ đến là:

from __future__ import division 
from __future__ import print_function 
try: 
    range = xrange 
except NameError: 
    pass 

Thói quen điều rõ ràng nhất mà tôi có thể nghĩ đến là "{0} {1}!".format("Hello", "World") để định dạng chuỗi.

Bất kỳ dòng nào khác và thói quen tốt để tham gia?

Trả lời

12

Vấn đề lớn nhất không thể được giải quyết đầy đủ bằng các thay đổi cấp vi mô và 2to3 là ​​sự thay đổi loại chuỗi mặc định từ byte thành Unicode.

Nếu mã của bạn cần làm bất cứ điều gì với mã hóa và byte I/O, nó sẽ cần một loạt các nỗ lực thủ công để chuyển đổi một cách chính xác, để những thứ phải là byte vẫn byte, và được giải mã một cách thích hợp ở bên phải sân khấu. Bạn sẽ thấy rằng một số phương thức chuỗi (cụ thể là format()) và các cuộc gọi thư viện yêu cầu chuỗi Unicode, vì vậy bạn có thể cần thêm chu kỳ giải mã/mã hóa chỉ để sử dụng chuỗi như Unicode ngay cả khi chúng thực sự chỉ là byte. Điều này không được hỗ trợ bởi thực tế là một số mô-đun thư viện chuẩn của Python đã được chuyển đổi thô bạo bằng cách sử dụng 2to3 mà không chú ý đến các vấn đề byte/unicode/mã hóa, và do đó họ mắc lỗi về loại chuỗi nào là thích hợp. Một số điều này đang bị đẩy ra ngoài, nhưng ít nhất là từ Python 3.0 đến 3.2, bạn sẽ phải đối mặt với hành vi khó hiểu và có khả năng gây lỗi từ các gói như urllib, email và wsgiref cần biết về mã hóa byte.

Bạn có thể cải thiện vấn đề bằng cách cẩn thận mỗi khi bạn viết chuỗi ký tự. Sử dụng các chuỗi u'' cho bất kỳ thứ gì vốn dựa trên ký tự, các chuỗi b'' cho bất kỳ thứ gì thực sự là byte và '' đối với loại chuỗi mặc định, không quan trọng hoặc bạn cần phải khớp với yêu cầu sử dụng chuỗi cuộc gọi của thư viện.

Thật không may cú pháp b'' chỉ được giới thiệu trong Python 2.6, do đó, việc này sẽ cắt giảm người dùng các phiên bản cũ hơn.

eta:

có gì khác biệt?

Oh my. Tốt...

Một byte chứa giá trị trong khoảng 0–255 và có thể đại diện cho một tải dữ liệu nhị phân (ví dụ: nội dung của hình ảnh) hoặc một số văn bản, trong trường hợp đó phải là tiêu chuẩn được chọn để ánh xạ một tập hợp các ký tự vào các byte đó. Hầu hết các tiêu chuẩn 'mã hóa' này ánh xạ ký tự 'ASCII' bình thường được đặt thành byte 0–127 theo cùng một cách, vì vậy thường an toàn khi sử dụng chuỗi byte cho xử lý văn bản chỉ ASCII bằng Python 2.

Nếu bạn muốn sử dụng bất kỳ ký tự nào bên ngoài thiết lập ASCII trong chuỗi byte, bạn gặp rắc rối, bởi vì mỗi mã hóa ánh xạ một nhóm ký tự khác nhau vào các giá trị byte còn lại 128–255 và hầu hết mã hóa không thể ánh xạ mọi ký tự có thể thành byte. Đây là nguồn gốc của tất cả những vấn đề mà bạn tải một tập tin từ một miền địa phương vào một ứng dụng Windows ở một miền địa phương khác và tất cả các chữ có dấu hoặc không phải là chữ cái Latinh thay đổi thành những cái sai, tạo ra một mớ hỗn độn không đọc được. (aka ‘mojibake’.)

Ngoài ra còn có các bảng mã ‘multibyte’, cố gắng ghép nhiều ký tự hơn vào không gian có sẵn bằng cách sử dụng nhiều hơn một byte để lưu trữ mỗi ký tự. Chúng được giới thiệu cho khu vực Đông Á, vì có rất nhiều ký tự Trung Quốc. Nhưng cũng có UTF-8, một mã hóa nhiều byte hiện đại được thiết kế tốt hơn có thể chứa mỗi ký tự.

Nếu bạn đang làm việc trên chuỗi byte trong mã hóa nhiều byte — và ngày nay bạn có thể sẽ sử dụng, vì UTF-8 được sử dụng rất rộng rãi; thực sự, không có mã hóa nào khác nên được sử dụng trong một ứng dụng hiện đại — sau đó bạn thậm chí còn gặp nhiều vấn đề hơn là chỉ theo dõi mã hóa bạn đang chơi. len() sẽ cho bạn biết độ dài tính theo byte, không phải độ dài ký tự và nếu bạn bắt đầu lập chỉ mục và thay đổi byte, bạn có khả năng phá vỡ chuỗi multibyte thành hai, tạo ra chuỗi không hợp lệ và thường gây nhầm lẫn mọi thứ.

Vì lý do này, Python 1.6 trở lên có chuỗi Unicode gốc (được viết là u'something'), trong đó mỗi đơn vị trong chuỗi là ký tự chứ không phải byte. Bạn có thể len() chúng, cắt chúng, thay thế chúng, chỉnh sửa chúng và chúng sẽ luôn hoạt động một cách thích hợp. Đối với các tác vụ xử lý văn bản, chúng hoàn toàn tốt hơn, đó là lý do Python 3 làm cho chúng trở thành kiểu chuỗi mặc định (không cần phải đặt u trước '').

Bắt là rất nhiều giao diện hiện có, chẳng hạn như tên tệp trên hệ điều hành không phải Windows hoặc HTTP hoặc SMTP, chủ yếu dựa trên byte, với cách riêng để chỉ định mã hóa. Vì vậy, khi bạn đang xử lý các thành phần cần byte, bạn phải cẩn thận mã hóa các chuỗi unicode thành byte đúng và trong Python 3, bạn sẽ phải làm điều đó một cách rõ ràng ở một số nơi trước khi bạn không cần.

Đây là chi tiết triển khai nội bộ mà chuỗi Unicode lấy 'hai byte' bộ nhớ trên mỗi đơn vị nội bộ. Bạn không bao giờ thấy bộ nhớ đó; bạn không nên nghĩ về nó theo byte. Các đơn vị bạn đang làm việc trên là các ký tự khái niệm, bất kể Python chọn để biểu diễn chúng như thế nào trong bộ nhớ.

... sang một bên:

Điều này không đúng. Trên 'các bản dựng hẹp' của Python như bản dựng Windows, mỗi đơn vị của một chuỗi Unicode không phải là một ký tự về mặt kỹ thuật, mà là một đơn vị mã UTF-16 '. Đối với các ký tự trong Mặt phẳng đa ngôn ngữ cơ bản, từ 0x0000–0xFFFF bạn sẽ không nhận thấy bất kỳ sự khác biệt nào, nhưng nếu bạn đang sử dụng các ký tự từ bên ngoài phạm vi 16 bit này, các ký tự trong 'máy bay astral', bạn sẽ thấy hai đơn vị thay vì một, và, một lần nữa, bạn có nguy cơ tách một nhân vật khi bạn cắt chúng.

Điều này là khá xấu và đã xảy ra vì Windows (và những người khác, chẳng hạn như Java) đã giải quyết UTF-16 như một cơ chế lưu trữ trong bộ nhớ trước khi Unicode vượt quá giới hạn 65.000 ký tự.Tuy nhiên, việc sử dụng các ký tự mở rộng này vẫn còn khá hiếm, và bất kỳ ai trên Windows sẽ được sử dụng để chúng phá vỡ trong nhiều ứng dụng, vì vậy nó có thể không quan trọng đối với bạn.

Trên ‘bản dựng rộng’, chuỗi Unicode được tạo thành từ các ký tự ‘mã điểm’ thực, vì vậy ngay cả các ký tự mở rộng bên ngoài BMP có thể được xử lý nhất quán và dễ dàng. Giá phải trả cho điều này là hiệu quả: mỗi đơn vị chuỗi chiếm bốn byte bộ nhớ trong bộ nhớ.

+0

Khi nói đến chuỗi byte và unicode, điểm khác biệt là gì? Chỉ cần các chuỗi byte sử dụng một byte cho mỗi ký tự trong khi unicode sử dụng hai byte? –

+0

"" "UTF-8 ... không sử dụng mã hóa khác trong ứng dụng hiện đại" "trừ khi chính phủ của bạn ủy quyền cho một số thứ khác, ví dụ: 'gb18030' :-) –

+0

Đó là một giải thích * tuyệt vời về sự khác biệt giữa chuỗi byte và Unicode. Tôi đã ít nhiều quen thuộc với ASCII v. Unicode, nhưng (rõ ràng) tôi không quen thuộc với cách Python (esp 3.x) xử lý chúng. Tôi muốn tôi có thể bỏ phiếu nhiều lần;) –

5

Tôi đang cố gắng để có thói quen sử dụng những thứ như var1//var2 bất cứ khi nào tôi thực sự muốn chia số nguyên (và không phải là một phao). Không phải là một bước tiến lớn đối với Python 3, nhưng ít nhất tôi sẽ không phải quay lại và kiểm tra tất cả các bộ phận của tôi :)

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