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
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. –
@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
@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. –