Có gì mới trong Python 2.1

tác giả:

A.M. Kuchling

Giới thiệu

Bài viết này giải thích các tính năng mới trong Python 2.1. Mặc dù không có nhiều thay đổi trong phiên bản 2.1 như trong Python 2.0 nhưng vẫn có một số điều bất ngờ thú vị đang chờ đợi. 2.1 là bản phát hành đầu tiên được định hướng thông qua việc sử dụng Đề xuất cải tiến Python hoặc PEP, vì vậy hầu hết các thay đổi lớn đều có PEP đi kèm cung cấp tài liệu đầy đủ hơn và cơ sở thiết kế cho thay đổi. Bài viết này không cố gắng ghi lại đầy đủ các tính năng mới mà chỉ cung cấp thông tin tổng quan về các tính năng mới dành cho lập trình viên Python. Tham khảo tài liệu Python 2.1 hoặc PEP cụ thể để biết thêm chi tiết về bất kỳ tính năng mới nào mà bạn đặc biệt quan tâm.

Một mục tiêu gần đây của nhóm phát triển Python là đẩy nhanh tốc độ phát hành các bản phát hành mới, với bản phát hành mới sẽ ra mắt sau mỗi 6 đến 9 tháng. 2.1 là bản phát hành đầu tiên ra mắt với tốc độ nhanh hơn, với bản alpha đầu tiên xuất hiện vào tháng 1, 3 tháng sau khi phiên bản cuối cùng của 2.0 được phát hành.

Bản phát hành cuối cùng của Python 2.1 được thực hiện vào ngày 17 tháng 4 năm 2001.

PEP 227: Phạm vi lồng nhau

Thay đổi lớn nhất trong Python 2.1 là các quy tắc xác định phạm vi của Python. Trong Python 2.0, tại bất kỳ thời điểm nào cũng có tối đa ba không gian tên được sử dụng để tra cứu tên biến: cục bộ, cấp độ mô-đun và không gian tên tích hợp. Điều này thường khiến mọi người ngạc nhiên vì nó không phù hợp với mong đợi trực quan của họ. Ví dụ: định nghĩa hàm đệ quy lồng nhau không hoạt động:

chắc chắn f():
    ...
    def g(giá trị):
        ...
        trả về g(giá trị-1) + 1
    ...

Hàm g() sẽ luôn đưa ra một ngoại lệ NameError, vì ràng buộc của tên g không nằm trong không gian tên cục bộ hoặc trong không gian tên cấp mô-đun. Đây không phải là vấn đề lớn trong thực tế (bạn có thường xuyên xác định đệ quy các hàm bên trong như thế này không?), nhưng điều này cũng khiến việc sử dụng biểu thức lambda trở nên vụng về hơn và đây là một vấn đề trong thực tế. Trong mã sử dụng lambda, bạn thường có thể thấy các biến cục bộ đang được sao chép bằng cách chuyển chúng làm giá trị mặc định của đối số.

def find(bản thân, tên):
    "Trả về danh sách của bất kỳ mục nào bằng 'tên'"
    L = filter(lambda x, name=name: x == name,
               self.list_attribute)
    trả lại L

Kết quả là khả năng đọc mã Python được viết theo phong cách chức năng mạnh mẽ bị ảnh hưởng rất nhiều.

Thay đổi quan trọng nhất đối với Python 2.1 là phạm vi tĩnh đã được thêm vào ngôn ngữ để khắc phục sự cố này. Hiệu ứng đầu tiên là đối số mặc định name=name hiện không còn cần thiết trong ví dụ trên. Nói một cách đơn giản, khi một tên biến nhất định không được gán giá trị trong một hàm (bằng một phép gán hoặc các câu lệnh def, class hoặc import), các tham chiếu đến biến đó sẽ được tra cứu trong không gian tên cục bộ của phạm vi kèm theo. Bạn có thể tìm thấy giải thích chi tiết hơn về các quy tắc và phân tích cách triển khai trong PEP.

Thay đổi này có thể gây ra một số vấn đề về tính tương thích đối với mã trong đó tên biến giống nhau được sử dụng cả ở cấp mô-đun và dưới dạng biến cục bộ trong hàm chứa các định nghĩa hàm khác. Tuy nhiên, điều này có vẻ khó xảy ra vì mã như vậy sẽ khá khó hiểu ngay từ đầu.

Một tác dụng phụ của sự thay đổi này là các câu lệnh from module import *exec đã bị coi là bất hợp pháp trong phạm vi chức năng trong một số điều kiện nhất định. Hướng dẫn tham khảo Python đã nói rõ rằng from module import * chỉ hợp pháp ở cấp cao nhất của mô-đun, nhưng trình thông dịch CPython chưa bao giờ thực thi điều này trước đây. Là một phần của việc triển khai các phạm vi lồng nhau, trình biên dịch biến nguồn Python thành mã byte phải tạo mã khác nhau để truy cập các biến trong phạm vi chứa. from module import *exec khiến trình biên dịch không thể tìm ra điều này vì chúng thêm tên vào không gian tên cục bộ mà không thể biết được tại thời điểm biên dịch. Do đó, nếu một hàm chứa các định nghĩa hàm hoặc biểu thức lambda với các biến tự do, trình biên dịch sẽ gắn cờ hàm này bằng cách đưa ra một ngoại lệ SyntaxError.

Để làm cho lời giải thích trước đó rõ ràng hơn một chút, đây là một ví dụ:

x = 1
chắc chắn f():
    # The dòng tiếp theo là lỗi cú pháp
    thực thi 'x=2'
    chắc chắn g():
        trả lại x

Dòng 4 chứa câu lệnh exec là một lỗi cú pháp, vì exec sẽ xác định một biến cục bộ mới có tên là x mà giá trị của nó phải được truy cập bởi g().

Đây không phải là một hạn chế lớn, vì exec hiếm khi được sử dụng trong hầu hết các mã Python (và khi nó được sử dụng, đó thường là dấu hiệu của một thiết kế kém).

Những lo ngại về khả năng tương thích đã dẫn đến việc đưa ra phạm vi lồng nhau dần dần; trong Python 2.1, chúng không được bật theo mặc định nhưng có thể được bật trong mô-đun bằng cách sử dụng câu lệnh tương lai như được mô tả trong PEP 236. (Xem phần sau để thảo luận thêm về PEP 236.) Trong Python 2.2, phạm vi lồng nhau sẽ trở thành mặc định và sẽ không có cách nào để tắt chúng, nhưng người dùng sẽ có toàn bộ thời gian sử dụng của 2.1 để khắc phục mọi sự cố do phần giới thiệu của chúng.

Xem thêm

PEP 227 - Phạm vi lồng nhau tĩnh

Được viết và thực hiện bởi Jeremy Hylton.

PEP 236: __future__ Chỉ thị

Phản ứng đối với các phạm vi lồng nhau là mối lo ngại rộng rãi về sự nguy hiểm của việc phá mã với bản phát hành 2.1 và nó đủ mạnh để khiến Pythoneers thực hiện một cách tiếp cận thận trọng hơn. Cách tiếp cận này bao gồm việc giới thiệu một quy ước để kích hoạt chức năng tùy chọn trong bản phát hành N và sẽ trở thành bắt buộc trong bản phát hành N+1.

Cú pháp sử dụng câu lệnh from...import sử dụng tên mô-đun dành riêng __future__. Phạm vi lồng nhau có thể được kích hoạt bằng câu lệnh sau:

từ __future__ nhập lồng_scopes

Mặc dù nó trông giống như một câu lệnh import bình thường nhưng thực tế không phải vậy; có những quy định nghiêm ngặt về nơi có thể đưa ra tuyên bố tương lai như vậy. Chúng chỉ có thể ở đầu mô-đun và phải đứng trước bất kỳ mã Python hoặc câu lệnh import thông thường nào. Điều này là do các câu lệnh như vậy có thể ảnh hưởng đến cách trình biên dịch mã byte Python phân tích mã và tạo mã byte, vì vậy chúng phải đặt trước bất kỳ câu lệnh nào dẫn đến mã byte được tạo ra.

Xem thêm

PEP 236 - Quay lại __future__

Được viết bởi Tim Peters và chủ yếu được thực hiện bởi Jeremy Hylton.

PEP 207: So sánh phong phú

Trong các phiên bản trước, sự hỗ trợ của Python để thực hiện so sánh trên các lớp do người dùng định nghĩa và các kiểu mở rộng khá đơn giản. Các lớp có thể triển khai phương thức __cmp__() được cung cấp hai phiên bản của một lớp và chỉ có thể trả về 0 nếu chúng bằng nhau hoặc +1 hoặc -1 nếu không; phương thức không thể đưa ra một ngoại lệ hoặc trả về bất cứ thứ gì ngoài giá trị Boolean. Người dùng Python số thường thấy mô hình này quá yếu và hạn chế, bởi vì trong các chương trình xử lý số mà Python số được sử dụng, sẽ hữu ích hơn nếu có thể thực hiện so sánh theo từng phần tử của hai ma trận, trả về một ma trận chứa kết quả của một phép so sánh nhất định cho từng phần tử. Nếu hai ma trận có kích thước khác nhau thì phép so sánh phải có khả năng đưa ra một ngoại lệ để báo hiệu lỗi.

Trong Python 2.1, các so sánh phong phú đã được thêm vào để hỗ trợ nhu cầu này. Giờ đây, các lớp Python có thể nạp chồng riêng lẻ từng thao tác <, <=, >, >=, ==!=. Tên phương thức ma thuật mới là:

hoạt động

Tên phương thức

<

__lt__()

<=

__le__()

>

__gt__()

>=

__ge__()

==

__eq__()

!=

__ne__()

(Các phương thức ma thuật được đặt theo tên của các toán tử Fortran tương ứng .LT.. .LE., &c. Các lập trình viên số gần như chắc chắn khá quen thuộc với những cái tên này và sẽ thấy chúng dễ nhớ.)

Mỗi phương thức ma thuật này đều có dạng method(self, other), trong đó self sẽ là đối tượng ở phía bên trái của toán tử, trong khi other sẽ là đối tượng ở phía bên phải. Ví dụ: biểu thức A < B sẽ khiến A.__lt__(B) được gọi.

Mỗi phương thức ma thuật này có thể trả về bất kỳ thứ gì: Boolean, ma trận, danh sách hoặc bất kỳ đối tượng Python nào khác. Ngoài ra, họ có thể đưa ra một ngoại lệ nếu việc so sánh là không thể, không nhất quán hoặc vô nghĩa.

Hàm cmp(A,B) tích hợp có thể sử dụng bộ máy so sánh phong phú và hiện chấp nhận một đối số tùy chọn chỉ định thao tác so sánh nào sẽ sử dụng; cái này được đưa ra dưới dạng một trong các chuỗi "<", "<=", ">", ">=", "==" hoặc "!=". Nếu được gọi mà không có đối số thứ ba tùy chọn, cmp() sẽ chỉ trả về -1, 0 hoặc +1 như trong các phiên bản trước của Python; nếu không nó sẽ gọi phương thức thích hợp và có thể trả về bất kỳ đối tượng Python nào.

Ngoài ra còn có những thay đổi tương ứng được các lập trình viên C quan tâm; có một vị trí tp_richcmp mới trong các đối tượng loại và một API để thực hiện một phép so sánh phong phú nhất định. Tôi sẽ không đề cập đến C API ở đây mà sẽ giới thiệu cho bạn PEP 207 hoặc tài liệu C API của 2.1 để biết danh sách đầy đủ các chức năng liên quan.

Xem thêm

PEP 207 - So sánh phong phú

Được viết bởi Guido van Rossum, chủ yếu dựa trên tác phẩm trước đó của David Ascher và được thực hiện bởi Guido van Rossum.

PEP 230: Khung cảnh báo

Trong suốt 10 năm tồn tại, Python đã tích lũy được một số mô-đun và tính năng lỗi thời nhất định trong quá trình phát triển. Thật khó để biết khi nào một tính năng là an toàn để xóa, vì không có cách nào biết được lượng mã sử dụng nó --- có lẽ không có chương trình nào phụ thuộc vào tính năng này hoặc có lẽ nhiều chương trình phụ thuộc vào tính năng đó. Để cho phép loại bỏ các tính năng cũ theo cách có cấu trúc hơn, khung cảnh báo đã được thêm vào. Khi các nhà phát triển Python muốn loại bỏ một tính năng, trước tiên nó sẽ kích hoạt cảnh báo trong phiên bản tiếp theo của Python. Sau đó, phiên bản Python sau đây có thể loại bỏ tính năng này và người dùng sẽ có chu kỳ phát hành đầy đủ để loại bỏ việc sử dụng tính năng cũ.

Python 2.1 bổ sung khung cảnh báo sẽ được sử dụng trong sơ đồ này. Nó bổ sung thêm mô-đun warnings cung cấp các chức năng đưa ra cảnh báo và lọc ra các cảnh báo mà bạn không muốn hiển thị. Các mô-đun của bên thứ ba cũng có thể sử dụng khung này để loại bỏ các tính năng cũ mà họ không muốn hỗ trợ nữa.

Ví dụ: trong Python 2.1, mô-đun regex không được dùng nữa, do đó việc nhập mô-đun này sẽ khiến cảnh báo được in

>>> nhập biểu thức chính quy
__main__:1: Không dùng nữaCảnh báo: mô-đun biểu thức chính quy
         không còn được dùng nữa; vui lòng sử dụng mô-đun re
>>>

Cảnh báo có thể được đưa ra bằng cách gọi hàm warnings.warn()

Warning.warn("Tính năng X không còn được hỗ trợ")

Tham số đầu tiên là thông báo cảnh báo; một tham số tùy chọn bổ sung có thể được sử dụng để chỉ định một danh mục cảnh báo cụ thể.

Bộ lọc có thể được thêm vào để tắt một số cảnh báo nhất định; một mẫu biểu thức chính quy có thể được áp dụng cho thông báo hoặc tên mô-đun để chặn cảnh báo. Ví dụ: bạn có thể có một chương trình sử dụng mô-đun regex và không muốn dành thời gian chuyển đổi nó để sử dụng mô-đun re ngay bây giờ. Cảnh báo có thể được loại bỏ bằng cách gọi

cảnh báo nhập khẩu
Warning.filterwarnings(action = 'bỏ qua',
                        message='.*mô-đun biểu thức chính quy không được dùng nữa',
                        Category=Không dùng nữaCảnh báo,
                        -đun = '__ chính__')

Điều này thêm một bộ lọc sẽ chỉ áp dụng cho các cảnh báo của lớp DeprecationWarning được kích hoạt trong mô-đun __main__ và áp dụng biểu thức chính quy để chỉ khớp với thông báo về mô-đun regex không được dùng nữa và sẽ khiến các cảnh báo đó bị bỏ qua. Cảnh báo cũng chỉ có thể được in một lần, in mỗi khi mã vi phạm được thực thi hoặc chuyển thành ngoại lệ khiến chương trình dừng lại (tất nhiên trừ khi các ngoại lệ được phát hiện theo cách thông thường).

Các chức năng cũng được thêm vào C API của Python để đưa ra cảnh báo; tham khảo PEP 230 hoặc tài liệu API của Python để biết chi tiết.

Xem thêm

PEP 5 - Hướng dẫn tiến hóa ngôn ngữ

Được viết bởi Paul Prescod, để chỉ định các quy trình cần tuân theo khi xóa các tính năng cũ khỏi Python. Chính sách được mô tả trong PEP này vẫn chưa được áp dụng chính thức, nhưng chính sách cuối cùng có thể sẽ không quá khác biệt so với đề xuất của Prescod.

PEP 230 - Khung cảnh báo

Được viết và thực hiện bởi Guido van Rossum.

PEP 229: Hệ thống xây dựng mới

Khi biên dịch Python, người dùng phải vào và chỉnh sửa tệp Modules/Setup để kích hoạt nhiều mô-đun bổ sung khác nhau; bộ mặc định tương đối nhỏ và giới hạn ở các mô-đun biên dịch trên hầu hết các nền tảng Unix. Điều này có nghĩa là trên nền tảng Unix có nhiều tính năng hơn, đặc biệt là Linux, các bản cài đặt Python thường không chứa tất cả các mô-đun hữu ích mà chúng có thể có.

Python 2.0 đã thêm Distutils, một bộ mô-đun để phân phối và cài đặt các tiện ích mở rộng. Trong Python 2.1, Distutils được sử dụng để biên dịch phần lớn thư viện tiêu chuẩn của các mô-đun mở rộng, tự động phát hiện những mô-đun nào được hỗ trợ trên máy hiện tại. Hy vọng rằng điều này sẽ giúp việc cài đặt Python dễ dàng hơn và nhiều tính năng hơn.

Thay vì phải chỉnh sửa tệp Modules/Setup để kích hoạt mô-đun, tập lệnh setup.py trong thư mục trên cùng của bản phân phối nguồn Python được chạy tại thời điểm xây dựng và cố gắng khám phá mô-đun nào có thể được kích hoạt bằng cách kiểm tra các mô-đun và tệp tiêu đề trên hệ thống. Nếu một mô-đun được định cấu hình trong Modules/Setup, tập lệnh setup.py sẽ không cố gắng biên dịch mô-đun đó và sẽ tuân theo nội dung của tệp Modules/Setup. Điều này cung cấp một cách để chỉ định bất kỳ cờ hoặc thư viện dòng lệnh lạ nào được yêu cầu cho một nền tảng cụ thể.

Trong một thay đổi sâu rộng khác đối với cơ chế xây dựng, Neil Schenauer đã cơ cấu lại mọi thứ để Python hiện sử dụng một tệp tạo tệp duy nhất không đệ quy, thay vì các tệp tạo tệp trong thư mục trên cùng và trong mỗi thư mục con Python/, Parser/, Objects/Modules/. Điều này giúp việc xây dựng Python nhanh hơn và cũng giúp việc hack Makefiles trở nên rõ ràng và đơn giản hơn.

Xem thêm

PEP 229 - Sử dụng Distutils để xây dựng Python

Được viết và thực hiện bởi A.M. Kuchling.

PEP 205: Tài liệu tham khảo yếu

Các tham chiếu yếu, có sẵn thông qua mô-đun weakref, là một kiểu dữ liệu mới nhỏ nhưng hữu ích trong hộp công cụ của lập trình viên Python.

Việc lưu trữ một tham chiếu đến một đối tượng (chẳng hạn như trong từ điển hoặc một danh sách) có tác dụng phụ là giữ cho đối tượng đó tồn tại mãi mãi. Có một số trường hợp cụ thể trong đó hành vi này là không mong muốn, bộ nhớ đệm đối tượng là trường hợp phổ biến nhất và một trường hợp khác là tham chiếu vòng tròn trong các cấu trúc dữ liệu như cây.

Ví dụ: hãy xem xét một hàm ghi nhớ lưu trữ kết quả của một hàm khác f(x) bằng cách lưu trữ đối số của hàm và kết quả của nó trong một từ điển:

_bộ đệm = {}
def ghi nhớ (x):
    nếu _cache.has_key(x):
        trả về _cache[x]

    hồi quy = f(x)

    # Cache đối tượng được trả về
    _cache[x] = lấy lại

    trả lại

Phiên bản này hoạt động với những thứ đơn giản như số nguyên, nhưng nó có tác dụng phụ; từ điển _cache giữ tham chiếu đến các giá trị trả về, vì vậy chúng sẽ không bao giờ bị hủy phân bổ cho đến khi quá trình Python thoát và dọn sạch. Điều này không đáng chú ý lắm đối với số nguyên, nhưng nếu f() trả về một đối tượng hoặc cấu trúc dữ liệu chiếm nhiều bộ nhớ thì đây có thể là một vấn đề.

Các tham chiếu yếu cung cấp một cách để triển khai bộ đệm không giữ cho các đối tượng tồn tại vượt quá thời gian của chúng. Nếu một đối tượng chỉ có thể truy cập được thông qua các tham chiếu yếu, thì đối tượng đó sẽ bị hủy cấp phát và các tham chiếu yếu bây giờ sẽ chỉ ra rằng đối tượng mà nó tham chiếu đến không còn tồn tại. Tham chiếu yếu đến đối tượng obj được tạo bằng cách gọi wr = weakref.ref(obj). Đối tượng được tham chiếu sẽ được trả về bằng cách gọi tham chiếu yếu như thể nó là một hàm: wr(). Nó sẽ trả về đối tượng được tham chiếu hoặc None nếu đối tượng không còn tồn tại.

Điều này cho phép viết một hàm memoize() có bộ đệm không giữ cho các đối tượng tồn tại bằng cách lưu trữ các tham chiếu yếu trong bộ đệm.

_bộ đệm = {}
def ghi nhớ (x):
    nếu _cache.has_key(x):
        obj = _cache[x]()
        đối tượng tham chiếu yếu # If vẫn tồn tại,
        # return nó
        nếu obj không phải  Không: trả về obj

    hồi quy = f(x)

    # Cache một tài liệu tham khảo yếu
    _cache[x] = yếuref.ref(retval)

    trả lại

Mô-đun weakref cũng cho phép tạo các đối tượng proxy hoạt động giống như các tham chiếu yếu --- một đối tượng chỉ được tham chiếu bởi các đối tượng proxy sẽ bị hủy phân bổ -- nhưng thay vì yêu cầu một lệnh gọi rõ ràng để truy xuất đối tượng, proxy sẽ chuyển tiếp một cách minh bạch tất cả các hoạt động đến đối tượng miễn là đối tượng vẫn tồn tại. Nếu đối tượng bị hủy cấp phát, việc cố gắng sử dụng proxy sẽ gây ra ngoại lệ weakref.ReferenceError.

proxy = yếuref.proxy(obj)
proxy.attr # Equivalent tới obj.attr
proxy.meth() # Equivalent tới obj.meth()
del obj
proxy.attr # raises yếuref.ReferenceError

Xem thêm

PEP 205 - Tài liệu tham khảo yếu

Được viết và thực hiện bởi Fred L. Drake, Jr.

PEP 232: Thuộc tính chức năng

Trong Python 2.1, giờ đây các hàm có thể có thông tin tùy ý được đính kèm. Mọi người thường sử dụng chuỗi tài liệu để chứa thông tin về các hàm và phương thức, vì thuộc tính __doc__ là cách duy nhất để đính kèm bất kỳ thông tin nào vào một hàm. Ví dụ: trong máy chủ ứng dụng web Zope, các hàm được đánh dấu là an toàn để truy cập công cộng bằng cách có một chuỗi tài liệu và trong khung phân tích cú pháp SPARK của John Aycock, các chuỗi tài liệu giữ các phần của ngữ pháp BNF được phân tích cú pháp. Việc quá tải này thật đáng tiếc vì các chuỗi tài liệu thực sự nhằm mục đích chứa tài liệu của hàm; ví dụ: điều đó có nghĩa là bạn không thể ghi lại chính xác các chức năng dành cho mục đích sử dụng cá nhân trong Zope.

Giờ đây, các thuộc tính tùy ý có thể được đặt và truy xuất trên các hàm bằng cú pháp Python thông thường

def f(): vượt qua

f.xuất bản = 1
f.secure = 1
f.grammar = "A ::= B (C D)*"

Từ điển chứa các thuộc tính có thể được truy cập dưới dạng __dict__ của hàm. Không giống như thuộc tính __dict__ của các thể hiện của lớp, trong các hàm, bạn thực sự có thể gán một từ điển mới cho __dict__, mặc dù giá trị mới bị hạn chế đối với một từ điển Python thông thường; bạn can't hãy khéo léo và đặt nó thành một phiên bản UserDict hoặc bất kỳ đối tượng ngẫu nhiên nào khác hoạt động giống như một ánh xạ.

Xem thêm

PEP 232 - Thuộc tính chức năng

Được viết và thực hiện bởi Barry Warsaw.

PEP 235: Nhập mô-đun trên nền tảng không phân biệt chữ hoa chữ thường

Một số hệ điều hành có hệ thống tệp không phân biệt chữ hoa chữ thường, MacOS và Windows là những ví dụ chính; trên các hệ thống này, không thể phân biệt tên tệp FILE.PYfile.py, mặc dù chúng lưu tên tệp trong kiểu chữ gốc (chúng cũng được bảo quản kiểu chữ).

Trong Python 2.1, câu lệnh import sẽ hoạt động để mô phỏng phân biệt chữ hoa chữ thường trên các nền tảng không phân biệt chữ hoa chữ thường. Giờ đây, Python sẽ tìm kiếm kết quả khớp phân biệt chữ hoa chữ thường đầu tiên theo mặc định, đưa ra ImportError nếu không tìm thấy tệp nào như vậy, vì vậy import file sẽ không nhập mô-đun có tên FILE.PY. Có thể yêu cầu khớp không phân biệt chữ hoa chữ thường bằng cách đặt biến môi trường PYTHONCASEOK trước khi khởi động trình thông dịch Python.

PEP 217: Móc hiển thị tương tác

Khi sử dụng trình thông dịch Python một cách tương tác, đầu ra của các lệnh sẽ được hiển thị bằng hàm repr() tích hợp. Trong Python 2.1, biến sys.displayhook() có thể được đặt thành một đối tượng có thể gọi được, đối tượng này sẽ được gọi thay vì repr(). Ví dụ: bạn có thể đặt nó thành chức năng in đẹp đặc biệt

>>> # Create cấu trúc dữ liệu đệ quy
... L = [1,2,3]
>>> L.append(L)
>>> L # Show Đầu ra mặc định của Python
[1, 2, 3, […]]
>>> # Use pprint.pprint() làm chức năng hiển thị
... nhập sys, pprint
>>> sys.displayhook = pprint.pprint
>>> L
[1, 2, 3, <Đệ quy trong danh sách có id=135143996>]
>>>

Xem thêm

PEP 217 - Display Hook để sử dụng tương tác

Được viết và thực hiện bởi Moshe Zadka.

PEP 208: Mô hình cưỡng bức mới

Cách thực hiện ép buộc số ở cấp độ C đã được sửa đổi đáng kể. Điều này sẽ chỉ ảnh hưởng đến các tác giả của tiện ích mở rộng C cho Python, cho phép họ linh hoạt hơn trong việc viết các loại tiện ích mở rộng hỗ trợ các phép toán số.

Các loại tiện ích mở rộng hiện có thể đặt cờ loại Py_TPFLAGS_CHECKTYPES trong cấu trúc PyTypeObject của chúng để cho biết rằng chúng hỗ trợ mô hình cưỡng chế mới. Trong các loại tiện ích mở rộng như vậy, các hàm khe số không còn có thể giả định rằng chúng sẽ được truyền hai đối số cùng loại; thay vào đó, chúng có thể được truyền hai đối số thuộc các loại khác nhau và sau đó có thể thực hiện sự ép buộc nội bộ của riêng chúng. Nếu hàm vị trí được truyền một loại mà nó không thể xử lý, thì nó có thể chỉ ra lỗi bằng cách trả về một tham chiếu đến giá trị singleton Py_NotImplemented. Sau đó, các hàm số thuộc loại khác sẽ được thử và có lẽ chúng có thể xử lý được thao tác; nếu loại kia cũng trả về Py_NotImplemented thì TypeError sẽ được nâng lên. Các phương thức số được viết bằng Python cũng có thể trả về Py_NotImplemented, khiến trình thông dịch hoạt động như thể phương thức đó không tồn tại (có thể tạo ra một TypeError, có thể thử các phương thức số của đối tượng khác).

Xem thêm

PEP 208 - Làm lại mô hình cưỡng chế

Được viết và thực hiện bởi Neil Schenauer, dựa chủ yếu vào tác phẩm trước đó của Marc-André Lemburg. Đọc phần này để hiểu những điểm chính về cách xử lý các phép toán số ở cấp độ C.

PEP 241: Siêu dữ liệu trong gói Python

Lời phàn nàn phổ biến của người dùng Python là không có một danh mục duy nhất nào chứa tất cả các mô-đun Python. Vaults of Parnassus của T. Middleton tại www.vex.net/parnassus/ (đã ngừng hoạt động vào tháng 2 năm 2009, available in the Internet Archive Wayback Machine) là danh mục mô-đun Python lớn nhất, nhưng việc đăng ký phần mềm tại Vaults là tùy chọn và nhiều người không bận tâm.

Là bước nhỏ đầu tiên để khắc phục sự cố, phần mềm Python được đóng gói bằng lệnh Distutils sdist sẽ bao gồm một tệp có tên PKG-INFO chứa thông tin về gói như tên, phiên bản và tác giả (siêu dữ liệu, theo thuật ngữ lập danh mục). PEP 241 chứa danh sách đầy đủ các trường có thể có trong tệp PKG-INFO. Khi mọi người bắt đầu đóng gói phần mềm của họ bằng Python 2.1, ngày càng có nhiều gói sẽ bao gồm siêu dữ liệu, giúp xây dựng hệ thống danh mục tự động và thử nghiệm chúng. Với trải nghiệm thu được, có lẽ sẽ có thể thiết kế một danh mục thực sự tốt và sau đó xây dựng sự hỗ trợ cho nó bằng Python 2.2. Ví dụ: lệnh Distutils sdistbdist_* có thể hỗ trợ tùy chọn upload sẽ tự động tải gói hàng của bạn lên máy chủ danh mục.

Bạn có thể bắt đầu tạo các gói chứa PKG-INFO ngay cả khi bạn không sử dụng Python 2.1, vì bản phát hành Distutils mới sẽ được tạo cho người dùng các phiên bản Python cũ hơn. Phiên bản 1.0.2 của Distutils bao gồm những thay đổi được mô tả trong PEP 241, cũng như các bản sửa lỗi và cải tiến khác nhau. Nó sẽ có sẵn từ Distutils SIG tại https://www.python.org/community/sigs/current/distutils-sig/.

Xem thêm

PEP 241 - Siêu dữ liệu cho gói phần mềm Python

Được viết và thực hiện bởi A.M. Kuchling.

PEP 243 - Cơ chế tải lên kho lưu trữ mô-đun

Được viết bởi Sean Reifschneider, bản dự thảo PEP này mô tả một cơ chế được đề xuất để tải các gói Python lên máy chủ trung tâm.

Các mô-đun mới và cải tiến

  • Ka-Ping Yee đã đóng góp hai mô-đun mới: inspect.py, một mô-đun để nhận thông tin về mã Python trực tiếp và pydoc.py, một mô-đun để chuyển đổi các chuỗi tài liệu thành HTML hoặc văn bản một cách tương tác. Như một phần thưởng, Tools/scripts/pydoc, hiện được cài đặt tự động, sử dụng pydoc.py để hiển thị tài liệu được cung cấp tên mô-đun, gói hoặc lớp Python. Ví dụ: pydoc xml.dom hiển thị như sau:

    Tài liệu thư viện Python: gói xml.dom trong xml
    
    NAME
        xml.dom - Triển khai  hình đối tượng tài liệu W3C cho Python.
    
    FILE
        /usr/local/lib/python2.1/xml/dom/__init__.pyc
    
    DESCRIPTION
        Ánh xạ Python của  hình đối tượng tài liệu được ghi lại trong
        Tham khảo Thư viện Python trong phần trên gói xml.dom.
    
        Gói này chứa các -đun sau:
          ...
    

    pydoc cũng bao gồm trình duyệt trợ giúp tương tác dựa trên Tk. pydoc nhanh chóng trở nên gây nghiện; hãy thử nó!

  • Hai mô-đun khác nhau để kiểm tra đơn vị đã được thêm vào thư viện tiêu chuẩn. Mô-đun doctest do Tim Peters đóng góp cung cấp khung thử nghiệm dựa trên việc chạy các ví dụ được nhúng trong chuỗi tài liệu và so sánh kết quả với kết quả đầu ra dự kiến. PyUnit, do Steve Purcell đóng góp, là một khung thử nghiệm đơn vị được lấy cảm hứng từ JUnit, đến lượt nó là một phiên bản chuyển thể từ khung thử nghiệm Smalltalk của Kent Beck. Xem https://pyunit.sourceforge.net/ để biết thêm thông tin về PyUnit.

  • Mô-đun difflib chứa một lớp, SequenceMatcher, so sánh hai chuỗi và tính toán những thay đổi cần thiết để chuyển đổi chuỗi này thành chuỗi khác. Ví dụ: mô-đun này có thể được sử dụng để viết một công cụ tương tự như chương trình Unix diff và trên thực tế, chương trình mẫu Tools/scripts/ndiff.py minh họa cách viết một tập lệnh như vậy.

  • curses.panel, một trình bao bọc cho thư viện bảng điều khiển, một phần của ncurses và SYSV, được đóng góp bởi Thomas Gelekum. Thư viện bảng điều khiển cung cấp cho các cửa sổ tính năng bổ sung về độ sâu. Windows có thể được di chuyển cao hơn hoặc thấp hơn theo thứ tự độ sâu và thư viện bảng điều khiển sẽ tìm ra vị trí các bảng chồng lên nhau và phần nào hiển thị.

  • Gói PyXML đã trải qua một số bản phát hành kể từ Python 2.0 và Python 2.1 bao gồm phiên bản cập nhật của gói xml. Một số thay đổi đáng chú ý bao gồm hỗ trợ cho Expat 1.2 và các phiên bản mới hơn, khả năng trình phân tích cú pháp Expat xử lý các tệp ở bất kỳ mã hóa nào được Python hỗ trợ và các bản sửa lỗi khác nhau cho mô-đun SAX, DOM và minidom.

  • Ping cũng đóng góp một cách khác để xử lý các trường hợp ngoại lệ chưa được phát hiện. sys.excepthook() có thể được đặt thành một đối tượng có thể gọi được. Khi một ngoại lệ không bị bắt bởi bất kỳ khối try...except nào, ngoại lệ đó sẽ được chuyển đến sys.excepthook(), sau đó có thể làm bất cứ điều gì nó thích. Tại Hội nghị Python lần thứ 9, Ping đã trình diễn một ứng dụng cho hook này: in một truy ngược mở rộng không chỉ liệt kê các khung ngăn xếp mà còn liệt kê các đối số hàm và các biến cục bộ cho mỗi khung.

  • Các hàm khác nhau trong mô-đun time, chẳng hạn như asctime()localtime(), yêu cầu đối số dấu phẩy động chứa thời gian tính bằng giây kể từ kỷ nguyên. Cách sử dụng phổ biến nhất của các hàm này là làm việc với thời gian hiện tại, vì vậy đối số dấu phẩy động được đặt làm tùy chọn; khi giá trị không được cung cấp, thời gian hiện tại sẽ được sử dụng. Ví dụ: các mục nhập tệp nhật ký thường cần một chuỗi chứa thời gian hiện tại; trong Python 2.1, time.asctime() có thể được sử dụng thay vì time.asctime(time.localtime(time.time())) dài hơn được yêu cầu trước đây.

    Sự thay đổi này được đề xuất và thực hiện bởi Thomas Wouters.

  • Mô-đun ftplib hiện mặc định truy xuất tệp ở chế độ thụ động, vì chế độ thụ động có nhiều khả năng hoạt động từ phía sau tường lửa hơn. Yêu cầu này đến từ hệ thống theo dõi lỗi Debian, vì các gói Debian khác sử dụng ftplib để truy xuất tệp và sau đó không hoạt động sau tường lửa. Có vẻ như điều này sẽ không gây ra vấn đề cho bất kỳ ai vì Netscape mặc định ở chế độ thụ động và ít người phàn nàn, nhưng nếu chế độ thụ động không phù hợp với ứng dụng hoặc thiết lập mạng của bạn, hãy gọi set_pasv(0) trên các đối tượng FTP để tắt chế độ thụ động.

  • Hỗ trợ truy cập ổ cắm thô đã được thêm vào mô-đun socket, do Grant Edwards đóng góp.

  • Mô-đun pstats hiện chứa một trình duyệt thống kê tương tác đơn giản để hiển thị cấu hình thời gian cho các chương trình Python, được gọi khi mô-đun được chạy dưới dạng tập lệnh. Đóng góp bởi Eric S. Raymond.

  • Một hàm phụ thuộc vào việc triển khai mới, sys._getframe([depth]), đã được thêm vào để trả về một đối tượng khung nhất định từ ngăn xếp cuộc gọi hiện tại. sys._getframe() trả về khung ở đầu ngăn xếp cuộc gọi; nếu đối số số nguyên tùy chọn depth được cung cấp, hàm sẽ trả về khung được depth gọi bên dưới đầu ngăn xếp. Ví dụ: sys._getframe(1) trả về đối tượng khung của người gọi.

    Chức năng này chỉ có trong CPython, không có trong Jython hoặc triển khai .NET. Hãy sử dụng nó để gỡ lỗi và chống lại sự cám dỗ đưa nó vào mã sản xuất.

Những thay đổi và sửa lỗi khác

Có tương đối ít thay đổi nhỏ hơn được thực hiện trong Python 2.1 do chu kỳ phát hành ngắn hơn. Tìm kiếm trong nhật ký thay đổi của CVS cho thấy 117 bản vá được áp dụng và 136 lỗi đã được sửa; cả hai con số đều có khả năng bị đánh giá thấp. Một số thay đổi đáng chú ý hơn là:

  • Một bộ cấp phát đối tượng chuyên dụng hiện có sẵn tùy chọn, bộ cấp phát này sẽ nhanh hơn hệ thống malloc() và có ít chi phí bộ nhớ hơn. Bộ cấp phát sử dụng hàm malloc() của C để có được vùng bộ nhớ lớn, sau đó đáp ứng các yêu cầu bộ nhớ nhỏ hơn từ các vùng này. Nó có thể được kích hoạt bằng cách cung cấp tùy chọn --with-pymalloc cho tập lệnh configure; xem Objects/obmalloc.c để biết chi tiết triển khai.

    Tác giả của mô-đun mở rộng C nên kiểm tra mã của họ khi bật bộ cấp phát đối tượng, vì một số mã không chính xác có thể bị hỏng, gây ra hiện tượng kết xuất lõi trong thời gian chạy. Có một loạt hàm cấp phát bộ nhớ trong C API của Python trước đây chỉ là bí danh cho malloc()free() của thư viện C, nghĩa là nếu bạn vô tình gọi các hàm không khớp, lỗi sẽ không đáng chú ý. Khi bộ cấp phát đối tượng được bật, các hàm này không còn là bí danh của malloc()free() nữa và việc gọi sai hàm để giải phóng bộ nhớ sẽ khiến bạn bị kết xuất lõi. Ví dụ: nếu bộ nhớ được cấp phát bằng PyMem_New thì nó phải được giải phóng bằng PyMem_Del() chứ không phải free(). Một số mô-đun đi kèm với Python đã gặp phải lỗi này và phải sửa; chắc chắn sẽ có nhiều mô-đun bên thứ ba gặp vấn đề tương tự.

    Bộ cấp phát đối tượng được đóng góp bởi Vladimir Marangozov.

  • Tốc độ của tệp I/O định hướng dòng đã được cải thiện vì mọi người thường phàn nàn về tốc độ thiếu của nó và vì nó thường được sử dụng làm điểm chuẩn ngây thơ. Do đó, phương thức readline() của các đối tượng tệp đã được viết lại để nhanh hơn nhiều. Mức tăng tốc chính xác sẽ khác nhau tùy theo nền tảng tùy thuộc vào tốc độ chậm của getc() của thư viện C, nhưng là khoảng 66% và có khả năng nhanh hơn nhiều trên một số hệ điều hành cụ thể. Tim Peters đã thực hiện phần lớn việc đo điểm chuẩn và mã hóa cho thay đổi này, được thúc đẩy bởi một cuộc thảo luận trên comp.lang.python.

    Một mô-đun và phương thức mới cho các đối tượng tệp cũng được thêm vào, do Jeff Epler đóng góp. Phương thức mới, xreadlines(), tương tự như xrange() tích hợp sẵn. xreadlines() trả về một đối tượng chuỗi mờ chỉ hỗ trợ lặp đi lặp lại, đọc một dòng trên mỗi lần lặp nhưng không đọc toàn bộ tệp vào bộ nhớ như phương thức readlines() hiện có. Bạn sẽ sử dụng nó như thế này:

    cho dòng trong sys.stdin.xreadlines():
        # ... làm gì đó cho mỗi dòng ...
        ...
    

    Để có cuộc thảo luận đầy đủ hơn về các thay đổi I/O của dòng, hãy xem bản tóm tắt python-dev cho ngày 1--15 tháng 1 năm 2001 tại https://mail.python.org/pipermail/python-dev/2001-January/.

  • Một phương pháp mới, popitem(), đã được thêm vào từ điển để cho phép lặp lại triệt để thông qua nội dung của từ điển; việc này có thể nhanh hơn đối với các từ điển lớn vì không cần phải tạo danh sách chứa tất cả các khóa hoặc giá trị. D.popitem() xóa một cặp (key, value) ngẫu nhiên khỏi từ điển D và trả về dưới dạng 2 bộ. Điều này chủ yếu được thực hiện bởi Tim Peters và Guido van Rossum, sau khi có gợi ý và bản vá sơ bộ của Moshe Zadka.

  • Giờ đây, các mô-đun có thể kiểm soát tên nào được nhập khi sử dụng from module import *, bằng cách xác định thuộc tính __all__ chứa danh sách các tên sẽ được nhập. Một khiếu nại phổ biến là nếu mô-đun nhập các mô-đun khác như sys hoặc string, from module import * sẽ thêm chúng vào không gian tên của mô-đun nhập. Để khắc phục điều này, chỉ cần liệt kê tên công khai trong __all__:

    # List tên công khai
    __all__ = ['Cơ sở dữ liệu', 'mở']
    

    Phiên bản chặt chẽ hơn của bản vá này lần đầu tiên được đề xuất và triển khai bởi Ben Wolfson, nhưng sau một số cuộc thảo luận giữa python-dev, phiên bản cuối cùng yếu hơn đã được kiểm tra.

  • Áp dụng repr() cho các chuỗi thoát bát phân được sử dụng trước đó cho các ký tự không in được; ví dụ: một dòng mới là '\012'. Đây là dấu vết còn sót lại của tổ tiên C của Python, nhưng ngày nay hệ bát phân được sử dụng rất ít trong thực tế. Ka-Ping Yee đã đề xuất sử dụng các ký tự thoát hex thay vì ký tự bát phân và sử dụng các ký tự thoát \n, \t, \r cho các ký tự thích hợp và triển khai định dạng mới này.

  • Các lỗi cú pháp được phát hiện tại thời điểm biên dịch giờ đây có thể đưa ra các ngoại lệ chứa tên tệp và số dòng của lỗi, một tác dụng phụ dễ chịu của việc sắp xếp lại trình biên dịch do Jeremy Hylton thực hiện.

  • Các tiện ích mở rộng C nhập các mô-đun khác đã được thay đổi để sử dụng PyImport_ImportModule(), có nghĩa là chúng sẽ sử dụng bất kỳ móc nhập nào đã được cài đặt. Điều này cũng được khuyến khích đối với các tiện ích mở rộng của bên thứ ba cần nhập một số mô-đun khác từ mã C.

  • Kích thước của cơ sở dữ liệu ký tự Unicode đã bị thu hẹp thêm 340K nhờ Fredrik Lundh.

  • Một số cổng mới được đóng góp: MacOS X (của Steven Majewski), Cygwin (của Jason Tishler); RISCOS (bởi Dietmar Schwertberger); Unixware 7 (bởi Billy G. Allie).

Và có một danh sách thông thường gồm các sửa lỗi nhỏ, rò rỉ bộ nhớ nhỏ, chỉnh sửa chuỗi tài liệu và các chỉnh sửa khác, quá dài để có thể liệt kê thành từng mục; xem nhật ký CVS để biết chi tiết đầy đủ nếu bạn muốn.

Lời cảm ơn

Tác giả xin cảm ơn những người sau đây đã đưa ra những gợi ý cho các bản thảo khác nhau của bài viết này: Graeme Cross, David Goodger, Jay Graves, Michael Hudson, Marc-André Lemburg, Fredrik Lundh, Neil Schenauer, Thomas Wouters.