Có gì mới trong Python 3.0

tác giả:

Guido van Rossum

Bài viết này giải thích các tính năng mới trong Python 3.0, so với 2.6. Python 3.0, còn được gọi là "Python 3000" hoặc "Py3K", là bản phát hành Python intentionally backwards incompatible đầu tiên. Python 3.0 được phát hành vào ngày 3 tháng 12 năm 2008. Có nhiều thay đổi hơn so với phiên bản thông thường và còn nhiều thay đổi quan trọng đối với tất cả người dùng Python. Tuy nhiên, sau khi tìm hiểu các thay đổi, bạn sẽ thấy rằng Python thực sự không thay đổi nhiều -- nhìn chung, chúng tôi chủ yếu sửa chữa các vấn đề khó chịu và mụn cóc phổ biến cũng như loại bỏ nhiều lỗi cũ.

Bài viết này không cố gắng cung cấp thông số kỹ thuật đầy đủ của tất cả các tính năng mới mà thay vào đó cố gắng cung cấp một cái nhìn tổng quan thuận tiện. Để biết chi tiết đầy đủ, bạn nên tham khảo tài liệu dành cho Python 3.0 và/hoặc nhiều PEP được tham chiếu trong văn bản. Nếu bạn muốn hiểu cơ sở lý luận về thiết kế và triển khai đầy đủ cho một tính năng cụ thể, PEP thường có nhiều chi tiết hơn tài liệu thông thường; nhưng lưu ý rằng PEP thường không được cập nhật khi một tính năng đã được triển khai đầy đủ.

Do hạn chế về thời gian nên tài liệu này chưa hoàn chỉnh như mong đợi. Như thường lệ đối với một bản phát hành mới, tệp Misc/NEWS trong bản phân phối nguồn chứa rất nhiều thông tin chi tiết về mọi điều nhỏ nhặt đã được thay đổi.

Những trở ngại thường gặp

Phần này liệt kê một số thay đổi có nhiều khả năng khiến bạn gặp khó khăn nhất nếu bạn đã quen với Python 2.5.

Lượt xem và vòng lặp thay vì danh sách

Một số API nổi tiếng không còn trả về danh sách:

  • Các phương thức dict dict.keys(), dict.items()dict.values() trả về "lượt xem" thay vì danh sách. Ví dụ: điều này không còn hoạt động nữa: k = d.keys(); k.sort(). Thay vào đó, hãy sử dụng k = sorted(d) (điều này cũng hoạt động trong Python 2.5 và hiệu quả tương đương).

  • Ngoài ra, các phương thức dict.iterkeys(), dict.iteritems()dict.itervalues() không còn được hỗ trợ.

  • map()filter() trả về các trình vòng lặp. Nếu bạn thực sự cần một danh sách và các chuỗi đầu vào đều có độ dài bằng nhau, cách khắc phục nhanh là bọc map() trong list(), ví dụ: list(map(...)), nhưng cách khắc phục tốt hơn thường là sử dụng tính năng hiểu danh sách (đặc biệt khi mã gốc sử dụng lambda) hoặc viết lại mã để không cần danh sách nào cả. Đặc biệt khó khăn là map() được gọi vì các tác dụng phụ của hàm; cách chuyển đổi đúng là sử dụng vòng lặp for thông thường (vì việc tạo danh sách sẽ rất lãng phí).

    Nếu các chuỗi đầu vào không có độ dài bằng nhau, map() sẽ dừng ở điểm cuối của chuỗi ngắn nhất. Để tương thích hoàn toàn với map() từ Python 2.x, hãy gói cả các chuỗi trong itertools.zip_longest(), ví dụ: map(func, *sequences) trở thành list(map(func, itertools.zip_longest(*sequences))).

  • range() hiện hoạt động giống như xrange() trước đây, ngoại trừ việc nó hoạt động với các giá trị có kích thước tùy ý. Cái sau không còn tồn tại.

  • zip() hiện trả về một trình vòng lặp.

So sánh thứ tự

Python 3.0 đã đơn giản hóa các quy tắc so sánh thứ tự:

  • Các toán tử so sánh thứ tự (<, <=, >=, >) đưa ra ngoại lệ TypeError khi các toán hạng không có thứ tự tự nhiên có ý nghĩa. Do đó, các biểu thức như 1 < '', 0 > None hoặc len <= len không còn hợp lệ và ví dụ: None < None tăng TypeError thay vì trả về False. Một hệ quả tất yếu là việc sắp xếp một danh sách không đồng nhất không còn ý nghĩa nữa -- tất cả các phần tử phải có thể so sánh được với nhau. Lưu ý rằng điều này không áp dụng cho toán tử ==!=: các đối tượng thuộc các loại không thể so sánh được khác nhau luôn so sánh không bằng nhau.

  • sorted()list.sort() không còn chấp nhận đối số cmp cung cấp chức năng so sánh. Thay vào đó hãy sử dụng đối số key. N.B. các đối số keyreverse hiện là "chỉ từ khóa".

  • Chức năng cmp() sẽ được coi là không còn nữa và phương thức đặc biệt __cmp__() không còn được hỗ trợ. Sử dụng __lt__() để sắp xếp, __eq__() với __hash__() và các so sánh phong phú khác nếu cần. (Nếu bạn thực sự cần chức năng cmp(), bạn có thể sử dụng biểu thức (a > b) - (a < b) tương đương với cmp(a, b).)

số nguyên

  • PEP 237: Về cơ bản, long được đổi tên thành int. Tức là chỉ có một loại tích phân tích hợp có tên là int; nhưng nó hoạt động giống như loại long cũ.

  • PEP 238: Một biểu thức như 1/2 trả về một float. Sử dụng 1//2 để thực hiện hành vi cắt ngắn. (Cú pháp sau đã tồn tại trong nhiều năm, ít nhất là kể từ Python 2.2.)

  • Hằng số sys.maxint đã bị xóa vì không còn giới hạn đối với giá trị của số nguyên. Tuy nhiên, sys.maxsize có thể được sử dụng như một số nguyên lớn hơn bất kỳ danh sách hoặc chỉ mục chuỗi thực tế nào. Nó phù hợp với kích thước số nguyên "tự nhiên" của quá trình triển khai và thường giống với sys.maxint trong các bản phát hành trước trên cùng một nền tảng (giả sử có cùng các tùy chọn xây dựng).

  • repr() của một số nguyên dài không còn bao gồm L ở cuối nữa, do đó, mã loại bỏ ký tự đó một cách vô điều kiện sẽ cắt bỏ chữ số cuối cùng. (Thay vào đó hãy sử dụng str().)

  • Chữ bát phân không còn ở dạng 0720 nữa; thay vào đó hãy sử dụng 0o720.

Văn bản Vs. Dữ liệu thay vì Unicode Vs. 8-bit

Mọi thứ bạn nghĩ bạn biết về dữ liệu nhị phân và Unicode đã thay đổi.

  • Python 3.0 sử dụng các khái niệm text và (nhị phân) data thay vì chuỗi Unicode và chuỗi 8 bit. Tất cả văn bản đều là Unicode; tuy nhiên encoded Unicode được biểu diễn dưới dạng dữ liệu nhị phân. Loại dùng để chứa văn bản là str, loại dùng để chứa dữ liệu là bytes. Sự khác biệt lớn nhất với tình huống 2.x là mọi nỗ lực trộn văn bản và dữ liệu trong Python 3.0 đều làm tăng TypeError, trong khi nếu bạn trộn chuỗi Unicode và chuỗi 8 bit trong Python 2.x, nó sẽ hoạt động nếu chuỗi 8 bit tình cờ chỉ chứa byte 7 bit (ASCII), nhưng bạn sẽ nhận được UnicodeDecodeError nếu nó chứa các giá trị không phải là ASCII. Hành vi có giá trị cụ thể này đã gây ra nhiều gương mặt đau buồn trong nhiều năm qua.

  • Do hậu quả của sự thay đổi về triết lý này, hầu như tất cả các mã sử dụng Unicode, mã hóa hoặc dữ liệu nhị phân rất có thể phải thay đổi. Sự thay đổi này là tốt hơn, vì trong thế giới 2.x có rất nhiều lỗi liên quan đến việc trộn lẫn văn bản được mã hóa và không được mã hóa. Để chuẩn bị bằng Python 2.x, hãy bắt đầu sử dụng unicode cho tất cả văn bản chưa được mã hóa và str chỉ cho dữ liệu nhị phân hoặc được mã hóa. Sau đó, công cụ 2to3 sẽ thực hiện hầu hết công việc cho bạn.

  • Bạn không thể sử dụng chữ u"..." cho văn bản Unicode nữa. Tuy nhiên, bạn phải sử dụng hằng số b"..." cho dữ liệu nhị phân.

  • Vì loại strbytes không thể trộn lẫn nên bạn phải luôn chuyển đổi rõ ràng giữa chúng. Sử dụng str.encode() để chuyển từ str sang bytesbytes.decode() để chuyển từ bytes sang str. Bạn cũng có thể sử dụng bytes(s, encoding=...)str(b, encoding=...) tương ứng.

  • Giống như str, loại bytes là bất biến. Có một loại mutable riêng để chứa dữ liệu nhị phân được đệm, bytearray. Gần như tất cả các API chấp nhận bytes cũng chấp nhận bytearray. Zz007zz có thể thay đổi được dựa trên collections.MutableSequence.

  • Tất cả các dấu gạch chéo ngược trong chuỗi ký tự thô được hiểu theo nghĩa đen. Điều này có nghĩa là các ký tự thoát '\U''\u' trong chuỗi thô không được xử lý đặc biệt. Ví dụ: r'\u20ac' là một chuỗi gồm 6 ký tự trong Python 3.0, trong khi ở 2.6, ur'\u20ac' là một ký tự "euro". (Tất nhiên, thay đổi này chỉ ảnh hưởng đến các chuỗi ký tự thô; ký tự euro là '\u20ac' trong Python 3.0.)

  • Loại trừu tượng basestring tích hợp đã bị xóa. Thay vào đó hãy sử dụng str. Các loại strbytes không có đủ chức năng chung để đảm bảo một lớp cơ sở dùng chung. Công cụ 2to3 (xem bên dưới) thay thế mọi lần xuất hiện của basestring bằng str.

  • Các tệp được mở dưới dạng tệp văn bản (vẫn là chế độ mặc định cho open()) luôn sử dụng mã hóa để ánh xạ giữa các chuỗi (trong bộ nhớ) và byte (trên đĩa). Các tệp nhị phân (được mở bằng b trong đối số chế độ) luôn sử dụng byte trong bộ nhớ. Điều này có nghĩa là nếu một tệp được mở bằng chế độ hoặc mã hóa không chính xác, I/O có thể sẽ bị lỗi nghiêm trọng, thay vì âm thầm tạo ra dữ liệu không chính xác. Điều đó cũng có nghĩa là ngay cả người dùng Unix cũng sẽ phải chỉ định chế độ chính xác (văn bản hoặc nhị phân) khi mở tệp. Có một mã hóa mặc định phụ thuộc vào nền tảng, trên nền tảng Unixy có thể được đặt bằng biến môi trường LANG (và đôi khi cũng có một số biến môi trường liên quan đến ngôn ngữ cụ thể theo nền tảng khác). Trong nhiều trường hợp, nhưng không phải tất cả, mặc định của hệ thống là UTF-8; bạn không bao giờ nên tin tưởng vào sự mặc định này. Bất kỳ ứng dụng nào đọc hoặc viết nhiều hơn văn bản ASCII thuần túy đều có thể có cách ghi đè mã hóa. Không còn nhu cầu sử dụng các luồng nhận biết mã hóa trong mô-đun codecs nữa.

  • Các giá trị ban đầu của sys.stdin, sys.stdoutsys.stderr hiện là các tệp văn bản chỉ unicode (tức là chúng là các phiên bản của io.TextIOBase). Để đọc và ghi dữ liệu byte với các luồng này, bạn cần sử dụng thuộc tính io.TextIOBase.buffer của chúng.

  • Tên tệp được chuyển đến và trả về từ API dưới dạng chuỗi (Unicode). Điều này có thể gây ra các vấn đề dành riêng cho nền tảng vì trên một số tên tệp nền tảng là các chuỗi byte tùy ý. (Mặt khác, trên Windows, tên tệp được lưu trữ nguyên bản dưới dạng Unicode.) Để giải quyết, hầu hết các API (ví dụ: open() và nhiều hàm trong mô-đun os) lấy tên tệp chấp nhận các đối tượng bytes cũng như các chuỗi và một số API có cách yêu cầu giá trị trả về bytes. Do đó, os.listdir() trả về danh sách các phiên bản bytes nếu đối số là phiên bản bytesos.getcwdb() trả về thư mục làm việc hiện tại dưới dạng phiên bản bytes. Lưu ý rằng khi os.listdir() trả về danh sách các chuỗi, tên tệp không thể giải mã chính xác sẽ bị bỏ qua thay vì tăng UnicodeError.

  • Một số API hệ thống như os.environsys.argv cũng có thể gây ra sự cố khi các byte do hệ thống cung cấp không thể hiểu được bằng cách sử dụng mã hóa mặc định. Đặt biến LANG và chạy lại chương trình có lẽ là cách tiếp cận tốt nhất.

  • PEP 3138: repr() của chuỗi không còn thoát khỏi các ký tự không phải ASCII. Tuy nhiên, nó vẫn thoát khỏi các ký tự điều khiển và điểm mã với trạng thái không in được trong tiêu chuẩn Unicode.

  • PEP 3120: Mã hóa nguồn mặc định hiện là UTF-8.

  • PEP 3131: Các chữ cái không phải ASCII hiện được phép sử dụng trong mã định danh. (Tuy nhiên, thư viện tiêu chuẩn vẫn chỉ có ASCII ngoại trừ tên người đóng góp trong nhận xét.)

  • Các mô-đun StringIOcStringIO đã biến mất. Thay vào đó, hãy nhập mô-đun io và sử dụng io.StringIO hoặc io.BytesIO cho văn bản và dữ liệu tương ứng.

  • Xem thêm Unicode HOWTO, được cập nhật cho Python 3.0.

Tổng quan về các thay đổi cú pháp

Phần này cung cấp thông tin tổng quan ngắn gọn về mọi thay đổi syntactic trong Python 3.0.

Cú pháp mới

  • PEP 3107: Chú thích đối số hàm và giá trị trả về. Điều này cung cấp một cách chuẩn hóa để chú thích các tham số và giá trị trả về của hàm. Không có ngữ nghĩa nào được đính kèm với các chú thích như vậy ngoại trừ việc chúng có thể được xem xét nội tâm trong thời gian chạy bằng thuộc tính __annotations__. Mục đích là khuyến khích thử nghiệm thông qua siêu lớp, trang trí hoặc khung.

  • PEP 3102: Đối số chỉ có từ khóa. Các tham số được đặt tên xảy ra sau *args trong danh sách tham số must được chỉ định bằng cú pháp từ khóa trong lệnh gọi. Bạn cũng có thể sử dụng * trần trong danh sách tham số để cho biết rằng bạn không chấp nhận danh sách đối số có độ dài thay đổi, nhưng bạn có các đối số chỉ từ khóa.

  • Đối số từ khóa được cho phép sau danh sách các lớp cơ sở trong định nghĩa lớp. Điều này được quy ước mới sử dụng để chỉ định siêu dữ liệu (xem phần tiếp theo), nhưng cũng có thể được sử dụng cho các mục đích khác, miễn là siêu dữ liệu hỗ trợ nó.

  • PEP 3104: câu lệnh nonlocal. Bằng cách sử dụng nonlocal x, giờ đây bạn có thể gán trực tiếp cho một biến ở phạm vi bên ngoài (nhưng không phải toàn cục). nonlocal là một từ dành riêng mới.

  • PEP 3132: Giải nén lặp lại mở rộng. Bây giờ bạn có thể viết những thứ như a, b, *rest = some_sequence. Và thậm chí cả *rest, a = stuff. Đối tượng rest luôn là một danh sách (có thể trống); phía bên phải có thể là bất kỳ lần lặp nào. Ví dụ:

    (a, *phần còn lại, b) = phạm vi (5)
    

    Điều này đặt a thành 0, b thành 4rest thành [1, 2, 3].

  • Hiểu từ điển: {k: v for k, v in stuff} có nghĩa tương tự như dict(stuff) nhưng linh hoạt hơn. (Đây là PEP 274 được minh oan. :-)

  • Đặt chữ, ví dụ: {1, 2}. Lưu ý rằng {} là một từ điển trống; sử dụng set() cho một bộ trống. Việc hiểu tập hợp cũng được hỗ trợ; ví dụ: {x for x in stuff} có nghĩa tương tự như set(stuff) nhưng linh hoạt hơn.

  • Chữ bát phân mới, ví dụ: 0o720 (đã có trong 2.6). Các chữ bát phân cũ (0720) đã biến mất.

  • Chữ nhị phân mới, ví dụ: 0b1010 (đã có trong 2.6) và có một chức năng tích hợp tương ứng mới, bin().

  • Các ký tự byte được giới thiệu với b hoặc B đứng đầu và có một hàm tích hợp tương ứng mới, bytes().

Cú pháp đã thay đổi

  • PEP 3109PEP 3134: cú pháp câu lệnh raise mới: raise [expr [from expr]]. Xem bên dưới.

  • aswith hiện là những từ dành riêng. (Thực tế là kể từ 2.6.)

  • True, FalseNone là những từ dành riêng. (2.6 đã thực thi một phần các hạn chế trên None.)

  • Thay đổi từ except exc, var thành except exc as var. Xem PEP 3110.

  • PEP 3115: Cú pháp siêu dữ liệu mới. Thay vì:

    lớp C:
        __siêu lớp__ = M
        ...
    

    bây giờ bạn phải sử dụng:

    lớp C (siêu lớp=M):
        ...
    

    Biến __metaclass__ toàn cầu của mô-đun không còn được hỗ trợ. (Đó là một chiếc nạng để giúp việc mặc định các lớp kiểu mới dễ dàng hơn mà không cần lấy mọi lớp từ object.)

  • Tính năng hiểu danh sách không còn hỗ trợ dạng cú pháp [... for var in item1, item2, ...] nữa. Thay vào đó hãy sử dụng [... for var in (item1, item2, ...)]. Cũng lưu ý rằng việc hiểu danh sách có ngữ nghĩa khác nhau: chúng gần với cú pháp hơn đối với biểu thức trình tạo bên trong hàm tạo list() và đặc biệt là các biến điều khiển vòng lặp không còn bị rò rỉ vào phạm vi xung quanh.

  • ellipsis (...) có thể được sử dụng làm biểu thức nguyên tử ở bất cứ đâu. (Trước đây nó chỉ được phép ở dạng lát.) Ngoài ra, must bây giờ được đánh vần là .... (Trước đây nó cũng có thể được đánh vần là . . ., chỉ do sự ngẫu nhiên về ngữ pháp.)

Cú pháp đã xóa

  • PEP 3113: Đã xóa giải nén tham số Tuple. Bạn không thể viết def foo(a, (b, c)): ... nữa. Thay vào đó hãy sử dụng def foo(a, b_c): b, c = b_c.

  • Đã xóa backticks (thay vào đó hãy sử dụng repr()).

  • Đã xóa <> (thay vào đó hãy sử dụng !=).

  • Từ khóa đã xóa: exec() không còn là từ khóa; nó vẫn còn như một chức năng. (May mắn thay, cú pháp hàm cũng được chấp nhận trong 2.x.) Cũng lưu ý rằng exec() không còn nhận đối số luồng nữa; thay vì exec(f) bạn có thể sử dụng exec(f.read()).

  • Chữ nguyên không còn hỗ trợ l hoặc L ở cuối.

  • Chuỗi ký tự không còn hỗ trợ u hoặc U hàng đầu nữa.

  • Cú pháp from module import * chỉ được phép ở cấp mô-đun, không còn bên trong các hàm.

  • Cú pháp duy nhất được chấp nhận để nhập tương đối là from .[module] import name. Tất cả các dạng import không bắt đầu bằng . đều được hiểu là nhập tuyệt đối. (PEP 328)

  • Các lớp học cổ điển đã biến mất.

Những thay đổi đã có trong Python 2.6

Vì nhiều người dùng có lẽ đã chuyển thẳng từ Python 2.5 sang Python 3.0, nên phần này nhắc nhở người đọc về các tính năng mới ban đầu được thiết kế cho Python 3.0 nhưng đã được chuyển ngược sang Python 2.6. Nên tham khảo các phần tương ứng trong Có gì mới trong Python 2.6 để có mô tả dài hơn.

Thay đổi thư viện

Do hạn chế về thời gian, tài liệu này không đề cập đầy đủ những thay đổi sâu rộng đối với thư viện chuẩn. PEP 3108 là tài liệu tham khảo cho những thay đổi lớn đối với thư viện. Đây là một đánh giá viên nang:

  • Nhiều mô-đun cũ đã bị loại bỏ. Một số, như gopherlib (không còn được sử dụng) và md5 (được thay thế bằng hashlib), đã không còn được dùng nữa bởi PEP 4. Một số khác đã bị xóa do không còn hỗ trợ cho nhiều nền tảng khác nhau như Irix, BeOS và Mac OS 9 (xem PEP 11). Một số mô-đun cũng đã được chọn để xóa trong Python 3.0 do không được sử dụng hoặc do có sự thay thế tốt hơn. Xem PEP 3108 để biết danh sách đầy đủ.

  • Gói bsddb3 đã bị xóa vì sự hiện diện của nó trong thư viện tiêu chuẩn cốt lõi theo thời gian đã chứng tỏ là gánh nặng đặc biệt đối với các nhà phát triển cốt lõi do tính không ổn định của quá trình kiểm tra và lịch phát hành của Berkeley DB. Tuy nhiên, gói hàng vẫn hoạt động tốt, được bảo trì bên ngoài tại https://www.jcea.es/programacion/pybsddb.htm.

  • Một số mô-đun đã được đổi tên vì tên cũ của chúng không tuân theo PEP 8 hoặc vì nhiều lý do khác. Đây là danh sách:

    Tên cũ

    Tên mới

    _winreg

    winreg

    Trình phân tích cú pháp cấu hình

    trình phân tích cú pháp cấu hình

    sao chép_reg

    sao chép

    Hàng đợi

    xếp hàng

    Máy chủ ổ cắm

    máy chủ ổ cắm

    cơ sở đánh dấu

    _markupbase

    đại diện

    viết lại

    kiểm tra.test_support

    kiểm tra.support

  • Mẫu phổ biến trong Python 2.x là có một phiên bản mô-đun được triển khai bằng Python thuần túy, với phiên bản tăng tốc tùy chọn được triển khai dưới dạng phần mở rộng C; ví dụ: picklecPickle. Điều này đặt gánh nặng nhập phiên bản tăng tốc và quay lại phiên bản Python thuần túy cho mỗi người dùng của các mô-đun này. Trong Python 3.0, các phiên bản tăng tốc được coi là chi tiết triển khai của các phiên bản Python thuần túy. Người dùng phải luôn nhập phiên bản tiêu chuẩn, phiên bản này sẽ cố gắng nhập phiên bản tăng tốc và quay lại phiên bản Python thuần túy. Cặp pickle/cPickle nhận được cách xử lý này. Mô-đun profile nằm trong danh sách dành cho phiên bản 3.1. Mô-đun StringIO đã được chuyển thành một lớp trong mô-đun io.

  • Một số mô-đun liên quan đã được nhóm thành các gói và thông thường tên mô-đun con đã được đơn giản hóa. Các gói mới kết quả là:

    • dbm (anydbm, dbhash, dbm, dumbdbm, gdbm, whichdb).

    • html (HTMLParser, htmlentitydefs).

    • http (httplib, BaseHTTPServer, CGIHTTPServer, SimpleHTTPServer, Cookie, cookielib).

    • tkinter (tất cả các mô-đun liên quan đến Tkinter ngoại trừ turtle). Đối tượng mục tiêu của turtle không thực sự quan tâm đến tkinter. Cũng lưu ý rằng kể từ Python 2.6, chức năng của turtle đã được nâng cao đáng kể.

    • urllib (urllib, urllib2, urlparse, robotparse).

    • xmlrpc (xmlrpclib, DocXMLRPCServer, SimpleXMLRPCServer).

Một số thay đổi khác đối với mô-đun thư viện tiêu chuẩn, không được PEP 3108 đề cập:

  • Đã giết sets. Sử dụng lớp set() tích hợp.

  • Dọn dẹp mô-đun sys: đã xóa sys.exitfunc(), sys.exc_clear(), sys.exc_type, sys.exc_value, sys.exc_traceback. (Lưu ý rằng sys.last_type, v.v. vẫn còn.)

  • Dọn dẹp loại array.array: các phương thức read()write() không còn nữa; thay vào đó hãy sử dụng fromfile()tofile(). Ngoài ra, mã kiểu 'c' cho mảng không còn nữa -- hãy sử dụng 'b' cho byte hoặc 'u' cho ký tự Unicode.

  • Dọn dẹp mô-đun operator: loại bỏ sequenceIncludes()isCallable().

  • Dọn dẹp mô-đun thread: acquire_lock()release_lock() không còn nữa; thay vào đó hãy sử dụng acquire()release().

  • Dọn dẹp mô-đun random: đã xóa jumpahead() API.

  • Mô-đun new đã biến mất.

  • Các chức năng os.tmpnam(), os.tempnam()os.tmpfile() đã bị loại bỏ để thay thế cho mô-đun tempfile.

  • Mô-đun tokenize đã được thay đổi để hoạt động với byte. Điểm vào chính bây giờ là tokenize.tokenize(), thay vì generate_tokens.

  • string.letters và những người bạn của nó (string.lowercasestring.uppercase) đã biến mất. Thay vào đó hãy sử dụng string.ascii_letters, v.v. (Lý do xóa là string.letters và bạn bè có hành vi cụ thể theo địa phương, đây là một ý tưởng tồi đối với các "hằng số" toàn cầu được đặt tên hấp dẫn như vậy.)

  • Đã đổi tên mô-đun __builtin__ thành builtins (xóa dấu gạch dưới, thêm 's'). Biến __builtins__ được tìm thấy trong hầu hết các không gian tên chung không thay đổi. Để sửa đổi nội dung, bạn nên sử dụng builtins, không phải __builtins__!

PEP 3101: Một cách tiếp cận mới để định dạng chuỗi

  • Một hệ thống mới dành cho các hoạt động định dạng chuỗi tích hợp sẽ thay thế toán tử định dạng chuỗi %. (Tuy nhiên, toán tử % vẫn được hỗ trợ; nó sẽ không được dùng nữa trong Python 3.1 và bị xóa khỏi ngôn ngữ sau này.) Đọc PEP 3101 để biết thông tin đầy đủ.

Thay đổi ngoại lệ

Các API để phát hiện và bắt ngoại lệ đã được cải tiến và bổ sung các tính năng mạnh mẽ mới:

  • PEP 352: Tất cả các ngoại lệ phải được bắt nguồn (trực tiếp hoặc gián tiếp) từ BaseException. Đây là gốc của hệ thống phân cấp ngoại lệ. Đây không phải là một đề xuất mới, nhưng requirement kế thừa từ BaseException là mới. (Python 2.6 vẫn cho phép nâng cấp các lớp cổ điển và không đặt ra hạn chế nào đối với những gì bạn có thể bắt được.) Kết quả là, các ngoại lệ chuỗi cuối cùng đã thực sự bị loại bỏ.

  • Hầu như tất cả các trường hợp ngoại lệ thực sự đều bắt nguồn từ Exception; BaseException chỉ nên được sử dụng làm lớp cơ sở cho các trường hợp ngoại lệ chỉ nên được xử lý ở cấp cao nhất, chẳng hạn như SystemExit hoặc KeyboardInterrupt. Thành ngữ được đề xuất để xử lý tất cả các trường hợp ngoại lệ ngoại trừ danh mục sau này là sử dụng except Exception.

  • StandardError đã bị xóa.

  • Các ngoại lệ không còn hoạt động như một chuỗi nữa. Thay vào đó hãy sử dụng thuộc tính args.

  • PEP 3109: Đưa ra ngoại lệ. Bây giờ bạn phải sử dụng raise Exception(args) thay vì raise Exception, args. Ngoài ra, bạn không còn có thể chỉ định rõ ràng truy nguyên; thay vào đó, nếu bạn have thực hiện việc này, bạn có thể gán trực tiếp cho thuộc tính __traceback__ (xem bên dưới).

  • PEP 3110: Bắt ngoại lệ. Bây giờ bạn phải sử dụng except SomeException as variable thay vì except SomeException, variable. Hơn nữa, variable bị xóa rõ ràng khi còn lại khối except.

  • PEP 3134: Chuỗi ngoại lệ. Có hai trường hợp: chuỗi ngầm và chuỗi rõ ràng. Chuỗi ngầm định xảy ra khi một ngoại lệ được đưa ra trong khối xử lý except hoặc finally. Điều này thường xảy ra do lỗi trong khối xử lý; chúng tôi gọi đây là ngoại lệ secondary. Trong trường hợp này, ngoại lệ ban đầu (đang được xử lý) được lưu dưới dạng thuộc tính __context__ của ngoại lệ phụ. Chuỗi rõ ràng được gọi bằng cú pháp này

    nâng cao Ngoại lệ phụ() từ ngoại lệ chính
    

    (trong đó primary_exception là bất kỳ biểu thức nào tạo ra một đối tượng ngoại lệ, có thể là một ngoại lệ đã được phát hiện trước đó). Trong trường hợp này, ngoại lệ chính được lưu trữ trên thuộc tính __cause__ của ngoại lệ phụ. Truy nguyên được in khi xảy ra một ngoại lệ chưa được xử lý sẽ đi theo chuỗi thuộc tính __cause____context__ và in một truy nguyên riêng cho từng thành phần của chuỗi, với ngoại lệ chính ở trên cùng. (Người dùng Java có thể nhận ra hành vi này.)

  • PEP 3134: Các đối tượng ngoại lệ hiện lưu trữ dấu vết của chúng dưới dạng thuộc tính __traceback__. Điều này có nghĩa là một đối tượng ngoại lệ hiện chứa tất cả thông tin liên quan đến một ngoại lệ và có ít lý do hơn để sử dụng sys.exc_info() (mặc dù lý do sau không bị xóa).

  • Một số thông báo ngoại lệ được cải thiện khi Windows không tải được mô-đun mở rộng. Ví dụ: error code 193 bây giờ là %1 is not a valid Win32 application. Các chuỗi hiện xử lý các ngôn ngữ không phải tiếng Anh.

Những thay đổi khác

Toán tử và phương pháp đặc biệt

  • != hiện trả về kết quả ngược lại với ==, trừ khi == trả về NotImplemented.

  • Khái niệm "phương pháp không liên kết" đã bị xóa khỏi ngôn ngữ. Khi tham chiếu một phương thức dưới dạng thuộc tính lớp, bây giờ bạn sẽ có được một đối tượng hàm đơn giản.

  • __getslice__(), __setslice__()__delslice__() đã bị giết. Cú pháp a[i:j] hiện được dịch thành a.__getitem__(slice(i, j)) (hoặc __setitem__() hoặc __delitem__(), khi được sử dụng làm mục tiêu gán hoặc xóa tương ứng).

  • PEP 3114: phương thức next() tiêu chuẩn đã được đổi tên thành __next__().

  • Các phương thức đặc biệt __oct__()__hex__() bị loại bỏ -- oct()hex() sử dụng __index__() ngay bây giờ để chuyển đổi đối số thành số nguyên.

  • Đã xóa hỗ trợ cho __members____methods__.

  • Các thuộc tính hàm có tên func_X đã được đổi tên để sử dụng dạng __X__, giải phóng các tên này trong không gian tên thuộc tính hàm cho các thuộc tính do người dùng xác định. Nói một cách ngắn gọn, func_closure, func_code, func_defaults, func_dict, func_doc, func_globals, func_name lần lượt được đổi tên thành __closure__, __code__, __defaults__, __dict__, __doc__, __globals__, __name__.

  • __nonzero__() bây giờ là __bool__().

Nội dung

  • PEP 3135: super() mới. Bây giờ bạn có thể gọi super() mà không cần đối số và (giả sử đây là một phương thức phiên bản thông thường được xác định bên trong câu lệnh class), lớp và phiên bản phù hợp sẽ tự động được chọn. Với các đối số, hành vi của super() không thay đổi.

  • PEP 3111: raw_input() được đổi tên thành input(). Tức là, hàm input() mới đọc một dòng từ sys.stdin và trả về dòng đó với dòng mới ở cuối đã bị loại bỏ. Nó tăng EOFError nếu đầu vào bị chấm dứt sớm. Để có được hành vi cũ của input(), hãy sử dụng eval(input()).

  • Một hàm tích hợp mới next() đã được thêm vào để gọi phương thức __next__() trên một đối tượng.

  • Chiến lược làm tròn hàm round() và kiểu trả về đã thay đổi. Các trường hợp chính xác ở giữa giờ đây được làm tròn đến kết quả chẵn gần nhất thay vì cách xa 0. (Ví dụ: round(2.5) hiện trả về 2 thay vì 3.) round(x[, n]) hiện ủy quyền cho x.__round__([n]) thay vì luôn trả về một float. Nó thường trả về một số nguyên khi được gọi với một đối số duy nhất và một giá trị cùng loại với x khi được gọi với hai đối số.

  • Đã chuyển intern() sang sys.intern().

  • Đã xóa: apply(). Thay vì apply(f, args) hãy sử dụng f(*args).

  • Đã xóa callable(). Thay vì callable(f) bạn có thể sử dụng isinstance(f, collections.Callable). Chức năng operator.isCallable() cũng không còn nữa.

  • Đã xóa coerce(). Chức năng này không còn phục vụ mục đích nữa khi các lớp cổ điển không còn nữa.

  • Đã xóa execfile(). Thay vì execfile(fn) hãy sử dụng exec(open(fn).read()).

  • Đã xóa loại file. Sử dụng open(). Hiện có một số loại luồng khác nhau có thể mở trong mô-đun io.

  • Đã xóa reduce(). Sử dụng functools.reduce() nếu bạn thực sự cần nó; tuy nhiên, 99% trường hợp, vòng lặp for rõ ràng sẽ dễ đọc hơn.

  • Đã xóa reload(). Sử dụng imp.reload().

  • Đã xóa. dict.has_key() -- thay vào đó hãy sử dụng toán tử in.

Xây dựng và thay đổi C API

Do hạn chế về thời gian, đây là danh sách không đầy đủ các thay đổi của very đối với C API.

  • Hỗ trợ cho một số nền tảng đã bị loại bỏ, bao gồm nhưng không giới hạn ở Mac OS 9, BeOS, RISCOS, Irix và Tru64.

  • PEP 3118: Bộ đệm mới API.

  • PEP 3121: Khởi tạo và hoàn thiện mô-đun mở rộng.

  • PEP 3123: Làm cho PyObject_HEAD phù hợp với tiêu chuẩn C.

  • Không còn hỗ trợ C API cho việc thực thi bị hạn chế.

  • Các API PyNumber_Coerce(), PyNumber_CoerceEx(), PyMember_Get()PyMember_Set() C bị xóa.

  • C API PyImport_ImportModuleNoBlock() mới, hoạt động giống như PyImport_ImportModule() nhưng không chặn khóa nhập (thay vào đó trả về lỗi).

  • Đã đổi tên khe và phương thức cấp C chuyển đổi boolean: nb_nonzero hiện là nb_bool.

  • Đã xóa METH_OLDARGSWITH_CYCLE_GC khỏi C API.

Hiệu suất

Kết quả cuối cùng của việc khái quát hóa 3.0 là Python 3.0 chạy điểm chuẩn pystone chậm hơn khoảng 10% so với Python 2.5. Rất có thể nguyên nhân lớn nhất là việc loại bỏ lớp vỏ đặc biệt dành cho số nguyên nhỏ. Vẫn còn chỗ để cải thiện, nhưng điều đó sẽ xảy ra sau khi phiên bản 3.0 được phát hành!

Chuyển sang Python 3.0

Để chuyển mã nguồn Python 2.5 hoặc 2.6 hiện có sang Python 3.0, chiến lược tốt nhất là như sau:

  1. (Điều kiện tiên quyết:) Bắt đầu với phạm vi kiểm tra xuất sắc.

  2. Chuyển sang Python 2.6. Điều này sẽ không hiệu quả hơn cổng trung bình từ Python 2.x đến Python 2.(x+1). Hãy chắc chắn rằng tất cả các bài kiểm tra của bạn vượt qua.

  3. (Vẫn đang sử dụng 2.6 :) Bật công tắc dòng lệnh -3. Điều này cho phép cảnh báo về các tính năng sẽ bị xóa (hoặc thay đổi) trong phiên bản 3.0. Chạy lại bộ thử nghiệm của bạn và sửa mã mà bạn nhận được cảnh báo cho đến khi không còn cảnh báo nào và tất cả các thử nghiệm của bạn vẫn vượt qua.

  4. Chạy trình dịch nguồn sang nguồn 2to3 trên cây mã nguồn của bạn. Chạy kết quả dịch trong Python 3.0. Khắc phục thủ công mọi vấn đề còn lại, khắc phục sự cố cho đến khi tất cả các bài kiểm tra đều vượt qua.

Bạn không nên thử viết mã nguồn chạy không thay đổi trong cả Python 2.6 và 3.0; bạn sẽ phải sử dụng một phong cách mã hóa rất méo mó, ví dụ: tránh các câu lệnh print, siêu dữ liệu, v.v. Nếu bạn đang duy trì một thư viện cần hỗ trợ cả Python 2.6 và Python 3.0, cách tiếp cận tốt nhất là sửa đổi bước 3 ở trên bằng cách chỉnh sửa phiên bản 2.6 của mã nguồn và chạy lại trình dịch 2to3, thay vì chỉnh sửa phiên bản 3.0 của mã nguồn.

Để chuyển các tiện ích mở rộng C sang Python 3.0, vui lòng xem Chuyển các mô-đun mở rộng sang Python 3.