2011-12-14 11 views
34

Có nhiều cách để bao gồm các tính năng Python 3.x trong Python 2.x, do đó, mã của các script Python 2.x có thể dễ dàng được chuyển đổi sang Python 3.x trong tương lai. Một trong những ví dụ được thay thế print tuyên bố với print() chức năng:Cách viết Python 2.x tương thích với Python 3.x càng tốt?

>>> from __future__ import print_function 

Có bất kỳ danh sách hoặc tài nguyên mà có thể cung cấp cho một số ý tưởng làm thế nào để làm cho mã Python 2.x càng gần Python 3.x càng tốt?

bạn có thể đưa ra ví dụ về nhập khẩu hữu ích khác hoặc các định nghĩa có thể làm Python 2.x nhìn và cư xử giống như Python 3.x?

Giả sử chúng tôi có phiên bản Python 2.x mới nhất (2.7.2 tại thời điểm này, tôi tin) theo ý của chúng tôi.

+2

câu trả lời cho [this] (http://stackoverflow.com/questions/5937251/writing-python-2-7-code-that-is-as-close-to-python-3-x-syntax-as -possible) câu hỏi có thể hữu ích. –

+2

@BoraCaglayan: Có, tiêu đề gần giống y như câu hỏi này :) Nhưng tiếc là liên kết đó là về các ứng dụng Django (nghĩa là có mã cơ sở hiện tại và bạn không được làm hỏng ứng dụng). Câu hỏi của tôi là về các ứng dụng mới được tạo, nơi bạn không cần phải lo lắng điều đó. có rất nhiều mã sử dụng câu lệnh 'print' thay cho hàm. Điều này giúp loại bỏ rất nhiều vấn đề, tôi tin. – Tadeck

+0

@Tadeck: Không, chức năng in là một vấn đề rất nhỏ.Hầu hết các vấn đề đều giống nhau và khó hơn nhiều. Bạn không thực sự tránh bất kỳ sự khó khăn tương thích bằng cách sử dụng Django. –

Trả lời

22

Tôi đang đặt lo mọi việc trên một dòng xấp xỉ 5000, deduplicating chương trình sao lưu (http://stromberg.dnsalias.org/~strombrg/backshift/) chạy trên CPython 2. [ 567], CPython 3. [0123] (3,3 vẫn là alpha 0), Pypy 1.7 và Jython trunk. Tôi cũng đã cố gắng IronPython, nhưng nó là một điều khá khác nhau - nó không có thư viện chuẩn, vì vậy không có tình yêu backshift. Ồ, và nó có thể sử dụng Cython cho vòng lặp trong cùng của nó, hoặc psyco - nhưng pypy nhanh hơn một trong hai, đặc biệt là trên các hệ thống 32 bit.

Dù sao, tôi thấy rằng để viết mã chạy tốt như nhau trên 2.x và 3.x tất cả những gì cần làm là:

1) in (biến) hoạt động tương tự trên cả hai 2.x và 3.x. print (biến1, biến2) thì không. Để 2.x, in (biến) cho biết "đánh giá biểu thức được lồng dấu này và in kết quả đơn bằng cách sử dụng câu lệnh in". Để in 3.x, in (biến) cho biết "hãy gọi hàm in trên kết quả này. Vì vậy, in ('abc% d% d'% (1, 2)) hoạt động tốt trong cả hai, bởi vì nó là kết quả đơn giá trị, và cả hai grok các nhà điều hành% để định dạng chuỗi.

2) Tránh hằng bát phân. Thay vì viết 0755, viết (7 * 64 + 5 * 8 + 5).

3) để làm nhị phân I/O Tôi đã sử dụng mô-đun bufsock của mình http://stromberg.dnsalias.org/~strombrg/bufsock.html Tôi muốn sử dụng một tập tin, và bọc nó với bufsock (hoặc sử dụng lớp rawio trong module). Trên 2.x, điều này sẽ trả về một chuỗi các byte được mã hóa thành 8 Trong chuỗi 3.x, điều này sẽ trả về một đối tượng byte, hoạt động giống như một danh sách các số nguyên nhỏ, sau đó tôi chỉ chuyển qua một hoặc một số khác, thử nghiệm với "isinstance (foo, str)" khi cần để phân biệt giữa hai. d này, bởi vì để một chương trình sao lưu, byte là byte - Tôi không muốn mess xung quanh với encodings ô nhiễm lên tiết kiệm dữ liệu đáng tin cậy, và không phải tất cả các mã hóa vòng chuyến đi tốt.

4) Khi thực hiện ngoại lệ, hãy tránh từ khóa "dưới dạng". Thay vào đó, hãy sử dụng EG:

try: 
    self.update_timestamp() 
    except (OSError, IOError): 
    dummy, utime_extra, dummy = sys.exc_info() 
    if utime_extra.errno == errno.ENOENT: 

5) Một loạt các mô-đun được đổi tên trong quá trình chuyển đổi từ 2.x thành 3.x.Vì vậy hãy thử nhập một trong hai thành một mô-đun khác rỗng, với một cái gì đó như:

try: 
    from anydbm import * 
except ImportError: 
    from dbm import * 

... điều này sẽ xuất hiện trong một mô-đun bằng cách riêng của mình, với một tên EG adbm.py. Sau đó, bất cứ lúc nào tôi cần một cửa hàng khóa-giá trị, tôi muốn nhập adbm thay vì hai thứ khác nhau cần thiết cho 2.x hoặc 3.x trực tiếp. Sau đó, tôi muốn pylint tất cả mọi thứ nhưng mô-đun mập mạp, adbm.py - và những thứ như nó mà pylint không thích. Ý tưởng là để pylint tất cả mọi thứ có thể, với ngoại lệ cho "tất cả mọi thứ của gotta pylint" quy tắc trong một mô-đun nhỏ tất cả bởi chính nó, một ngoại lệ cho mỗi mô-đun.

6) Nó giúp rất nhiều để thiết lập kiểm tra đơn vị tự động và kiểm tra hệ thống chạy trên 2.x và 3.x, và sau đó kiểm tra thường xuyên trên ít nhất một thông dịch viên 2.x cũng như ít nhất một 3. x thông dịch viên. Tôi cũng chạy pylint chống lại mã của tôi thường xuyên, mặc dù chỉ là một pylint kiểm tra cho tuân thủ 2.5.x - Tôi bắt đầu dự án trước khi pylint có hỗ trợ 3.x.

7) Tôi thiết lập một nhỏ "python2x3" mô-đun mà có một vài hằng số và callables để làm cho cuộc sống dễ dàng hơn: http://stromberg.dnsalias.org/svn/python2x3/trunk/python2x3.py

8) b '' literals không làm việc trong 2,5, mặc dù họ sắp xếp công việc trong 2. [67]. Thay vì cố gắng tiền xử lý hoặc một cái gì đó, tôi thiết lập một constants_mod.py có rất nhiều thứ thường là b '' literals in 3.x, và chuyển đổi chúng từ một chuỗi đơn giản thành bất kỳ kiểu "byte" nào cho 2 .x hoặc 3.x. Vì vậy, chúng được chuyển đổi một lần trên nhập khẩu mô-đun, không phải hơn và hơn khi chạy. Nếu bạn đang nhắm mục tiêu 2. [67] và lên, có lẽ là một cách tốt hơn, nhưng khi tôi bắt đầu dự án Pypy chỉ tương thích với 2.5, và Jython vẫn còn.

9) Trong 2.x, số nguyên dài có hậu tố L. Trong 3.x, tất cả các số nguyên đều dài. Vì vậy, tôi chỉ cần đi với tránh hằng số nguyên dài càng nhiều càng tốt; 2.x sẽ thúc đẩy một số nguyên lâu dài khi cần thiết, vì vậy điều này dường như làm việc tốt cho hầu hết mọi thứ.

10) Nó giúp một LOT có một loạt các trình dịch python xung quanh để kiểm tra. Tôi xây dựng 2. [567] và 3. [0123] và lưu trữ chúng trong /usr/local/cpython-x.y/ để kiểm tra dễ dàng. Tôi cũng đặt một số Pypy và Jython trong/usr/local, một lần nữa để kiểm tra dễ dàng. Có một kịch bản để tự động hóa các bản xây dựng CPython là khá có giá trị.

Tôi tin rằng đây là tất cả những mâu thuẫn mà tôi yêu cầu để có được một codebase python có khả năng di động cao trong một dự án không phát triển. Một thiếu sót lớn trong danh sách tôi đã viết ở trên, là tôi không cố gắng sử dụng các đối tượng unicode - đó là điều mà một người khác có thể đủ điều kiện để nhận xét.

HTH

+1

hey, bạn biết rằng thủ thuật sys.exc_info() sẽ làm cho tiếng khóc đáng sợ? – fijal

+0

Không, tôi đã không. Cảm ơn bạn đã đề cập đến điều đó. Cần gì để sửa nó trong Pypy? – dstromberg

+0

Nó có thực sự không? Điều này dường như hoạt động: >>>> thử: .... dummy = 1/0 .... ngoại trừ: .... dummy, foo, dummy = sys.exc_info() ... in foo .... số nguyên chia cho số không >>>> – dstromberg

7

Bạn nên xem Porting Python Code to 3.0. Trong khi nó nhắm vào porting, nó trả lời về cơ bản cùng một câu hỏi; bạn sẽ không đi hết đường.

+0

Cảm ơn. Tôi đặc biệt quan tâm đến tùy chọn thứ 2 từ liên kết mà bạn đã đưa ra: "_make code run unmodified trong cả Python 2 và Python 3_". Tùy chọn này là gần nhất với những gì tôi đang cố gắng đạt được. – Tadeck

1

Tôi có điều này ở phía trên cùng của Python 2.7 kịch bản mẫu của tôi:

from __future__ import division, print_function 
from future_builtins import ascii, filter, hex, map, oct, zip 
+2

Đó là hư không gần đủ để sử dụng thực tế. Và tương lai_builtins không tồn tại trong Python 3, vì vậy mã này sẽ không chạy trên Python 3. –

+1

Sẽ không thực tế hơn nếu giữ mô đun furure_builtins trong thư viện chuẩn Python 3, để làm cho nó dễ dàng hơn để hỗ trợ cả hai Python2 và Python3 phiên bản từ một codebase chung? – pmav99

7

a whole chapter về vấn đề này trong "Porting to Python 3". Cũng đừng bỏ lỡ các phụ lục, liệt kê các khác biệt về ngôn ngữ với cách giải quyết để hỗ trợ cả hai ngôn ngữ.

Bạn có thể muốn sử dụng six library, mặc dù có thể thực hiện việc này mà không cần đến nó.

1

Vì nó chưa được đề cập: Tôi thấy điều này cheat sheet thực sự hữu ích cho mục đích chính xác này.