3. Mô hình dữ liệu¶
3.1. Đối tượng, giá trị và loại¶
Objects là sự trừu tượng hóa dữ liệu của Python. Tất cả dữ liệu trong chương trình Python được biểu diễn bằng các đối tượng hoặc bằng quan hệ giữa các đối tượng. Ngay cả mã cũng được đại diện bởi các đối tượng.
Mỗi đối tượng đều có một danh tính, một loại và một giá trị. identity của một đối tượng không bao giờ thay đổi sau khi nó được tạo; bạn có thể coi nó như địa chỉ của đối tượng trong bộ nhớ. Toán tử is so sánh danh tính của hai đối tượng; hàm id() trả về một số nguyên biểu thị danh tính của nó.
Đối với CPython, id(x) là địa chỉ bộ nhớ nơi lưu trữ x.
Kiểu của một đối tượng xác định các hoạt động mà đối tượng đó hỗ trợ (ví dụ: "nó có độ dài không?") và cũng xác định các giá trị có thể có cho các đối tượng thuộc loại đó. Hàm type() trả về kiểu của một đối tượng (chính là một đối tượng). Giống như danh tính của nó, type của một đối tượng cũng không thể thay đổi được. [1]
Zz000zz của một số đối tượng có thể thay đổi. Các đối tượng có giá trị có thể thay đổi được gọi là mutable; các đối tượng có giá trị không thể thay đổi khi chúng được tạo được gọi là immutable. (Giá trị của một đối tượng vùng chứa bất biến chứa tham chiếu đến một đối tượng có thể thay đổi có thể thay đổi khi giá trị của đối tượng sau bị thay đổi; tuy nhiên, vùng chứa vẫn được coi là bất biến, vì tập hợp các đối tượng mà nó chứa không thể thay đổi. Vì vậy, tính bất biến không hoàn toàn giống như việc có một giá trị không thể thay đổi, nó tinh tế hơn.) Tính biến đổi của một đối tượng được xác định bởi loại của nó; ví dụ: số, chuỗi và bộ dữ liệu là bất biến, trong khi từ điển và danh sách có thể thay đổi.
Các đối tượng không bao giờ bị phá hủy một cách rõ ràng; tuy nhiên, khi không thể truy cập được, chúng có thể bị thu gom rác. Việc triển khai được phép trì hoãn việc thu thập rác hoặc bỏ qua nó hoàn toàn --- vấn đề là chất lượng triển khai cách triển khai việc thu gom rác, miễn là không có đối tượng nào được thu thập mà vẫn có thể truy cập được.
CPython hiện sử dụng sơ đồ đếm tham chiếu với khả năng phát hiện rác liên kết theo chu kỳ bị trì hoãn (tùy chọn), thu thập hầu hết các đối tượng ngay khi chúng không thể truy cập được, nhưng không đảm bảo thu thập rác có chứa tham chiếu vòng tròn. Xem tài liệu của mô-đun gc để biết thông tin về cách kiểm soát việc thu thập rác tuần hoàn. Các triển khai khác hoạt động khác và CPython có thể thay đổi. Đừng phụ thuộc vào việc hoàn thiện ngay lập tức các đối tượng khi chúng không thể truy cập được (vì vậy bạn phải luôn đóng các tệp một cách rõ ràng).
Lưu ý rằng việc sử dụng các phương tiện theo dõi hoặc gỡ lỗi của quá trình triển khai có thể giữ cho các đối tượng vẫn tồn tại mà thông thường có thể thu thập được. Cũng lưu ý rằng việc bắt ngoại lệ bằng câu lệnh try...except có thể giữ cho các đối tượng vẫn tồn tại.
Một số đối tượng chứa các tham chiếu đến các tài nguyên "bên ngoài" như các tệp hoặc cửa sổ đang mở. Điều này được hiểu rằng các tài nguyên này được giải phóng khi đối tượng được thu gom rác, nhưng vì việc thu gom rác không đảm bảo sẽ xảy ra nên các đối tượng đó cũng cung cấp một cách rõ ràng để giải phóng tài nguyên bên ngoài, thường là phương thức close(). Các chương trình được khuyến khích đóng các đối tượng như vậy một cách rõ ràng. Câu lệnh try...:keyword:finally và câu lệnh with cung cấp những cách thuận tiện để thực hiện việc này.
Một số đối tượng chứa tham chiếu đến các đối tượng khác; chúng được gọi là containers. Ví dụ về các thùng chứa là bộ dữ liệu, danh sách và từ điển. Các tham chiếu là một phần giá trị của vùng chứa. Trong hầu hết các trường hợp, khi chúng ta nói về giá trị của vùng chứa, chúng ta ám chỉ các giá trị chứ không phải danh tính của các đối tượng được chứa; tuy nhiên, khi chúng ta nói về khả năng thay đổi của một vùng chứa, chỉ có danh tính của các đối tượng được chứa ngay lập tức được ngụ ý. Vì vậy, nếu một vùng chứa bất biến (như bộ dữ liệu) chứa tham chiếu đến một đối tượng có thể thay đổi, thì giá trị của nó sẽ thay đổi nếu đối tượng có thể thay đổi đó bị thay đổi.
Các loại ảnh hưởng đến hầu hết các khía cạnh của hành vi đối tượng. Ngay cả tầm quan trọng của nhận dạng đối tượng cũng bị ảnh hưởng theo một nghĩa nào đó: đối với các loại không thay đổi, các hoạt động tính toán các giá trị mới thực sự có thể trả về một tham chiếu đến bất kỳ đối tượng hiện có nào có cùng loại và giá trị, trong khi đối với các đối tượng có thể thay đổi thì điều này không được phép. Ví dụ: sau a = 1; b = 1, a và b có thể hoặc không thể tham chiếu đến cùng một đối tượng có giá trị một, tùy thuộc vào cách triển khai. Điều này là do int là loại không thể thay đổi nên tham chiếu đến 1 có thể được sử dụng lại. Hành vi này phụ thuộc vào việc triển khai được sử dụng, do đó không nên dựa vào, nhưng là điều cần lưu ý khi sử dụng các bài kiểm tra nhận dạng đối tượng. Tuy nhiên, sau c = []; d = [], c và d được đảm bảo đề cập đến hai danh sách trống khác nhau, duy nhất, mới được tạo. (Lưu ý rằng e = f = [] gán đối tượng same cho cả e và f.)
3.2. Hệ thống phân cấp loại tiêu chuẩn¶
Dưới đây là danh sách các kiểu được tích hợp trong Python. Các mô-đun mở rộng (được viết bằng C, Java hoặc các ngôn ngữ khác, tùy thuộc vào cách triển khai) có thể xác định các loại bổ sung. Các phiên bản tương lai của Python có thể thêm các kiểu vào hệ thống phân cấp kiểu (ví dụ: số hữu tỷ, mảng số nguyên được lưu trữ hiệu quả, v.v.), mặc dù những bổ sung như vậy thường sẽ được cung cấp thông qua thư viện tiêu chuẩn.
Một số mô tả loại bên dưới có chứa đoạn liệt kê 'thuộc tính đặc biệt'. Đây là các thuộc tính cung cấp quyền truy cập vào việc triển khai và không nhằm mục đích sử dụng chung. Định nghĩa của họ có thể thay đổi trong tương lai.
3.2.1. không có¶
Loại này có một giá trị duy nhất. Có một đối tượng duy nhất có giá trị này. Đối tượng này được truy cập thông qua tên tích hợp None. Nó được sử dụng để biểu thị sự vắng mặt của một giá trị trong nhiều trường hợp, ví dụ: nó được trả về từ các hàm không trả về bất kỳ giá trị nào một cách rõ ràng. Giá trị thật của nó là sai.
3.2.2. Chưa thực hiện¶
Loại này có một giá trị duy nhất. Có một đối tượng duy nhất có giá trị này. Đối tượng này được truy cập thông qua tên tích hợp NotImplemented. Các phương pháp số và phương pháp so sánh phong phú sẽ trả về giá trị này nếu chúng không triển khai thao tác cho các toán hạng được cung cấp. (Sau đó, trình thông dịch sẽ thử thao tác được phản ánh hoặc một số thao tác dự phòng khác, tùy thuộc vào toán tử.) Không nên đánh giá nó trong ngữ cảnh boolean.
Xem Thực hiện các phép tính số học để biết thêm chi tiết.
Thay đổi trong phiên bản 3.9: Việc đánh giá NotImplemented trong ngữ cảnh boolean không được dùng nữa.
Thay đổi trong phiên bản 3.14: Việc đánh giá NotImplemented trong ngữ cảnh boolean hiện đưa ra TypeError. Trước đây nó được đánh giá là True và phát ra DeprecationWarning kể từ Python 3.9.
3.2.3. dấu ba chấm¶
Loại này có một giá trị duy nhất. Có một đối tượng duy nhất có giá trị này. Đối tượng này được truy cập thông qua ... theo nghĩa đen hoặc tên cài sẵn Ellipsis. Giá trị chân lý của nó là đúng.
3.2.4. numbers.Number¶
Chúng được tạo bởi các ký tự số và được trả về dưới dạng kết quả bởi các toán tử số học và các hàm số học tích hợp sẵn. Đối tượng số là bất biến; một khi được tạo ra, giá trị của chúng không bao giờ thay đổi. Tất nhiên, số Python có liên quan chặt chẽ với các số toán học, nhưng chịu những hạn chế về biểu diễn số trong máy tính.
Biểu diễn chuỗi của các lớp số, được tính toán bởi __repr__() và __str__(), có các thuộc tính sau:
Chúng là các ký tự số hợp lệ, khi được truyền cho hàm tạo của lớp, sẽ tạo ra một đối tượng có giá trị của số gốc.
Biểu diễn ở cơ số 10, khi có thể.
Các số 0 đứng đầu, có thể ngoại trừ một số 0 duy nhất trước dấu thập phân, không được hiển thị.
Các số 0 ở cuối, có thể ngoại trừ một số 0 duy nhất sau dấu thập phân, không được hiển thị.
Dấu chỉ được hiển thị khi số âm.
Python phân biệt giữa số nguyên, số dấu phẩy động và số phức:
3.2.4.1. numbers.Integral¶
Chúng đại diện cho các phần tử từ tập hợp toán học của các số nguyên (dương và âm).
Ghi chú
Các quy tắc biểu diễn số nguyên nhằm mục đích đưa ra cách giải thích có ý nghĩa nhất về các phép dịch và mặt nạ liên quan đến số nguyên âm.
Có hai loại số nguyên:
- Số nguyên (
int) Chúng đại diện cho các số trong phạm vi không giới hạn, chỉ tùy thuộc vào bộ nhớ (ảo) có sẵn. Với mục đích của các phép toán dịch chuyển và mặt nạ, giả sử biểu diễn nhị phân và các số âm được biểu diễn dưới dạng biến thể của phần bù 2, tạo ảo giác về một chuỗi bit dấu vô hạn kéo dài sang trái.
- Boolean (
bool) Chúng đại diện cho các giá trị thật Sai và Đúng. Hai đối tượng đại diện cho các giá trị
FalsevàTruelà các đối tượng Boolean duy nhất. Loại Boolean là một loại con của loại số nguyên và các giá trị Boolean hoạt động giống như các giá trị 0 và 1 tương ứng trong hầu hết các ngữ cảnh, ngoại trừ khi được chuyển đổi thành một chuỗi, các chuỗi"False"hoặc"True"sẽ được trả về tương ứng.
3.2.4.2. numbers.Real (float)¶
Chúng đại diện cho các số dấu phẩy động có độ chính xác kép ở cấp độ máy. Bạn có thể tùy ý sử dụng kiến trúc máy cơ bản (và cách triển khai C hoặc Java) đối với phạm vi được chấp nhận và cách xử lý tràn. Python không hỗ trợ các số dấu phẩy động có độ chính xác đơn; mức tiết kiệm trong việc sử dụng bộ xử lý và bộ nhớ thường là lý do để sử dụng những thứ này bị giảm đi do chi phí sử dụng các đối tượng trong Python, do đó không có lý do gì để làm phức tạp ngôn ngữ với hai loại số dấu phẩy động.
3.2.4.3. numbers.Complex (complex)¶
Chúng biểu diễn các số phức dưới dạng một cặp số dấu phẩy động có độ chính xác kép ở cấp độ máy. Những cảnh báo tương tự cũng được áp dụng như đối với các số có dấu phẩy động. Phần thực và phần ảo của số phức z có thể được truy xuất thông qua các thuộc tính chỉ đọc z.real và z.imag.
3.2.5. trình tự¶
Chúng đại diện cho các tập hợp có thứ tự hữu hạn được lập chỉ mục bởi các số không âm. Hàm tích hợp len() trả về số mục của một chuỗi. Khi độ dài của chuỗi là n, tập chỉ mục chứa các số 0, 1, ..., n-1. Mục i của dãy a được a[i] chọn. Một số trình tự, bao gồm các trình tự dựng sẵn, giải thích các chỉ số dưới âm bằng cách thêm độ dài trình tự. Ví dụ: a[-2] bằng a[n-2], mục thứ hai đến mục cuối cùng của chuỗi a có độ dài n.
Giá trị kết quả phải là số nguyên không âm nhỏ hơn số mục trong chuỗi. Nếu không, IndexError sẽ được nâng lên.
Trình tự cũng hỗ trợ cắt: a[start:stop] chọn tất cả các mục có chỉ mục k sao cho start <= k < stop. Khi được sử dụng làm biểu thức, lát cắt là một chuỗi cùng loại. Nhận xét ở trên về chỉ số dưới âm cũng áp dụng cho các vị trí lát cắt âm. Lưu ý rằng không có lỗi nào xảy ra nếu vị trí lát cắt nhỏ hơn 0 hoặc lớn hơn độ dài của chuỗi.
Nếu start bị thiếu hoặc None, việc cắt sẽ hoạt động như thể start bằng 0. Nếu stop bị thiếu hoặc None, việc cắt sẽ hoạt động như thể stop bằng độ dài của chuỗi.
Một số trình tự cũng hỗ trợ "cắt mở rộng" với tham số "bước" thứ ba: a[i:j:k] chọn tất cả các mục của a với chỉ mục x trong đó x = i + n*k, n >= 0 và i <= x < j.
Trình tự được phân biệt theo khả năng biến đổi của chúng:
3.2.5.1. Trình tự bất biến¶
Một đối tượng thuộc loại trình tự bất biến không thể thay đổi một khi nó được tạo. (Nếu đối tượng chứa các tham chiếu đến các đối tượng khác, các đối tượng khác này có thể thay đổi và có thể bị thay đổi; tuy nhiên, tập hợp các đối tượng được tham chiếu trực tiếp bởi một đối tượng bất biến không thể thay đổi.)
Các loại sau đây là trình tự bất biến:
- Dây
Chuỗi (
str) là một chuỗi các giá trị đại diện cho characters hoặc chính thức hơn là Unicode code points. Tất cả các điểm mã trong phạm vi0đến0x10FFFFcó thể được biểu diễn dưới dạng chuỗi.Python không có loại character chuyên dụng. Thay vào đó, mọi điểm mã trong chuỗi được biểu diễn dưới dạng đối tượng chuỗi có độ dài
1.Hàm tích hợp
ord()chuyển đổi một điểm mã từ dạng chuỗi thành số nguyên trong phạm vi0đến0x10FFFF;chr()chuyển đổi một số nguyên trong phạm vi0thành0x10FFFFthành đối tượng chuỗi1có độ dài tương ứng.str.encode()có thể được sử dụng để chuyển đổistrthànhbytesbằng cách sử dụng mã hóa văn bản nhất định vàbytes.decode()có thể được sử dụng để đạt được điều ngược lại.- Bộ dữ liệu
Các mục của
tuplelà các đối tượng Python tùy ý. Các bộ gồm hai hoặc nhiều mục được hình thành bởi danh sách các biểu thức được phân tách bằng dấu phẩy. Một bộ gồm một mục ('singleton') có thể được tạo bằng cách gắn dấu phẩy vào một biểu thức (bản thân một biểu thức không tạo ra một bộ, vì phải sử dụng được dấu ngoặc đơn để nhóm các biểu thức). Một bộ trống có thể được hình thành bởi một cặp dấu ngoặc đơn trống.- Byte
Đối tượng
byteslà một mảng bất biến. Các mục là byte 8 bit, được biểu thị bằng các số nguyên trong phạm vi 0 <= x < 256. Các ký tự byte (nhưb'abc') và hàm tạobytes()tích hợp có thể được sử dụng để tạo các đối tượng byte. Ngoài ra, các đối tượng byte có thể được giải mã thành chuỗi thông qua phương thứcdecode().
3.2.5.2. Trình tự có thể thay đổi¶
Trình tự có thể thay đổi có thể được thay đổi sau khi chúng được tạo. Các ký hiệu đăng ký và cắt có thể được sử dụng làm mục tiêu của các câu lệnh gán và del (xóa).
Ghi chú
Mô-đun collections và array cung cấp các ví dụ bổ sung về các loại trình tự có thể thay đổi.
Hiện tại có hai loại trình tự có thể thay đổi nội tại:
- Danh sách
Các mục của danh sách là các đối tượng Python tùy ý. Danh sách được hình thành bằng cách đặt danh sách các biểu thức được phân tách bằng dấu phẩy trong dấu ngoặc vuông. (Lưu ý rằng không cần có trường hợp đặc biệt nào để tạo danh sách có độ dài 0 hoặc 1.)
- Mảng byte
Đối tượng bytearray là một mảng có thể thay đổi được. Chúng được tạo bởi hàm tạo
bytearray()tích hợp sẵn. Ngoài việc có thể thay đổi (và do đó không thể băm), mảng byte còn cung cấp giao diện và chức năng tương tự như các đối tượngbytesbất biến.
3.2.6. Đặt loại¶
Chúng đại diện cho các tập hợp hữu hạn, không có thứ tự của các đối tượng duy nhất, bất biến. Như vậy, chúng không thể được lập chỉ mục bởi bất kỳ chỉ số dưới nào. Tuy nhiên, chúng có thể được lặp lại và hàm tích hợp len() trả về số lượng mục trong một bộ. Các cách sử dụng phổ biến cho các tập hợp là kiểm tra thành viên nhanh chóng, loại bỏ các bản sao khỏi một chuỗi và tính toán các phép toán như giao, hợp, sai phân và sai đối xứng.
Đối với các phần tử tập hợp, các quy tắc bất biến tương tự được áp dụng như đối với khóa từ điển. Lưu ý rằng các kiểu số tuân theo các quy tắc thông thường để so sánh số: nếu hai số so sánh bằng nhau (ví dụ: 1 và 1.0), thì chỉ một trong số chúng có thể được chứa trong một tập hợp.
Hiện tại có hai loại tập hợp nội tại:
- bộ
Chúng đại diện cho một tập hợp có thể thay đổi. Chúng được tạo bởi hàm tạo
set()tích hợp và có thể được sửa đổi sau đó bằng một số phương pháp, chẳng hạn nhưadd().- Bộ đông lạnh
Chúng đại diện cho một tập hợp bất biến. Chúng được tạo bởi hàm tạo
frozenset()tích hợp sẵn. Vì một tập hợp đông lạnh là bất biến và hashable nên nó có thể được sử dụng lại như một phần tử của tập hợp khác hoặc làm khóa từ điển.
3.2.7. Ánh xạ¶
Chúng đại diện cho các tập hợp hữu hạn các đối tượng được lập chỉ mục bởi các bộ chỉ mục tùy ý. Ký hiệu chỉ số dưới a[k] chọn mục được k lập chỉ mục từ ánh xạ a; cái này có thể được sử dụng trong các biểu thức và làm mục tiêu của các phép gán hoặc câu lệnh del. Hàm tích hợp len() trả về số lượng mục trong ánh xạ.
Hiện tại có một loại ánh xạ nội tại duy nhất:
3.2.7.1. Từ điển¶
Chúng đại diện cho các tập hợp hữu hạn các đối tượng được lập chỉ mục bởi các giá trị gần như tùy ý. Các loại giá trị duy nhất không được chấp nhận làm khóa là các giá trị chứa danh sách hoặc từ điển hoặc các loại có thể thay đổi khác được so sánh theo giá trị thay vì theo danh tính đối tượng, lý do là việc triển khai từ điển hiệu quả yêu cầu giá trị băm của khóa không đổi. Các kiểu số được sử dụng cho khóa tuân theo các quy tắc thông thường để so sánh số: nếu hai số so sánh bằng nhau (ví dụ: 1 và 1.0) thì chúng có thể được sử dụng thay thế cho nhau để lập chỉ mục cho cùng một mục từ điển.
Từ điển giữ nguyên thứ tự chèn, nghĩa là các khóa sẽ được tạo theo cùng thứ tự mà chúng được thêm tuần tự vào từ điển. Việc thay thế khóa hiện có không làm thay đổi thứ tự, tuy nhiên, việc xóa khóa và chèn lại sẽ thêm khóa đó vào cuối thay vì giữ nguyên vị trí cũ.
Từ điển có thể thay đổi được; chúng có thể được tạo bằng ký hiệu {} (xem phần Hiển thị từ điển).
Các mô-đun mở rộng dbm.ndbm và dbm.gnu cung cấp các ví dụ bổ sung về các loại ánh xạ, cũng như mô-đun collections.
Thay đổi trong phiên bản 3.7: Từ điển không giữ nguyên thứ tự chèn trong các phiên bản Python trước 3.6. Trong CPython 3.6, thứ tự chèn vẫn được giữ nguyên, nhưng vào thời điểm đó nó được coi là một chi tiết triển khai hơn là một sự đảm bảo về ngôn ngữ.
3.2.8. Các loại có thể gọi được¶
Đây là những loại mà thao tác gọi hàm có thể được áp dụng (xem phần Cuộc gọi):
3.2.8.1. Các hàm do người dùng xác định¶
Đối tượng hàm do người dùng định nghĩa được tạo bởi định nghĩa hàm (xem phần định nghĩa hàm). Nó phải được gọi với một danh sách đối số chứa cùng số mục như danh sách tham số chính thức của hàm.
3.2.8.1.1. Thuộc tính chỉ đọc đặc biệt¶
Thuộc tính |
Ý nghĩa |
|---|---|
|
Tham chiếu đến Added in version 3.10. |
|
Tham chiếu đến |
|
Đối tượng ô có thuộc tính |
3.2.8.1.2. Thuộc tính có thể ghi đặc biệt¶
Hầu hết các thuộc tính này kiểm tra loại giá trị được chỉ định:
Thuộc tính |
Ý nghĩa |
|---|---|
|
Chuỗi tài liệu của hàm hoặc |
|
Tên của hàm. Xem thêm: |
|
Chức năng của qualified name. Xem thêm: Added in version 3.3. |
|
Tên của mô-đun chứa chức năng được xác định hoặc |
|
Một |
|
Zz000zz đại diện cho phần thân hàm được biên dịch. |
|
Không gian tên hỗ trợ các thuộc tính hàm tùy ý. Xem thêm: |
|
Một Thay đổi trong phiên bản 3.14: Chú thích bây giờ là lazily evaluated. Xem PEP 649. |
|
annotate function cho hàm này hoặc Added in version 3.14. |
|
Một |
|
Một Added in version 3.12. |
Các đối tượng hàm cũng hỗ trợ việc nhận và thiết lập các thuộc tính tùy ý, chẳng hạn như có thể được sử dụng để đính kèm siêu dữ liệu vào các hàm. Ký hiệu dấu chấm thuộc tính thông thường được sử dụng để lấy và đặt các thuộc tính đó.
Việc triển khai hiện tại của CPython chỉ hỗ trợ các thuộc tính hàm trên các hàm do người dùng xác định. Các thuộc tính chức năng trên built-in functions có thể được hỗ trợ trong tương lai.
Thông tin bổ sung về định nghĩa của hàm có thể được lấy từ code object của nó (có thể truy cập thông qua thuộc tính __code__).
3.2.8.2. Phương thức sơ thẩm¶
Một đối tượng phương thức cá thể kết hợp một lớp, một cá thể lớp và bất kỳ đối tượng có thể gọi được nào (thường là hàm do người dùng định nghĩa).
Thuộc tính chỉ đọc đặc biệt:
|
Đề cập đến đối tượng thể hiện của lớp mà phương thức là bound |
|
Đề cập đến function object ban đầu |
|
Tài liệu của phương pháp (giống như |
|
Tên của phương thức (giống như |
|
Tên của mô-đun mà phương thức được xác định hoặc |
Các phương thức cũng hỗ trợ truy cập (nhưng không thiết lập) các thuộc tính hàm tùy ý trên function object cơ bản.
Các đối tượng phương thức do người dùng định nghĩa có thể được tạo khi lấy một thuộc tính của một lớp (có thể thông qua một thể hiện của lớp đó), nếu thuộc tính đó là đối tượng function object hoặc classmethod do người dùng định nghĩa.
Khi một đối tượng phương thức cá thể được tạo bằng cách truy xuất một function object do người dùng định nghĩa từ một lớp thông qua một trong các cá thể của nó, thuộc tính __self__ của nó là cá thể và đối tượng phương thức được cho là bound. Thuộc tính __func__ của phương thức mới là đối tượng hàm ban đầu.
Khi một đối tượng phương thức cá thể được tạo bằng cách truy xuất một đối tượng classmethod từ một lớp hoặc một thể hiện, thuộc tính __self__ của nó là chính lớp đó và thuộc tính __func__ của nó là đối tượng hàm nằm bên dưới phương thức lớp.
Khi một đối tượng phương thức cá thể được gọi, hàm cơ bản (__func__) sẽ được gọi, chèn cá thể lớp (__self__) vào trước danh sách đối số. Ví dụ: khi C là một lớp chứa định nghĩa cho hàm f() và x là một phiên bản của C, việc gọi x.f(1) tương đương với việc gọi C.f(x, 1).
Khi một đối tượng phương thức cá thể có nguồn gốc từ một đối tượng classmethod, "thể hiện lớp" được lưu trữ trong __self__ sẽ thực sự là chính lớp đó, do đó việc gọi x.f(1) hoặc C.f(1) tương đương với việc gọi f(C,1) trong đó f là hàm cơ bản.
Điều quan trọng cần lưu ý là các hàm do người dùng định nghĩa là thuộc tính của một thể hiện lớp không được chuyển đổi thành các phương thức ràng buộc; only này xảy ra khi hàm là một thuộc tính của lớp.
3.2.8.3. Chức năng tạo¶
Hàm hoặc phương thức sử dụng câu lệnh yield (xem phần Tuyên bố yield) được gọi là generator function. Một hàm như vậy, khi được gọi, luôn trả về một đối tượng iterator có thể được sử dụng để thực thi phần thân của hàm: việc gọi phương thức iterator.__next__() của iterator sẽ khiến hàm thực thi cho đến khi nó cung cấp một giá trị bằng câu lệnh yield. Khi hàm thực thi câu lệnh return hoặc rơi ra khỏi phần cuối, một ngoại lệ StopIteration sẽ xuất hiện và trình vòng lặp sẽ đạt đến phần cuối của tập hợp các giá trị được trả về.
3.2.8.4. Hàm coroutine¶
Hàm hoặc phương thức được xác định bằng async def được gọi là coroutine function. Hàm như vậy khi được gọi sẽ trả về đối tượng coroutine. Nó có thể chứa các biểu thức await, cũng như các câu lệnh async with và async for. Xem thêm phần Đối tượng Coroutine.
3.2.8.5. Chức năng tạo không đồng bộ¶
Hàm hoặc phương thức được xác định bằng async def và sử dụng câu lệnh yield được gọi là asynchronous generator function. Hàm như vậy, khi được gọi, sẽ trả về một đối tượng asynchronous iterator có thể được sử dụng trong câu lệnh async for để thực thi phần thân của hàm.
Việc gọi phương thức aiterator.__anext__ của trình vòng lặp không đồng bộ sẽ trả về một awaitable mà khi được chờ đợi sẽ thực thi cho đến khi nó cung cấp một giá trị bằng cách sử dụng biểu thức yield. Khi hàm thực thi một câu lệnh return trống hoặc rơi ra khỏi phần cuối, một ngoại lệ StopAsyncIteration sẽ xuất hiện và trình vòng lặp không đồng bộ sẽ đạt đến phần cuối của tập hợp các giá trị được tạo ra.
3.2.8.6. Các chức năng tích hợp¶
Đối tượng hàm dựng sẵn là một trình bao bọc xung quanh hàm C. Ví dụ về các hàm tích hợp là len() và math.sin() (math là mô-đun tích hợp tiêu chuẩn). Số lượng và loại đối số được xác định bởi hàm C. Thuộc tính chỉ đọc đặc biệt:
__doc__là chuỗi tài liệu của hàm hoặcNonenếu không có. Xemfunction.__doc__.__name__là tên của hàm. Xemfunction.__name__.__self__được đặt thànhNone(nhưng hãy xem mục tiếp theo).__module__là tên của mô-đun chứa hàm được xác định hoặcNonenếu không có. Xemfunction.__module__.
3.2.8.7. Các phương pháp tích hợp¶
Đây thực sự là một cách ngụy trang khác của một hàm dựng sẵn, lần này chứa một đối tượng được truyền cho hàm C dưới dạng một đối số bổ sung ngầm định. Một ví dụ về phương thức tích hợp sẵn là alist.append(), giả sử alist là một đối tượng danh sách. Trong trường hợp này, thuộc tính chỉ đọc đặc biệt __self__ được đặt thành đối tượng được biểu thị bằng alist. (Thuộc tính có cùng ngữ nghĩa như với other instance methods.)
3.2.8.8. Lớp học¶
Các lớp học có thể gọi được. Các đối tượng này thường hoạt động như các nhà máy cho các phiên bản mới của chính chúng, nhưng có thể có các biến thể đối với các loại lớp ghi đè __new__(). Các đối số của cuộc gọi được chuyển tới __new__() và trong trường hợp điển hình là __init__() để khởi tạo phiên bản mới.
3.2.8.9. Phiên bản lớp¶
Các thể hiện của các lớp tùy ý có thể được gọi bằng cách định nghĩa phương thức __call__() trong lớp của chúng.
3.2.9. Mô-đun¶
Mô-đun là đơn vị tổ chức cơ bản của mã Python và được tạo bởi import system khi được gọi bằng câu lệnh import hoặc bằng cách gọi các hàm như importlib.import_module() và __import__() tích hợp. Đối tượng mô-đun có một không gian tên được triển khai bởi đối tượng dictionary (đây là từ điển được tham chiếu bởi thuộc tính __globals__ của các hàm được xác định trong mô-đun). Các tham chiếu thuộc tính được dịch sang dạng tra cứu trong từ điển này, ví dụ: m.x tương đương với m.__dict__["x"]. Đối tượng mô-đun không chứa đối tượng mã được sử dụng để khởi tạo mô-đun (vì nó không cần thiết sau khi quá trình khởi tạo hoàn tất).
Việc gán thuộc tính cập nhật từ điển không gian tên của mô-đun, ví dụ: m.x = 1 tương đương với m.__dict__["x"] = 1.
3.2.9.2. Các thuộc tính có thể ghi khác trên đối tượng mô-đun¶
Ngoài các thuộc tính liên quan đến nhập được liệt kê ở trên, các đối tượng mô-đun cũng có các thuộc tính có thể ghi sau:
- module.__doc__¶
Chuỗi tài liệu của mô-đun hoặc
Nonenếu không có. Xem thêm:__doc__ attributes.
- module.__annotations__¶
Một từ điển chứa variable annotations được thu thập trong quá trình thực thi phần thân mô-đun. Để biết các phương pháp hay nhất khi làm việc với
__annotations__, hãy xemannotationlib.Thay đổi trong phiên bản 3.14: Chú thích bây giờ là lazily evaluated. Xem PEP 649.
- module.__annotate__¶
annotate function cho mô-đun này hoặc
Nonenếu mô-đun không có chú thích. Xem thêm: thuộc tính__annotate__.Added in version 3.14.
3.2.9.3. Từ điển mô-đun¶
Các đối tượng mô-đun cũng có thuộc tính chỉ đọc đặc biệt sau:
- module.__dict__¶
Không gian tên của mô-đun như một đối tượng từ điển. Duy nhất trong số các thuộc tính được liệt kê ở đây,
__dict__không thể được truy cập dưới dạng biến toàn cục từ bên trong mô-đun; nó chỉ có thể được truy cập như một thuộc tính trên các đối tượng mô-đun.Do cách CPython xóa từ điển mô-đun nên từ điển mô-đun sẽ bị xóa khi mô-đun nằm ngoài phạm vi ngay cả khi từ điển vẫn còn tham chiếu trực tiếp. Để tránh điều này, hãy sao chép từ điển hoặc giữ lại mô-đun trong khi sử dụng trực tiếp từ điển của nó.
3.2.10. Lớp tùy chỉnh¶
Các loại lớp tùy chỉnh thường được tạo theo định nghĩa lớp (xem phần Định nghĩa lớp). Một lớp có một không gian tên được thực hiện bởi một đối tượng từ điển. Các tham chiếu thuộc tính lớp được dịch sang dạng tra cứu trong từ điển này, ví dụ: C.x được dịch sang C.__dict__["x"] (mặc dù có một số hook cho phép các phương tiện định vị thuộc tính khác). Khi không tìm thấy tên thuộc tính ở đó, việc tìm kiếm thuộc tính sẽ tiếp tục trong các lớp cơ sở. Việc tìm kiếm các lớp cơ sở này sử dụng thứ tự phân giải phương thức C3 hoạt động chính xác ngay cả khi có cấu trúc kế thừa 'kim cương' trong đó có nhiều đường dẫn kế thừa dẫn trở lại tổ tiên chung. Bạn có thể tìm thêm thông tin chi tiết về C3 MRO được Python sử dụng tại Thứ tự phân giải phương thức Python 2.3.
Khi một tham chiếu thuộc tính lớp (chẳng hạn như đối với lớp C) mang lại một đối tượng phương thức lớp, nó sẽ được chuyển đổi thành một đối tượng phương thức cá thể có thuộc tính __self__ là C. Khi nó mang lại một đối tượng staticmethod, nó sẽ được chuyển đổi thành đối tượng được bao bọc bởi đối tượng phương thức tĩnh. Xem phần Triển khai mô tả để biết cách khác trong đó các thuộc tính được truy xuất từ một lớp có thể khác với các thuộc tính thực sự có trong __dict__ của nó.
Phép gán thuộc tính lớp cập nhật từ điển của lớp, không bao giờ là từ điển của lớp cơ sở.
Một đối tượng lớp có thể được gọi (xem ở trên) để tạo ra một thể hiện của lớp (xem bên dưới).
3.2.10.1. Thuộc tính đặc biệt¶
Thuộc tính |
Ý nghĩa |
|---|---|
|
Tên của lớp học. Xem thêm: |
|
Lớp học qualified name. Xem thêm: |
|
Tên của mô-đun trong đó lớp được xác định. |
|
Zz000zz cung cấp chế độ xem chỉ đọc cho không gian tên của lớp. Xem thêm: |
|
Một |
|
Lớp cơ sở duy nhất trong chuỗi kế thừa chịu trách nhiệm bố trí bộ nhớ của các phiên bản. Thuộc tính này tương ứng với |
|
Chuỗi tài liệu của lớp hoặc |
|
Một từ điển chứa variable annotations được thu thập trong quá trình thực thi nội dung lớp. Xem thêm: Để biết các phương pháp hay nhất khi làm việc với Cảnh báo Việc truy cập thuộc tính Thuộc tính này không tồn tại trên một số lớp dựng sẵn nhất định. Trên các lớp do người dùng định nghĩa không có Thay đổi trong phiên bản 3.14: Chú thích bây giờ là lazily evaluated. Xem PEP 649. |
|
annotate function cho lớp này hoặc Added in version 3.14. |
|
Một Added in version 3.12. |
|
Một Added in version 3.13. |
|
Số dòng của dòng đầu tiên trong định nghĩa lớp, bao gồm cả phần trang trí. Việc đặt thuộc tính Added in version 3.13. |
|
|
3.2.10.2. Phương pháp đặc biệt¶
Ngoài các thuộc tính đặc biệt được mô tả ở trên, tất cả các lớp Python còn có sẵn hai phương thức sau:
- type.mro()¶
Phương thức này có thể được ghi đè bằng siêu dữ liệu để tùy chỉnh thứ tự phân giải phương thức cho các phiên bản của nó. Nó được gọi khi khởi tạo lớp và kết quả của nó được lưu trữ trong
__mro__.
- type.__subclasses__()¶
Mỗi lớp giữ một danh sách các tham chiếu yếu đến các lớp con trực tiếp của nó. Phương thức này trả về danh sách tất cả các tham chiếu đó vẫn còn tồn tại. Danh sách theo thứ tự định nghĩa. Ví dụ:
>>> lớp A: đậu >>> lớp B(A): đậu >>> A.__lớp con__() [<lớp 'B'>]
3.2.11. Phiên bản lớp¶
Một thể hiện của lớp được tạo bằng cách gọi một đối tượng lớp (xem ở trên). Một thể hiện của lớp có một không gian tên được triển khai như một từ điển, đây là nơi đầu tiên tìm kiếm các tham chiếu thuộc tính. Khi không tìm thấy thuộc tính ở đó và lớp của cá thể có thuộc tính có tên đó, việc tìm kiếm sẽ tiếp tục với các thuộc tính của lớp. Nếu một thuộc tính lớp được tìm thấy là một đối tượng hàm do người dùng định nghĩa, nó sẽ được chuyển đổi thành một đối tượng phương thức cá thể có thuộc tính __self__ là cá thể. Các đối tượng phương thức tĩnh và phương thức lớp cũng được chuyển đổi; xem ở trên trong phần "Lớp học". Xem phần Triển khai mô tả để biết cách khác trong đó các thuộc tính của một lớp được truy xuất thông qua các thể hiện của nó có thể khác với các đối tượng thực sự được lưu trữ trong __dict__ của lớp. Nếu không tìm thấy thuộc tính lớp nào và lớp của đối tượng có phương thức __getattr__() thì phương thức đó được gọi để đáp ứng việc tra cứu.
Việc gán và xóa thuộc tính cập nhật từ điển của thể hiện, không bao giờ là từ điển của lớp. Nếu lớp có phương thức __setattr__() hoặc __delattr__(), thì phương thức này sẽ được gọi thay vì cập nhật trực tiếp từ điển phiên bản.
Các thể hiện của lớp có thể giả vờ là số, chuỗi hoặc ánh xạ nếu chúng có các phương thức với một số tên đặc biệt nhất định. Xem phần Tên phương thức đặc biệt.
3.2.11.1. Thuộc tính đặc biệt¶
- object.__class__¶
Lớp mà một thể hiện của lớp thuộc về.
3.2.12. Đối tượng I/O (còn được gọi là đối tượng tệp)¶
Zz000zz đại diện cho một tệp đang mở. Có sẵn nhiều phím tắt khác nhau để tạo các đối tượng tệp: hàm dựng sẵn open(), cũng như os.popen(), os.fdopen() và phương thức makefile() của các đối tượng socket (và có thể bằng các hàm hoặc phương thức khác được cung cấp bởi các mô-đun mở rộng).
Các đối tượng tệp triển khai các phương thức phổ biến được liệt kê bên dưới để đơn giản hóa việc sử dụng mã chung. Họ dự kiến sẽ là Với Trình quản lý bối cảnh câu lệnh.
Các đối tượng sys.stdin, sys.stdout và sys.stderr được khởi tạo để lưu trữ các đối tượng tương ứng với các luồng đầu vào, đầu ra và lỗi tiêu chuẩn của trình thông dịch; tất cả chúng đều mở ở chế độ văn bản và do đó tuân theo giao diện được xác định bởi lớp trừu tượng io.TextIOBase.
- file.read(size=-1, /)¶
Truy xuất dữ liệu lên tới size từ tệp. Để thuận tiện nếu size không được chỉ định hoặc -1 truy xuất tất cả dữ liệu có sẵn.
- file.write(data, /)¶
Lưu trữ data vào tập tin.
- file.close()¶
Xóa mọi bộ đệm và đóng tệp cơ bản.
3.2.13. Các loại nội bộ¶
Một số loại được trình thông dịch sử dụng nội bộ sẽ được hiển thị cho người dùng. Định nghĩa của chúng có thể thay đổi theo các phiên bản tương lai của trình thông dịch, nhưng chúng được đề cập ở đây để đảm bảo đầy đủ.
3.2.13.1. Đối tượng mã¶
Các đối tượng mã đại diện cho mã Python thực thi byte-compiled hoặc bytecode. Sự khác biệt giữa đối tượng mã và đối tượng hàm là đối tượng hàm chứa tham chiếu rõ ràng đến toàn cục của hàm (mô-đun mà nó được xác định), trong khi đối tượng mã không chứa ngữ cảnh; các giá trị đối số mặc định cũng được lưu trữ trong đối tượng hàm chứ không phải trong đối tượng mã (vì chúng biểu thị các giá trị được tính toán trong thời gian chạy). Không giống như các đối tượng hàm, các đối tượng mã là bất biến và không chứa tham chiếu (trực tiếp hoặc gián tiếp) đến các đối tượng có thể thay đổi.
3.2.13.1.1. Thuộc tính chỉ đọc đặc biệt¶
|
Tên chức năng |
|
Tên hàm đủ điều kiện Added in version 3.11. |
|
Tổng số parameters vị trí (bao gồm các tham số chỉ có vị trí và các tham số có giá trị mặc định) mà hàm có |
|
Số lượng parameters chỉ có vị trí (bao gồm các đối số có giá trị mặc định) mà hàm có |
|
Số lượng parameters chỉ có từ khóa (bao gồm các đối số có giá trị mặc định) mà hàm có |
|
Số lượng local variables mà hàm sử dụng (bao gồm cả tham số) |
|
Một |
|
Một |
|
Một Lưu ý: bao gồm các tham chiếu đến tên chung và tên dựng sẵn not. |
|
Một chuỗi biểu thị chuỗi lệnh bytecode trong hàm |
|
|
|
|
|
Tên của tệp mà mã được biên dịch |
|
Số dòng của dòng đầu tiên của hàm |
|
Một chuỗi mã hóa ánh xạ từ độ lệch bytecode sang số dòng. Để biết chi tiết, hãy xem mã nguồn của trình thông dịch. Sắp loại bỏ từ phiên bản 3.12: Thuộc tính này của các đối tượng mã không được dùng nữa và có thể bị xóa trong Python 3.15. |
|
Kích thước ngăn xếp cần thiết của đối tượng mã |
|
Một |
Các bit cờ sau đây được xác định cho co_flags: bit 0x04 được đặt nếu hàm sử dụng cú pháp *arguments để chấp nhận số lượng đối số vị trí tùy ý; bit 0x08 được đặt nếu hàm sử dụng cú pháp **keywords để chấp nhận các đối số từ khóa tùy ý; bit 0x20 được đặt nếu hàm này là một trình tạo. Xem Cờ bit đối tượng mã để biết chi tiết về ngữ nghĩa của từng cờ có thể xuất hiện.
Các khai báo tính năng trong tương lai (ví dụ: from __future__ import division) cũng sử dụng các bit trong co_flags để cho biết liệu một đối tượng mã có được biên dịch với một tính năng cụ thể được bật hay không. Xem compiler_flag.
Các bit khác trong co_flags được dành riêng để sử dụng nội bộ.
Nếu một đối tượng mã đại diện cho một hàm và có chuỗi tài liệu, thì bit CO_HAS_DOCSTRING được đặt trong co_flags và mục đầu tiên trong co_consts là chuỗi tài liệu của hàm.
3.2.13.1.2. Các phương thức trên đối tượng mã¶
- codeobject.co_positions()¶
Trả về một giá trị có thể lặp lại trên các vị trí mã nguồn của từng lệnh bytecode trong đối tượng mã.
Trình vòng lặp trả về
tuples chứa(start_line, end_line, start_column, end_column). Bộ i-th tương ứng với vị trí của mã nguồn được biên dịch thành đơn vị mã i-th. Thông tin cột là độ lệch byte utf-8 được lập chỉ mục 0 trên dòng nguồn đã cho.Thông tin vị trí này có thể bị thiếu. Danh sách không đầy đủ các trường hợp điều này có thể xảy ra:
Chạy trình thông dịch với
-Xno_debug_ranges.Đang tải tệp pyc được biên dịch trong khi sử dụng
-Xno_debug_ranges.Vị trí các bộ dữ liệu tương ứng với các lệnh nhân tạo.
Không thể biểu thị số dòng và số cột do các hạn chế cụ thể khi triển khai.
Khi điều này xảy ra, một số hoặc tất cả các phần tử trong bộ có thể là
None.Added in version 3.11.
Ghi chú
Tính năng này yêu cầu lưu trữ các vị trí cột trong đối tượng mã, điều này có thể làm tăng nhẹ mức sử dụng đĩa của các tệp Python đã biên dịch hoặc mức sử dụng bộ nhớ trình thông dịch. Để tránh lưu trữ thông tin bổ sung và/hoặc hủy kích hoạt việc in thông tin truy nguyên bổ sung, có thể sử dụng cờ dòng lệnh
-Xno_debug_rangeshoặc biến môi trườngPYTHONNODEBUGRANGES.
- codeobject.co_lines()¶
Trả về một trình vòng lặp mang lại thông tin về các phạm vi liên tiếp của bytecodes. Mỗi mục mang lại là một
(start, end, lineno)tuple:start(mộtint) đại diện cho phần bù (bao gồm) điểm bắt đầu của phạm vi bytecodeend(mộtint) đại diện cho phần bù (độc quyền) của phần cuối của phạm vi bytecodelinenolàintđại diện cho số dòng của phạm vi bytecode hoặcNonenếu mã byte trong phạm vi đã cho không có số dòng
Các vật phẩm thu được sẽ có các thuộc tính sau:
Phạm vi đầu tiên mang lại sẽ có
startbằng 0.Phạm vi
(start, end)sẽ không giảm và liên tục. Nghĩa là, đối với bất kỳ cặptuples nào,startcủa cặp thứ hai sẽ bằngendcủa cặp thứ nhất.Không có phạm vi nào sẽ bị lùi:
end >= startcho tất cả các bộ ba.tuplecuối cùng mang lại sẽ cóendbằng kích thước của bytecode.
Cho phép phạm vi độ rộng bằng 0, trong đó
start == end. Phạm vi độ rộng bằng 0 được sử dụng cho các dòng có trong mã nguồn nhưng đã bị trình biên dịch bytecode loại bỏ.Added in version 3.10.
Xem thêm
- PEP 626 - Số dòng chính xác để gỡ lỗi và các công cụ khác.
Zz001zz đã giới thiệu phương pháp
co_lines().
- codeobject.replace(**kwargs)¶
Trả về bản sao của đối tượng mã với các giá trị mới cho các trường được chỉ định.
Các đối tượng mã cũng được hỗ trợ bởi hàm chung
copy.replace().Added in version 3.8.
3.2.13.2. Đóng khung đồ vật¶
Các đối tượng khung đại diện cho các khung thực thi. Chúng có thể xuất hiện trong traceback objects và cũng được chuyển đến các chức năng theo dõi đã đăng ký.
3.2.13.2.1. Thuộc tính chỉ đọc đặc biệt¶
|
Trỏ tới khung ngăn xếp trước đó (hướng tới người gọi) hoặc |
|
Zz000zz đang được thực thi trong khung này. Việc truy cập thuộc tính này sẽ tạo ra auditing event |
|
Ánh xạ được khung sử dụng để tra cứu local variables. Nếu khung tham chiếu đến optimized scope, điều này có thể trả về một đối tượng proxy ghi qua. Thay đổi trong phiên bản 3.13: Trả lại proxy cho phạm vi được tối ưu hóa. |
|
Từ điển được frame sử dụng để tra cứu global variables |
|
Từ điển được frame sử dụng để tra cứu built-in (intrinsic) names |
|
"Lệnh chính xác" của đối tượng khung (đây là chỉ mục trong chuỗi bytecode của code object) |
|
Đối tượng generator hoặc coroutine sở hữu khung này hoặc Added in version 3.14. |
3.2.13.2.2. Thuộc tính có thể ghi đặc biệt¶
|
Nếu không phải là |
|
Đặt thuộc tính này thành |
|
Đặt thuộc tính này thành |
|
Số dòng hiện tại của khung -- việc ghi vào khung này từ bên trong hàm theo dõi sẽ nhảy tới dòng đã cho (chỉ dành cho khung dưới cùng). Trình gỡ lỗi có thể triển khai lệnh Nhảy (còn gọi là Đặt câu lệnh tiếp theo) bằng cách ghi vào thuộc tính này. |
3.2.13.2.3. Phương thức đối tượng khung¶
Các đối tượng khung hỗ trợ một phương thức:
- frame.clear()¶
Phương pháp này xóa tất cả các tham chiếu đến local variables được giữ trong khung. Ngoài ra, nếu khung thuộc về generator, trình tạo sẽ được hoàn thiện. Điều này giúp phá vỡ các chu trình tham chiếu liên quan đến các đối tượng khung (ví dụ: khi bắt một exception và lưu trữ traceback của nó để sử dụng sau này).
RuntimeErrorđược nâng lên nếu khung hiện đang được thực thi hoặc bị treo.Added in version 3.4.
Thay đổi trong phiên bản 3.13: Cố gắng xóa khung bị treo sẽ tăng
RuntimeError(như trường hợp luôn xảy ra khi thực thi khung).
3.2.13.3. Đối tượng truy nguyên¶
Các đối tượng truy nguyên biểu thị dấu vết ngăn xếp của exception. Đối tượng truy nguyên được tạo ngầm khi xảy ra ngoại lệ và cũng có thể được tạo rõ ràng bằng cách gọi types.TracebackType.
Thay đổi trong phiên bản 3.7: Các đối tượng theo dõi hiện có thể được khởi tạo rõ ràng từ mã Python.
Đối với các truy nguyên được tạo ngầm, khi tìm kiếm một trình xử lý ngoại lệ sẽ giải phóng ngăn xếp thực thi, ở mỗi cấp độ không liên kết, một đối tượng truy nguyên sẽ được chèn vào phía trước truy nguyên hiện tại. Khi một trình xử lý ngoại lệ được nhập vào, dấu vết ngăn xếp sẽ được cung cấp cho chương trình. (Xem phần Tuyên bố try.) Nó có thể được truy cập dưới dạng mục thứ ba của bộ dữ liệu được trả về bởi sys.exc_info() và dưới dạng thuộc tính __traceback__ của ngoại lệ bị bắt.
Khi chương trình không chứa trình xử lý phù hợp, dấu vết ngăn xếp sẽ được ghi (được định dạng rõ ràng) vào luồng lỗi tiêu chuẩn; nếu trình thông dịch có tính tương tác thì nó cũng được cung cấp cho người dùng dưới dạng sys.last_traceback.
Đối với các truy nguyên được tạo rõ ràng, người tạo truy nguyên có trách nhiệm xác định cách liên kết các thuộc tính tb_next để tạo thành một dấu vết ngăn xếp đầy đủ.
Thuộc tính chỉ đọc đặc biệt:
|
Trỏ tới việc thực thi frame ở cấp độ hiện tại. Việc truy cập thuộc tính này sẽ tạo ra một auditing event |
|
Cung cấp số dòng nơi xảy ra ngoại lệ |
|
Cho biết "hướng dẫn chính xác". |
Số dòng và lệnh cuối cùng trong traceback có thể khác với số dòng của frame object nếu ngoại lệ xảy ra trong câu lệnh try không khớp với mệnh đề ngoại trừ hoặc với mệnh đề finally.
- traceback.tb_next¶
Thuộc tính có thể ghi đặc biệt
tb_nextlà cấp độ tiếp theo trong dấu vết ngăn xếp (hướng tới khung xảy ra ngoại lệ) hoặcNonenếu không có cấp độ tiếp theo.Thay đổi trong phiên bản 3.7: Thuộc tính này bây giờ có thể ghi được
3.2.13.4. Cắt lát đối tượng¶
Các đối tượng Slice được sử dụng để biểu diễn các lát cắt cho các phương thức __getitem__(). Chúng cũng được tạo bởi chức năng slice() tích hợp.
Thuộc tính chỉ đọc đặc biệt: start là giới hạn dưới; stop là giới hạn trên; step là giá trị bước; mỗi cái là None nếu bị bỏ qua. Các thuộc tính này có thể có bất kỳ loại nào.
Các đối tượng Slice hỗ trợ một phương thức:
- slice.indices(self, length)¶
Phương thức này lấy một đối số nguyên duy nhất length và tính toán thông tin về lát cắt mà đối tượng lát cắt sẽ mô tả nếu được áp dụng cho một chuỗi các mục length. Nó trả về một bộ ba số nguyên; tương ứng đây là các chỉ số start và stop và step hoặc độ dài sải chân của lát cắt. Các chỉ số bị thiếu hoặc nằm ngoài giới hạn được xử lý theo cách phù hợp với các lát cắt thông thường.
3.2.13.5. Đối tượng phương thức tĩnh¶
Các đối tượng phương thức tĩnh cung cấp một cách để loại bỏ sự biến đổi của các đối tượng hàm thành các đối tượng phương thức được mô tả ở trên. Đối tượng phương thức tĩnh là một trình bao bọc xung quanh bất kỳ đối tượng nào khác, thường là đối tượng phương thức do người dùng xác định. Khi một đối tượng phương thức tĩnh được lấy ra từ một lớp hoặc một thể hiện của lớp, đối tượng thực sự được trả về là đối tượng được bao bọc, không chịu bất kỳ sự chuyển đổi nào nữa. Các đối tượng phương thức tĩnh cũng có thể gọi được. Các đối tượng phương thức tĩnh được tạo bởi hàm tạo staticmethod() tích hợp.
3.2.13.6. Đối tượng phương thức lớp¶
Một đối tượng phương thức lớp, giống như một đối tượng phương thức tĩnh, là một trình bao bọc xung quanh một đối tượng khác làm thay đổi cách truy xuất đối tượng đó từ các lớp và các thể hiện của lớp. Hành vi của các đối tượng phương thức lớp khi truy xuất như vậy được mô tả ở trên, dưới phần "instance methods". Các đối tượng phương thức lớp được tạo bởi hàm tạo classmethod() tích hợp.
3.3. Tên phương thức đặc biệt¶
Một lớp có thể thực hiện một số thao tác nhất định được gọi bằng cú pháp đặc biệt (chẳng hạn như các phép toán số học hoặc chỉ số dưới và cắt) bằng cách xác định các phương thức có tên đặc biệt. Đây là cách tiếp cận của Python đối với operator overloading, cho phép các lớp xác định hành vi của riêng chúng đối với các toán tử ngôn ngữ. Ví dụ: nếu một lớp định nghĩa một phương thức có tên __getitem__() và x là một phiên bản của lớp này thì x[i] gần tương đương với type(x).__getitem__(x, i). Trừ khi được đề cập, các nỗ lực thực hiện một thao tác sẽ tạo ra ngoại lệ khi không có phương thức thích hợp nào được xác định (thường là AttributeError hoặc TypeError).
Việc đặt một phương thức đặc biệt thành None cho biết thao tác tương ứng không khả dụng. Ví dụ: nếu một lớp đặt __iter__() thành None, thì lớp đó không thể lặp lại được, do đó, việc gọi iter() trên các phiên bản của nó sẽ tăng TypeError (mà không quay trở lại __getitem__()). [2]
Khi triển khai một lớp mô phỏng bất kỳ loại tích hợp nào, điều quan trọng là việc mô phỏng chỉ được triển khai ở mức độ phù hợp với đối tượng được mô hình hóa. Ví dụ: một số chuỗi có thể hoạt động tốt với việc truy xuất các phần tử riêng lẻ, nhưng việc trích xuất một lát cắt có thể không có ý nghĩa. (Một ví dụ về điều này là giao diện NodeList trong Mô hình đối tượng tài liệu của W3C.)
3.3.1. Tùy chỉnh cơ bản¶
- object.__new__(cls[, ...])¶
Được gọi để tạo một thể hiện mới của lớp cls.
__new__()là một phương thức tĩnh (được đặt trong vỏ đặc biệt nên bạn không cần phải khai báo như vậy) lấy lớp mà phiên bản được yêu cầu làm đối số đầu tiên. Các đối số còn lại là những đối số được truyền cho biểu thức hàm tạo đối tượng (lệnh gọi lớp). Giá trị trả về của__new__()phải là phiên bản đối tượng mới (thường là phiên bản của cls).Các cách triển khai điển hình sẽ tạo một phiên bản mới của lớp bằng cách gọi phương thức
__new__()của siêu lớp bằng cách sử dụngsuper().__new__(cls[, ...])với các đối số thích hợp, sau đó sửa đổi phiên bản mới được tạo nếu cần trước khi trả về nó.Nếu
__new__()được gọi trong quá trình xây dựng đối tượng và nó trả về một phiên bản của cls, thì phương thức__init__()của phiên bản mới sẽ được gọi như__init__(self[, ...]), trong đó self là phiên bản mới và các đối số còn lại giống như được truyền cho hàm tạo đối tượng.Nếu
__new__()không trả về một phiên bản của cls thì phương thức__init__()của phiên bản mới sẽ không được gọi.__new__()chủ yếu nhằm mục đích cho phép các lớp con thuộc loại không thể thay đổi (như int, str hoặc tuple) tùy chỉnh việc tạo phiên bản. Nó cũng thường được ghi đè trong siêu dữ liệu tùy chỉnh để tùy chỉnh việc tạo lớp.
- object.__init__(self[, ...])¶
Được gọi sau khi phiên bản đã được tạo (bởi
__new__()), nhưng trước khi nó được trả về cho người gọi. Các đối số là những đối số được truyền cho biểu thức hàm tạo của lớp. Nếu một lớp cơ sở có một phương thức__init__(), thì phương thức__init__()của lớp dẫn xuất, nếu có, phải gọi nó một cách rõ ràng để đảm bảo khởi tạo đúng phần lớp cơ sở của cá thể; ví dụ:super().__init__([args...]).Vì
__new__()và__init__()phối hợp với nhau trong việc xây dựng các đối tượng (__new__()để tạo ra nó và__init__()để tùy chỉnh nó), nên__init__()không thể trả về giá trị không phảiNone; làm như vậy sẽ khiếnTypeErrorđược nâng lên khi chạy.
- object.__del__(self)¶
Được gọi khi instance sắp bị hủy. Đây còn được gọi là bộ hoàn thiện hoặc bộ hủy (không đúng cách). Nếu một lớp cơ sở có phương thức
__del__(), thì phương thức__del__()của lớp dẫn xuất, nếu có, phải gọi nó một cách rõ ràng để đảm bảo xóa đúng phần lớp cơ sở của cá thể.Phương thức
__del__()có thể trì hoãn việc hủy phiên bản bằng cách tạo một tham chiếu mới cho phiên bản đó (mặc dù không được khuyến nghị!) Đây được gọi là đối tượng resurrection. Việc__del__()có được gọi lần thứ hai hay không khi một đối tượng được phục hồi sắp bị phá hủy còn phụ thuộc vào việc triển khai hay không; việc triển khai CPython hiện tại chỉ gọi nó một lần.Không đảm bảo rằng các phương thức
__del__()được gọi cho các đối tượng vẫn tồn tại khi trình thông dịch thoát.weakref.finalizecung cấp một cách đơn giản để đăng ký hàm dọn dẹp để gọi khi một đối tượng được thu gom rác.Ghi chú
del xkhông gọi trực tiếpx.__del__()--- cái trước giảm số lượng tham chiếu choxđi một và cái sau chỉ được gọi khi số tham chiếu củaxđạt đến 0.Chu trình tham chiếu có thể ngăn chặn số lượng tham chiếu của một đối tượng về 0. Trong trường hợp này, chu trình sau đó sẽ được cyclic garbage collector phát hiện và xóa. Nguyên nhân phổ biến của chu kỳ tham chiếu là khi có một ngoại lệ xảy ra trong một biến cục bộ. Sau đó, các địa phương của khung sẽ tham chiếu đến ngoại lệ, tham chiếu đến dấu vết của chính nó, tham chiếu đến các địa phương của tất cả các khung được ghi lại trong dấu vết.
Xem thêm
Tài liệu cho mô-đun
gc.Cảnh báo
Do các trường hợp bấp bênh trong đó các phương thức
__del__()được gọi, các ngoại lệ xảy ra trong quá trình thực thi chúng sẽ bị bỏ qua và thay vào đó, một cảnh báo sẽ được in rasys.stderr. Đặc biệt:__del__()có thể được gọi khi mã tùy ý đang được thực thi, kể cả từ bất kỳ luồng tùy ý nào. Nếu__del__()cần khóa hoặc gọi bất kỳ tài nguyên chặn nào khác, nó có thể bị bế tắc vì tài nguyên có thể đã bị lấy bởi mã bị gián đoạn để thực thi__del__().__del__()có thể được thực thi trong khi tắt trình thông dịch. Kết quả là, các biến toàn cục mà nó cần truy cập (bao gồm các mô-đun khác) có thể đã bị xóa hoặc được đặt thànhNone. Python đảm bảo rằng các biến toàn cục có tên bắt đầu bằng một dấu gạch dưới sẽ bị xóa khỏi mô-đun của chúng trước khi các biến toàn cục khác bị xóa; nếu không có tham chiếu nào khác đến các hình cầu như vậy tồn tại, điều này có thể giúp đảm bảo rằng các mô-đun đã nhập vẫn có sẵn tại thời điểm phương thức__del__()được gọi.
- object.__repr__(self)¶
Được gọi bằng hàm tích hợp
repr()để tính toán biểu diễn chuỗi "chính thức" của một đối tượng. Nếu có thể, biểu thức này sẽ trông giống như một biểu thức Python hợp lệ có thể được sử dụng để tạo lại một đối tượng có cùng giá trị (trong một môi trường thích hợp). Nếu điều này là không thể, một chuỗi có dạng<...some useful description...>sẽ được trả về. Giá trị trả về phải là một đối tượng chuỗi. Nếu một lớp định nghĩa__repr__()chứ không phải__str__(), thì__repr__()cũng được sử dụng khi cần có một chuỗi biểu diễn "không chính thức" của các phiên bản của lớp đó.Điều này thường được sử dụng để gỡ lỗi, vì vậy điều quan trọng là cách trình bày phải giàu thông tin và rõ ràng. Việc triển khai mặc định được cung cấp bởi chính lớp
object.
- object.__str__(self)¶
Được gọi bởi
str(object), cách triển khai__format__()mặc định và hàmprint()tích hợp để tính toán biểu diễn chuỗi "không chính thức" hoặc có thể in độc đáo của một đối tượng. Giá trị trả về phải là đối tượng str.Phương thức này khác với
object.__repr__()ở chỗ không có kỳ vọng rằng__str__()trả về một biểu thức Python hợp lệ: có thể sử dụng một cách biểu diễn ngắn gọn hoặc thuận tiện hơn.Việc triển khai mặc định được xác định bởi loại
objecttích hợp gọiobject.__repr__().
- object.__bytes__(self)¶
Được gọi bởi bytes để tính toán biểu diễn chuỗi byte của một đối tượng. Điều này sẽ trả về một đối tượng
bytes. Bản thân lớpobjectkhông cung cấp phương thức này.
- object.__format__(self, format_spec)¶
Được gọi bằng hàm tích hợp
format()và bằng cách mở rộng, đánh giá formatted string literals và phương thứcstr.format()để tạo ra biểu diễn chuỗi "được định dạng" của một đối tượng. Đối số format_spec là một chuỗi chứa mô tả về các tùy chọn định dạng mong muốn. Việc giải thích đối số format_spec tùy thuộc vào loại triển khai__format__(), tuy nhiên, hầu hết các lớp sẽ ủy quyền định dạng cho một trong các loại có sẵn hoặc sử dụng cú pháp tùy chọn định dạng tương tự.Xem Đặc tả định dạng ngôn ngữ nhỏ để biết mô tả về cú pháp định dạng chuẩn.
Giá trị trả về phải là một đối tượng chuỗi.
Việc triển khai mặc định của lớp
objectphải được cung cấp một chuỗi format_spec trống. Nó ủy quyền cho__str__().Thay đổi trong phiên bản 3.4: Bản thân phương thức __format__ của
objectsẽ tăngTypeErrornếu truyền bất kỳ chuỗi nào không trống.Thay đổi trong phiên bản 3.7:
object.__format__(x, '')hiện tương đương vớistr(x)thay vìformat(str(x), '').
- object.__lt__(self, other)¶
- object.__le__(self, other)¶
- object.__eq__(self, other)¶
- object.__ne__(self, other)¶
- object.__gt__(self, other)¶
- object.__ge__(self, other)¶
Đây được gọi là phương pháp "so sánh phong phú". Sự tương ứng giữa các ký hiệu toán tử và tên phương thức như sau:
x<ygọix.__lt__(y),x<=ygọix.__le__(y),x==ygọix.__eq__(y),x!=ygọix.__ne__(y),x>ygọix.__gt__(y)vàx>=ygọix.__ge__(y).Một phương thức so sánh phong phú có thể trả về
NotImplementedđơn lẻ nếu nó không triển khai thao tác cho một cặp đối số nhất định. Theo quy ước,FalsevàTrueđược trả về để so sánh thành công. Tuy nhiên, các phương thức này có thể trả về bất kỳ giá trị nào, vì vậy nếu toán tử so sánh được sử dụng trong ngữ cảnh Boolean (ví dụ: trong điều kiện của câu lệnhif), Python sẽ gọibool()trên giá trị để xác định xem kết quả là đúng hay sai.Theo mặc định,
objecttriển khai__eq__()bằng cách sử dụngis, trả vềNotImplementedtrong trường hợp so sánh sai:True if x is y else NotImplemented. Đối với__ne__(), theo mặc định, nó ủy quyền cho__eq__()và đảo ngược kết quả trừ khi đó làNotImplemented. Không có mối quan hệ ngụ ý nào khác giữa các toán tử so sánh hoặc việc triển khai mặc định; ví dụ: sự thật của(x<y or x==y)không bao hàmx<=y. Để tự động tạo các hoạt động đặt hàng từ một thao tác gốc duy nhất, hãy xemfunctools.total_ordering().Theo mặc định, lớp
objectcung cấp các triển khai nhất quán với So sánh giá trị: so sánh đẳng thức theo danh tính đối tượng và so sánh thứ tự nâng caoTypeError. Mỗi phương thức mặc định có thể trực tiếp tạo ra các kết quả này nhưng cũng có thể trả vềNotImplemented.Xem đoạn về
__hash__()để biết một số lưu ý quan trọng về cách tạo đối tượng hashable hỗ trợ các hoạt động so sánh tùy chỉnh và có thể sử dụng làm khóa từ điển.Không có phiên bản đối số hoán đổi của các phương thức này (được sử dụng khi đối số bên trái không hỗ trợ thao tác nhưng đối số bên phải thì có); đúng hơn,
__lt__()và__gt__()là hình ảnh phản chiếu của nhau,__le__()và__ge__()là hình ảnh phản chiếu của nhau, còn__eq__()và__ne__()là hình ảnh phản chiếu của chính chúng. Nếu các toán hạng có nhiều kiểu khác nhau và kiểu của toán hạng bên phải là lớp con trực tiếp hoặc gián tiếp của kiểu toán hạng bên trái thì phương thức phản ánh của toán hạng bên phải có mức độ ưu tiên, nếu không thì phương thức của toán hạng bên trái sẽ được ưu tiên. Phân lớp ảo không được xem xét.Khi không có phương thức thích hợp nào trả về bất kỳ giá trị nào ngoài
NotImplemented, các toán tử==và!=sẽ lần lượt quay trở lạiisvàis not.
- object.__hash__(self)¶
Được gọi bằng hàm tích hợp
hash()và dành cho các thao tác trên các thành viên của bộ sưu tập băm bao gồmset,frozensetvàdict. Phương thức__hash__()sẽ trả về một số nguyên. Thuộc tính bắt buộc duy nhất là các đối tượng so sánh bằng nhau có cùng giá trị băm; Bạn nên kết hợp các giá trị băm của các thành phần của đối tượng cũng đóng vai trò so sánh các đối tượng với nhau bằng cách đóng gói chúng thành một bộ và băm bộ đó. Ví dụ:chắc chắn __hash__(tự): hàm băm trả về((self.name, self.nick, self.color))
Ghi chú
hash()cắt bớt giá trị được trả về từ phương thức__hash__()tùy chỉnh của đối tượng thành kích thước củaPy_ssize_t. Đây thường là 8 byte trên bản dựng 64 bit và 4 byte trên bản dựng 32 bit. Nếu__hash__()của một đối tượng phải tương tác trên các bản dựng có kích thước bit khác nhau, hãy nhớ kiểm tra độ rộng trên tất cả các bản dựng được hỗ trợ. Một cách dễ dàng để làm điều này là sử dụngpython -c "import sys; print(sys.hash_info.width)".Nếu một lớp không định nghĩa phương thức
__eq__()thì nó cũng không nên định nghĩa thao tác__hash__(); nếu nó xác định__eq__()chứ không phải__hash__(), thì các phiên bản của nó sẽ không thể sử dụng được làm mục trong bộ sưu tập có thể băm. Nếu một lớp xác định các đối tượng có thể thay đổi và triển khai phương thức__eq__()thì lớp đó không nên triển khai__hash__(), vì việc triển khai các bộ sưu tập hashable yêu cầu giá trị băm của khóa là không thay đổi (nếu giá trị băm của đối tượng thay đổi thì nó sẽ nằm trong nhóm băm sai).Các lớp do người dùng định nghĩa có các phương thức
__eq__()và__hash__()theo mặc định (được kế thừa từ lớpobject); với chúng, tất cả các đối tượng đều so sánh không bằng nhau (ngoại trừ với chính chúng) vàx.__hash__()trả về một giá trị thích hợp sao chox == yngụ ý cảx is yvàhash(x) == hash(y).Một lớp ghi đè
__eq__()và không xác định__hash__()sẽ có__hash__()được đặt ngầm định thànhNone. Khi phương thức__hash__()của một lớp làNone, các phiên bản của lớp đó sẽ đưa ra mộtTypeErrorthích hợp khi một chương trình cố gắng truy xuất giá trị băm của chúng và cũng sẽ được xác định chính xác là không thể băm được khi kiểm traisinstance(obj, collections.abc.Hashable).Nếu một lớp ghi đè
__eq__()cần giữ lại việc triển khai__hash__()từ lớp cha, thì trình thông dịch phải được thông báo rõ ràng điều này bằng cách đặt__hash__ = <ParentClass>.__hash__.Nếu một lớp không ghi đè
__eq__()muốn ngăn chặn hỗ trợ băm thì lớp đó phải bao gồm__hash__ = Nonetrong định nghĩa lớp. Một lớp xác định__hash__()của chính nó mà tăngTypeErrormột cách rõ ràng sẽ bị xác định không chính xác là có thể băm được bằng lệnh gọiisinstance(obj, collections.abc.Hashable).Ghi chú
Theo mặc định, các giá trị
__hash__()của các đối tượng str và byte được "ướp muối" bằng một giá trị ngẫu nhiên không thể đoán trước. Mặc dù chúng không đổi trong một quy trình Python riêng lẻ, nhưng chúng không thể dự đoán được giữa các lần gọi Python lặp đi lặp lại.Điều này nhằm mục đích cung cấp khả năng bảo vệ chống lại tình trạng từ chối dịch vụ do các đầu vào được lựa chọn cẩn thận nhằm khai thác hiệu suất trong trường hợp xấu nhất của thao tác chèn chính tả, độ phức tạp O(n2). Xem https://ocert.org/advisories/ocert-2011-003.html để biết chi tiết.
Việc thay đổi giá trị băm ảnh hưởng đến thứ tự lặp của tập hợp. Python chưa bao giờ đưa ra đảm bảo về thứ tự này (và nó thường thay đổi giữa các bản dựng 32 bit và 64 bit).
Xem thêm
PYTHONHASHSEED.Thay đổi trong phiên bản 3.3: Tính năng ngẫu nhiên băm được bật theo mặc định.
- object.__bool__(self)¶
Được gọi để triển khai kiểm tra giá trị thực và hoạt động tích hợp
bool(); nên trả vềFalsehoặcTrue. Khi phương thức này không được xác định,__len__()sẽ được gọi nếu nó được xác định và đối tượng được coi là đúng nếu kết quả của nó khác 0. Nếu một lớp không xác định__len__()hay__bool__()(điều này đúng với chính lớpobject), thì tất cả các phiên bản của nó đều được coi là đúng.
3.3.2. Tùy chỉnh quyền truy cập thuộc tính¶
Các phương thức sau đây có thể được định nghĩa để tùy chỉnh ý nghĩa của việc truy cập thuộc tính (sử dụng, gán hoặc xóa x.name) cho các thể hiện của lớp.
- object.__getattr__(self, name)¶
Được gọi khi truy cập thuộc tính mặc định không thành công với
AttributeError(__getattribute__()tăngAttributeErrorvì name không phải là thuộc tính phiên bản hoặc thuộc tính trong cây lớp choself; hoặc__get__()của thuộc tính name tăngAttributeError). Phương thức này sẽ trả về giá trị thuộc tính (được tính toán) hoặc đưa ra ngoại lệAttributeError. Bản thân lớpobjectkhông cung cấp phương thức này.Lưu ý rằng nếu thuộc tính được tìm thấy thông qua cơ chế thông thường,
__getattr__()sẽ không được gọi. (Đây là sự bất đối xứng có chủ ý giữa__getattr__()và__setattr__().) Điều này được thực hiện vì lý do hiệu quả và vì nếu không thì__getattr__()sẽ không có cách nào để truy cập các thuộc tính khác của phiên bản. Lưu ý rằng ít nhất đối với các biến mẫu, bạn có thể kiểm soát hoàn toàn bằng cách không chèn bất kỳ giá trị nào vào từ điển thuộc tính mẫu (mà thay vào đó chèn chúng vào một đối tượng khác). Xem phương pháp__getattribute__()bên dưới để biết cách thực sự có được toàn quyền kiểm soát quyền truy cập thuộc tính.
- object.__getattribute__(self, name)¶
Được gọi vô điều kiện để thực hiện truy cập thuộc tính cho các thể hiện của lớp. Nếu lớp cũng định nghĩa
__getattr__()thì lớp sau sẽ không được gọi trừ khi__getattribute__()gọi nó một cách rõ ràng hoặc tăngAttributeError. Phương thức này sẽ trả về giá trị thuộc tính (được tính toán) hoặc đưa ra một ngoại lệAttributeError. Để tránh đệ quy vô hạn trong phương thức này, việc triển khai nó phải luôn gọi phương thức lớp cơ sở có cùng tên để truy cập bất kỳ thuộc tính nào nó cần, ví dụ:object.__getattribute__(self, name).Ghi chú
Phương thức này vẫn có thể bị bỏ qua khi tra cứu các phương thức đặc biệt do lệnh gọi ngầm thông qua cú pháp ngôn ngữ hoặc built-in functions. Xem Tra cứu phương pháp đặc biệt.
Đối với các quyền truy cập thuộc tính nhạy cảm nhất định, hãy tăng auditing event
object.__getattr__với các đối sốobjvàname.
- object.__setattr__(self, name, value)¶
Được gọi khi cố gắng gán thuộc tính. Điều này được gọi thay vì cơ chế thông thường (tức là lưu trữ giá trị trong từ điển mẫu). name là tên thuộc tính, value là giá trị được gán cho nó.
Nếu
__setattr__()muốn gán cho một thuộc tính instance, nó nên gọi phương thức lớp cơ sở có cùng tên, ví dụ:object.__setattr__(self, name, value).Đối với một số phép gán thuộc tính nhạy cảm nhất định, hãy tăng auditing event
object.__setattr__với các đối sốobj,name,value.
- object.__delattr__(self, name)¶
Giống như
__setattr__()nhưng để xóa thuộc tính thay vì gán. Điều này chỉ nên được thực hiện nếudel obj.namecó ý nghĩa đối với đối tượng.Đối với một số thao tác xóa thuộc tính nhạy cảm nhất định, hãy tăng auditing event
object.__delattr__với các đối sốobjvàname.
- object.__dir__(self)¶
Được gọi khi
dir()được gọi trên đối tượng. Một lần lặp phải được trả lại.dir()chuyển đổi iterable được trả về thành một danh sách và sắp xếp nó.
3.3.2.1. Tùy chỉnh quyền truy cập thuộc tính mô-đun¶
Tên đặc biệt __getattr__ và __dir__ cũng có thể được sử dụng để tùy chỉnh quyền truy cập vào các thuộc tính mô-đun. Hàm __getattr__ ở cấp mô-đun phải chấp nhận một đối số là tên của thuộc tính và trả về giá trị được tính toán hoặc tăng AttributeError. Nếu không tìm thấy thuộc tính trên đối tượng mô-đun thông qua tra cứu thông thường, tức là object.__getattribute__(), thì __getattr__ sẽ được tìm kiếm trong mô-đun __dict__ trước khi đưa ra AttributeError. Nếu tìm thấy, nó sẽ được gọi với tên thuộc tính và kết quả được trả về.
Hàm __dir__ không được chấp nhận đối số và trả về một chuỗi lặp đại diện cho các tên có thể truy cập được trên mô-đun. Nếu có, chức năng này sẽ ghi đè tìm kiếm dir() tiêu chuẩn trên mô-đun.
- module.__class__¶
Để tùy chỉnh chi tiết hơn hành vi mô-đun (cài đặt thuộc tính, thuộc tính, v.v.), người ta có thể đặt thuộc tính __class__ của đối tượng mô-đun thành lớp con của types.ModuleType. Ví dụ:
hệ thống nhập khẩu
từ các loại nhập ModuleType
lớp VerboseModule(ModuleType):
chắc chắn __repr__(tự):
return f'Verbose {self.__name__}'
def __setattr__(self, attr, value):
print(f'Đặt {attr}...')
super().__setattr__(attr, giá trị)
sys.modules[__name__].__class__ = VerboseModule
Ghi chú
Việc xác định mô-đun __getattr__ và cài đặt mô-đun __class__ chỉ ảnh hưởng đến việc tra cứu được thực hiện bằng cú pháp truy cập thuộc tính -- việc truy cập trực tiếp vào các phần tổng thể của mô-đun (cho dù bằng mã trong mô-đun hay thông qua tham chiếu đến từ điển toàn cục của mô-đun) không bị ảnh hưởng.
Thay đổi trong phiên bản 3.5: Thuộc tính mô-đun __class__ hiện có thể ghi được.
Added in version 3.7: Thuộc tính mô-đun __getattr__ và __dir__.
Xem thêm
- PEP 562 - Mô-đun __getattr__ và __dir__
Mô tả các chức năng
__getattr__và__dir__trên mô-đun.
3.3.2.2. Triển khai mô tả¶
Các phương thức sau chỉ áp dụng khi một thể hiện của lớp chứa phương thức (còn gọi là lớp descriptor) xuất hiện trong lớp owner (bộ mô tả phải có trong từ điển lớp của chủ sở hữu hoặc trong từ điển lớp của một trong các cha mẹ của nó). Trong các ví dụ bên dưới, "thuộc tính" đề cập đến thuộc tính có tên là khóa của thuộc tính trong __dict__ của lớp chủ sở hữu. Bản thân lớp object không triển khai bất kỳ giao thức nào trong số này.
- object.__get__(self, instance, owner=None)¶
Được gọi để lấy thuộc tính của lớp chủ sở hữu (quyền truy cập thuộc tính lớp) hoặc của một thể hiện của lớp đó (quyền truy cập thuộc tính thể hiện). Đối số owner tùy chọn là lớp chủ sở hữu, trong khi instance là phiên bản mà thuộc tính được truy cập thông qua hoặc
Nonekhi thuộc tính được truy cập thông qua owner.Phương thức này sẽ trả về giá trị thuộc tính được tính toán hoặc đưa ra ngoại lệ
AttributeError.PEP 252 chỉ định rằng
__get__()có thể gọi được với một hoặc hai đối số. Các bộ mô tả tích hợp sẵn của Python hỗ trợ thông số kỹ thuật này; tuy nhiên, có khả năng một số công cụ của bên thứ ba có bộ mô tả yêu cầu cả hai đối số. Việc triển khai__getattribute__()của Python luôn chuyển cả hai đối số cho dù chúng có được yêu cầu hay không.
- object.__set__(self, instance, value)¶
Được gọi để đặt thuộc tính trên một thể hiện instance của lớp chủ sở hữu thành một giá trị mới, value.
Lưu ý, việc thêm
__set__()hoặc__delete__()sẽ thay đổi loại bộ mô tả thành "bộ mô tả dữ liệu". Xem Gọi mô tả để biết thêm chi tiết.
- object.__delete__(self, instance)¶
Được gọi để xóa thuộc tính trên một thể hiện instance của lớp chủ sở hữu.
Các phiên bản của bộ mô tả cũng có thể có thuộc tính __objclass__:
- object.__objclass__¶
Thuộc tính
__objclass__được mô-đuninspectdiễn giải là chỉ định lớp nơi đối tượng này được xác định (việc thiết lập thuộc tính này một cách thích hợp có thể hỗ trợ việc xem xét nội tâm thời gian chạy của các thuộc tính lớp động). Đối với các lệnh gọi được, nó có thể chỉ ra rằng một phiên bản của loại đã cho (hoặc một lớp con) được mong đợi hoặc được yêu cầu làm đối số vị trí đầu tiên (ví dụ: CPython đặt thuộc tính này cho các phương thức không liên kết được triển khai trong C).
3.3.2.3. Gọi mô tả¶
Nói chung, bộ mô tả là một thuộc tính đối tượng có "hành vi liên kết", một thuộc tính có quyền truy cập thuộc tính đã bị ghi đè bởi các phương thức trong giao thức bộ mô tả: __get__(), __set__() và __delete__(). Nếu bất kỳ phương thức nào trong số đó được xác định cho một đối tượng thì nó được gọi là một bộ mô tả.
Hành vi mặc định để truy cập thuộc tính là lấy, đặt hoặc xóa thuộc tính khỏi từ điển của đối tượng. Ví dụ: a.x có chuỗi tra cứu bắt đầu bằng a.__dict__['x'], sau đó là type(a).__dict__['x'] và tiếp tục đến các lớp cơ sở của type(a) ngoại trừ siêu dữ liệu.
Tuy nhiên, nếu giá trị tra cứu là một đối tượng xác định một trong các phương thức mô tả thì Python có thể ghi đè hành vi mặc định và gọi phương thức mô tả thay thế. Trường hợp điều này xảy ra trong chuỗi ưu tiên phụ thuộc vào phương thức mô tả nào được xác định và cách chúng được gọi.
Điểm bắt đầu cho việc gọi bộ mô tả là một ràng buộc, a.x. Cách tập hợp các đối số phụ thuộc vào a:
- Gọi trực tiếp
Lệnh gọi đơn giản và ít phổ biến nhất là khi mã người dùng gọi trực tiếp một phương thức mô tả:
x.__get__(a).- Ràng buộc cá thể
Nếu liên kết với một phiên bản đối tượng,
a.xsẽ được chuyển thành lệnh gọi:type(a).__dict__['x'].__get__(a, type(a)).- Ràng buộc lớp
Nếu liên kết với một lớp,
A.xsẽ được chuyển thành lệnh gọi:A.__dict__['x'].__get__(None, A).- siêu ràng buộc
Tra cứu theo dấu chấm chẳng hạn như
super(A, a).xtìm kiếma.__class__.__mro__để tìm lớp cơ sởBtheo sauAvà sau đó trả vềB.__dict__['x'].__get__(a, A). Nếu không phải là bộ mô tả,xsẽ được trả về không thay đổi.
Đối với các ràng buộc thể hiện, độ ưu tiên của việc gọi bộ mô tả phụ thuộc vào phương thức mô tả nào được xác định. Một bộ mô tả có thể xác định bất kỳ sự kết hợp nào của __get__(), __set__() và __delete__(). Nếu nó không xác định __get__() thì việc truy cập vào thuộc tính sẽ trả về chính đối tượng mô tả trừ khi có một giá trị trong từ điển đối tượng của đối tượng. Nếu bộ mô tả xác định __set__() và/hoặc __delete__() thì đó là bộ mô tả dữ liệu; nếu nó không xác định thì đó là một bộ mô tả phi dữ liệu. Thông thường, các bộ mô tả dữ liệu xác định cả __get__() và __set__(), trong khi các bộ mô tả không phải dữ liệu chỉ có phương thức __get__(). Bộ mô tả dữ liệu có __get__() và __set__() (và/hoặc __delete__()) được xác định luôn ghi đè định nghĩa lại trong từ điển phiên bản. Ngược lại, các bộ mô tả phi dữ liệu có thể bị ghi đè bởi các phiên bản.
Các phương thức Python (bao gồm cả các phương thức được trang trí bằng @staticmethod và @classmethod) được triển khai dưới dạng mô tả phi dữ liệu. Theo đó, các instance có thể định nghĩa lại và ghi đè các phương thức. Điều này cho phép các cá thể riêng lẻ có được các hành vi khác với các cá thể khác trong cùng một lớp.
Hàm property() được triển khai dưới dạng mô tả dữ liệu. Theo đó, các thể hiện không thể ghi đè hành vi của một thuộc tính.
3.3.2.4. __khe__¶
__slots__ cho phép chúng tôi khai báo rõ ràng các thành viên dữ liệu (như thuộc tính) và từ chối việc tạo __dict__ và __weakref__ (trừ khi được khai báo rõ ràng trong __slots__ hoặc có sẵn trong cha mẹ.)
Dung lượng được tiết kiệm khi sử dụng __dict__ có thể rất đáng kể. Tốc độ tra cứu thuộc tính cũng có thể được cải thiện đáng kể.
- object.__slots__¶
Biến lớp này có thể được gán một chuỗi, có thể lặp hoặc chuỗi các chuỗi có tên biến được sử dụng bởi các phiên bản. __slots__ dành không gian cho các biến được khai báo và ngăn việc tự động tạo
__dict__và __weakref__ cho mỗi phiên bản.
Những lưu ý khi sử dụng __slots__:
Khi kế thừa từ một lớp không có __slots__, thuộc tính
__dict__và __weakref__ của các phiên bản sẽ luôn có thể truy cập được.Nếu không có biến
__dict__, các phiên bản không thể được gán các biến mới không được liệt kê trong định nghĩa __slots__. Nỗ lực gán cho một tên biến không được liệt kê sẽ tăngAttributeError. Nếu muốn gán động các biến mới, thì hãy thêm'__dict__'vào chuỗi các chuỗi trong khai báo __slots__.Nếu không có biến __weakref__ cho mỗi phiên bản, các lớp xác định __slots__ sẽ không hỗ trợ
weak referencescho các phiên bản của nó. Nếu cần hỗ trợ tham chiếu yếu thì hãy thêm'__weakref__'vào chuỗi các chuỗi trong khai báo __slots__.__slots__ được triển khai ở cấp lớp bằng cách tạo descriptors cho mỗi tên biến. Do đó, các thuộc tính lớp không thể được sử dụng để đặt giá trị mặc định cho các biến thể hiện được xác định bởi __slots__; nếu không, thuộc tính lớp sẽ ghi đè lên phần gán mô tả.
Hành động của khai báo __slots__ không bị giới hạn ở lớp nơi nó được xác định. __slots__ được khai báo trong lớp cha có sẵn trong lớp con. Tuy nhiên, các phiên bản của lớp con con sẽ nhận được
__dict__và __weakref__ trừ khi lớp con đó cũng xác định __slots__ (chỉ nên chứa tên của bất kỳ vị trí additional nào).Nếu một lớp xác định một vị trí cũng được xác định trong một lớp cơ sở, thì biến thể hiện được xác định bởi vị trí của lớp cơ sở sẽ không thể truy cập được (ngoại trừ bằng cách truy xuất bộ mô tả của nó trực tiếp từ lớp cơ sở). Điều này làm cho ý nghĩa của chương trình không được xác định. Trong tương lai, một kiểm tra có thể được thêm vào để ngăn chặn điều này.
TypeErrorsẽ được tăng lên nếu __slots__ không trống được xác định cho một lớp bắt nguồn từ"variable-length" built-in typechẳng hạn nhưint,bytesvàtuple.Bất kỳ iterable không phải chuỗi nào cũng có thể được gán cho __slots__.
Nếu
dictionaryđược sử dụng để gán __slots__, các khóa từ điển sẽ được sử dụng làm tên vị trí. Các giá trị của từ điển có thể được sử dụng để cung cấp các chuỗi tài liệu cho mỗi thuộc tính sẽ đượcinspect.getdoc()nhận dạng và hiển thị trong đầu ra củahelp().Phép gán
__class__chỉ hoạt động nếu cả hai lớp có cùng __slots__.Có thể sử dụng Multiple inheritance với nhiều lớp cha mẹ có khe cắm, nhưng chỉ một lớp cha mẹ được phép có các thuộc tính được tạo bởi các vị trí (các cơ sở khác phải có bố cục vị trí trống) - vi phạm tăng
TypeError.Nếu iterator được sử dụng cho __slots__ thì descriptor sẽ được tạo cho mỗi giá trị của trình vòng lặp. Tuy nhiên, thuộc tính __slots__ sẽ là một trình lặp trống.
3.3.3. Tùy chỉnh việc tạo lớp¶
Bất cứ khi nào một lớp kế thừa từ một lớp khác, __init_subclass__() sẽ được gọi trên lớp cha. Bằng cách này, có thể viết các lớp thay đổi hành vi của các lớp con. Điều này liên quan chặt chẽ đến các trình trang trí lớp, nhưng trong đó các trình trang trí lớp chỉ ảnh hưởng đến lớp cụ thể mà chúng được áp dụng, thì __init_subclass__ chỉ áp dụng cho các lớp con trong tương lai của lớp xác định phương thức.
- classmethod object.__init_subclass__(cls)¶
Phương thức này được gọi bất cứ khi nào lớp chứa được phân lớp. cls sau đó sẽ là lớp con mới. Nếu được định nghĩa như một phương thức cá thể thông thường, thì phương thức này được chuyển đổi hoàn toàn thành một phương thức lớp.
Các đối số từ khóa được cấp cho một lớp mới sẽ được chuyển tới
__init_subclass__của lớp cha. Để tương thích với các lớp khác sử dụng__init_subclass__, người ta nên loại bỏ các đối số từ khóa cần thiết và chuyển các đối số từ khóa khác sang lớp cơ sở, như trongLớp triết gia: def __init_subclass__(cls, /, default_name, **kwargs): super().__init_subclass__(**kwargs) cls.default_name = tên_mặc định lớp AustralianPhilosopher(Triết gia, default_name="Bruce"): vượt qua
Việc triển khai mặc định
object.__init_subclass__không làm gì cả nhưng sẽ gây ra lỗi nếu nó được gọi với bất kỳ đối số nào.Ghi chú
Gợi ý siêu dữ liệu
metaclassđược sử dụng bởi phần còn lại của loại máy móc và không bao giờ được chuyển sang triển khai__init_subclass__. Siêu dữ liệu thực tế (chứ không phải gợi ý rõ ràng) có thể được truy cập dưới dạngtype(cls).Added in version 3.6.
Khi một lớp được tạo, type.__new__() sẽ quét các biến của lớp và thực hiện lệnh gọi lại những biến có móc __set_name__().
- object.__set_name__(self, owner, name)¶
Tự động được gọi vào thời điểm lớp sở hữu owner được tạo. Đối tượng đã được gán cho name trong lớp đó:
lớp A: x = C() # Automatically gọi: x.__set_name__(A, 'x')
Nếu biến lớp được gán sau khi lớp được tạo,
__set_name__()sẽ không được gọi tự động. Nếu cần,__set_name__()có thể được gọi trực tiếp:lớp A: vượt qua c = C() A.x = c # The hook không được gọi c.__set_name__(A, 'x') # Manually gọi hook
Xem Tạo đối tượng lớp để biết thêm chi tiết.
Added in version 3.6.
3.3.3.1. Siêu lớp¶
Theo mặc định, các lớp được xây dựng bằng type(). Nội dung lớp được thực thi trong một không gian tên mới và tên lớp được liên kết cục bộ với kết quả của type(name, bases, namespace).
Quá trình tạo lớp có thể được tùy chỉnh bằng cách chuyển đối số từ khóa metaclass trong dòng định nghĩa lớp hoặc bằng cách kế thừa từ một lớp hiện có có chứa đối số như vậy. Trong ví dụ sau, cả MyClass và MySubclass đều là phiên bản của Meta:
lớp Meta(loại):
vượt qua
lớp MyClass(metaclass=Meta):
vượt qua
lớp MySubclass(MyClass):
vượt qua
Bất kỳ đối số từ khóa nào khác được chỉ định trong định nghĩa lớp đều được chuyển qua tất cả các hoạt động siêu dữ liệu được mô tả bên dưới.
Khi một định nghĩa lớp được thực thi, các bước sau sẽ xảy ra:
các mục MRO được giải quyết;
siêu dữ liệu thích hợp được xác định;
không gian tên lớp đã được chuẩn bị;
thân lớp được thực thi;
đối tượng lớp được tạo ra.
3.3.3.2. Giải quyết các mục MRO¶
- object.__mro_entries__(self, bases)¶
Nếu cơ sở xuất hiện trong định nghĩa lớp không phải là một phiên bản của
typethì phương thức__mro_entries__()sẽ được tìm kiếm trên cơ sở đó. Nếu tìm thấy phương thức__mro_entries__(), cơ sở sẽ được thay thế bằng kết quả của lệnh gọi tới__mro_entries__()khi tạo lớp. Phương thức này được gọi với bộ dữ liệu cơ sở ban đầu được truyền cho tham số bases và phải trả về một bộ dữ liệu các lớp sẽ được sử dụng thay vì cơ sở. Bộ dữ liệu trả về có thể trống: trong những trường hợp này, cơ sở ban đầu bị bỏ qua.
Xem thêm
types.resolve_bases()Tự động giải quyết các cơ sở không phải là phiên bản của
type.types.get_original_bases()Truy xuất "cơ sở ban đầu" của một lớp trước khi sửa đổi bằng
__mro_entries__().- PEP 560
Hỗ trợ cốt lõi cho việc gõ mô-đun và các loại chung.
3.3.3.3. Xác định siêu dữ liệu thích hợp¶
Siêu dữ liệu thích hợp cho định nghĩa lớp được xác định như sau:
nếu không có cơ sở và siêu dữ liệu rõ ràng nào được đưa ra thì
type()sẽ được sử dụng;nếu một siêu dữ liệu rõ ràng được đưa ra và not là một phiên bản của
type()thì siêu dữ liệu đó sẽ được sử dụng trực tiếp làm siêu dữ liệu;nếu một phiên bản của
type()được đưa ra dưới dạng siêu dữ liệu rõ ràng hoặc các cơ sở được xác định thì siêu dữ liệu dẫn xuất nhiều nhất sẽ được sử dụng.
Siêu dữ liệu dẫn xuất nhiều nhất được chọn từ siêu dữ liệu được chỉ định rõ ràng (nếu có) và siêu dữ liệu (tức là type(cls)) của tất cả các lớp cơ sở được chỉ định. Siêu lớp có nguồn gốc nhiều nhất là siêu lớp là một kiểu con của all trong số các siêu lớp ứng cử viên này. Nếu không có siêu dữ liệu ứng cử viên nào đáp ứng tiêu chí đó thì định nghĩa lớp sẽ thất bại với TypeError.
3.3.3.4. Chuẩn bị không gian tên lớp¶
Khi siêu dữ liệu thích hợp đã được xác định thì không gian tên lớp sẽ được chuẩn bị. Nếu siêu dữ liệu có thuộc tính __prepare__ thì nó được gọi là namespace = metaclass.__prepare__(name, bases, **kwds) (trong đó các đối số từ khóa bổ sung, nếu có, đến từ định nghĩa lớp). Phương thức __prepare__ nên được triển khai dưới dạng classmethod. Không gian tên được trả về bởi __prepare__ sẽ được chuyển vào __new__, nhưng khi đối tượng lớp cuối cùng được tạo thì không gian tên đó sẽ được sao chép vào một dict mới.
Nếu siêu dữ liệu không có thuộc tính __prepare__ thì không gian tên lớp sẽ được khởi tạo dưới dạng ánh xạ có thứ tự trống.
Xem thêm
- PEP 3115 - Siêu dữ liệu trong Python 3000
Giới thiệu hook không gian tên
__prepare__
3.3.3.5. Thực thi thân lớp¶
Phần thân lớp được thực thi (xấp xỉ) dưới dạng exec(body, globals(), namespace). Sự khác biệt chính so với lệnh gọi thông thường tới exec() là phạm vi từ vựng cho phép nội dung lớp (bao gồm mọi phương thức) tham chiếu tên từ phạm vi hiện tại và phạm vi bên ngoài khi định nghĩa lớp xảy ra bên trong một hàm.
Tuy nhiên, ngay cả khi định nghĩa lớp xảy ra bên trong hàm, các phương thức được định nghĩa bên trong lớp vẫn không thể thấy tên được định nghĩa ở phạm vi lớp. Các biến lớp phải được truy cập thông qua tham số đầu tiên của các phương thức lớp hoặc thể hiện hoặc thông qua tham chiếu __class__ có phạm vi từ vựng ngầm được mô tả trong phần tiếp theo.
3.3.3.6. Tạo đối tượng lớp¶
Khi không gian tên lớp đã được điền bằng cách thực thi phần thân lớp, đối tượng lớp sẽ được tạo bằng cách gọi metaclass(name, bases, namespace, **kwds) (các từ khóa bổ sung được truyền ở đây giống như các từ khóa được truyền cho __prepare__).
Đối tượng lớp này là đối tượng sẽ được tham chiếu bởi dạng không đối số của super(). __class__ là một tham chiếu đóng ngầm được tạo bởi trình biên dịch nếu bất kỳ phương thức nào trong nội dung lớp tham chiếu đến __class__ hoặc super. Điều này cho phép dạng đối số 0 của super() xác định chính xác lớp đang được xác định dựa trên phạm vi từ vựng, trong khi lớp hoặc phiên bản được sử dụng để thực hiện lệnh gọi hiện tại được xác định dựa trên đối số đầu tiên được truyền cho phương thức.
Trong CPython 3.6 trở lên, ô __class__ được chuyển đến siêu dữ liệu dưới dạng mục nhập __classcell__ trong không gian tên lớp. Nếu có, điều này phải được truyền tới lệnh gọi type.__new__ để lớp được khởi tạo chính xác. Không làm như vậy sẽ dẫn đến RuntimeError trong Python 3.8.
Khi sử dụng siêu dữ liệu mặc định type hoặc bất kỳ siêu dữ liệu nào cuối cùng gọi type.__new__, các bước tùy chỉnh bổ sung sau đây sẽ được gọi sau khi tạo đối tượng lớp:
Phương thức
type.__new__thu thập tất cả các thuộc tính trong không gian tên lớp xác định phương thức__set_name__();Các phương thức
__set_name__đó được gọi với lớp được xác định và tên được gán của thuộc tính cụ thể đó;Hook
__init_subclass__()được gọi trên lớp cha trực tiếp của lớp mới theo thứ tự phân giải phương thức của nó.
Sau khi đối tượng lớp được tạo, nó được chuyển tới các trình trang trí lớp có trong định nghĩa lớp (nếu có) và đối tượng kết quả được liên kết trong không gian tên cục bộ như lớp được xác định.
Khi một lớp mới được tạo bởi type.__new__, đối tượng được cung cấp làm tham số không gian tên sẽ được sao chép sang ánh xạ có thứ tự mới và đối tượng ban đầu sẽ bị loại bỏ. Bản sao mới được bọc trong một proxy chỉ đọc, trở thành thuộc tính __dict__ của đối tượng lớp.
Xem thêm
- PEP 3135 - Siêu phẩm mới
Mô tả tham chiếu đóng
__class__ngầm định
3.3.3.7. Sử dụng cho siêu dữ liệu¶
Khả năng sử dụng siêu dữ liệu là vô hạn. Một số ý tưởng đã được khám phá bao gồm enum, ghi nhật ký, kiểm tra giao diện, ủy quyền tự động, tạo thuộc tính tự động, proxy, khung và khóa/đồng bộ hóa tài nguyên tự động.
3.3.4. Tùy chỉnh kiểm tra cá thể và lớp con¶
Các phương pháp sau đây được sử dụng để ghi đè hành vi mặc định của các hàm dựng sẵn isinstance() và issubclass().
Đặc biệt, siêu dữ liệu abc.ABCMeta triển khai các phương thức này để cho phép bổ sung các Lớp cơ sở trừu tượng (ABC) làm "lớp cơ sở ảo" cho bất kỳ lớp hoặc loại nào (bao gồm cả các loại dựng sẵn), bao gồm cả các ABC khác.
- type.__instancecheck__(self, instance)¶
Trả về true nếu instance được coi là một phiên bản (trực tiếp hoặc gián tiếp) của class. Nếu được xác định, sẽ được gọi để triển khai
isinstance(instance, class).
- type.__subclasscheck__(self, subclass)¶
Trả về true nếu subclass được coi là lớp con (trực tiếp hoặc gián tiếp) của class. Nếu được xác định, sẽ được gọi để triển khai
issubclass(subclass, class).
Lưu ý rằng các phương thức này được tra cứu theo kiểu (siêu lớp) của một lớp. Chúng không thể được định nghĩa là các phương thức lớp trong lớp thực tế. Điều này nhất quán với việc tra cứu các phương thức đặc biệt được gọi trên các thể hiện, chỉ trong trường hợp này bản thân thể hiện đó là một lớp.
Xem thêm
- PEP 3119 - Giới thiệu các lớp cơ sở trừu tượng
Bao gồm thông số kỹ thuật để tùy chỉnh hành vi
isinstance()vàissubclass()thông qua__instancecheck__()và__subclasscheck__(), với động lực cho chức năng này trong bối cảnh thêm các Lớp cơ sở trừu tượng (xem mô-đunabc) vào ngôn ngữ.
3.3.5. Mô phỏng các loại chung¶
Khi sử dụng type annotations, việc parameterize a generic type sử dụng ký hiệu dấu ngoặc vuông của Python thường rất hữu ích. Ví dụ: chú thích list[int] có thể được sử dụng để biểu thị list trong đó tất cả các phần tử đều thuộc loại int.
Xem thêm
- PEP 484 - Gợi ý gõ
Giới thiệu khung công tác chú thích kiểu của Python
- Generic Alias Types
Tài liệu cho các đối tượng đại diện cho các lớp chung được tham số hóa
- Thuốc gốc, user-defined generics và
typing.Generic Tài liệu về cách triển khai các lớp chung có thể được tham số hóa trong thời gian chạy và được trình kiểm tra kiểu tĩnh hiểu được.
Một lớp generally chỉ có thể được tham số hóa nếu nó định nghĩa phương thức lớp đặc biệt __class_getitem__().
- classmethod object.__class_getitem__(cls, key)¶
Trả về một đối tượng biểu thị sự chuyên môn hóa của một lớp chung theo các đối số kiểu được tìm thấy trong key.
Khi được định nghĩa trên một lớp,
__class_getitem__()tự động là một phương thức lớp. Như vậy, không cần thiết phải trang trí nó bằng@classmethodkhi nó được xác định.
3.3.5.1. Mục đích của __class_getitem__¶
Mục đích của __class_getitem__() là cho phép tham số hóa thời gian chạy của các lớp chung trong thư viện tiêu chuẩn để dễ dàng áp dụng type hints cho các lớp này.
Để triển khai các lớp chung tùy chỉnh có thể được tham số hóa trong thời gian chạy và được trình kiểm tra loại tĩnh hiểu, người dùng nên kế thừa từ một lớp thư viện tiêu chuẩn đã triển khai __class_getitem__() hoặc kế thừa từ typing.Generic, lớp này có cách triển khai __class_getitem__() riêng.
Việc triển khai tùy chỉnh __class_getitem__() trên các lớp được xác định bên ngoài thư viện tiêu chuẩn có thể không được các trình kiểm tra loại của bên thứ ba như mypy hiểu được. Không nên sử dụng __class_getitem__() trên bất kỳ lớp nào cho các mục đích khác ngoài gợi ý kiểu.
3.3.5.2. __class_getitem__ so với __getitem__¶
Thông thường, subscription của một đối tượng sử dụng dấu ngoặc vuông sẽ gọi phương thức cá thể __getitem__() được xác định trên lớp của đối tượng. Tuy nhiên, nếu đối tượng được đăng ký chính là một lớp thì phương thức lớp __class_getitem__() có thể được gọi thay thế. __class_getitem__() sẽ trả về một đối tượng GenericAlias nếu nó được xác định đúng.
Được trình bày cùng với expression obj[x], trình thông dịch Python tuân theo quy trình giống như sau để quyết định xem nên gọi __getitem__() hay __class_getitem__():
từ kiểm tra nhập khẩu isclass
đăng ký def (obj, x):
"""Trả về kết quả của biểu thức 'obj[x]'"""
class_of_obj = loại(obj)
# If lớp obj định nghĩa __getitem__,
# call class_of_obj.__getitem__(obj, x)
nếu hasattr(class_of_obj, '__getitem__'):
trả về class_of_obj.__getitem__(obj, x)
# Else, nếu obj là một lớp và định nghĩa __class_getitem__,
# call obj.__class_getitem__(x)
elif isclass(obj) và hasattr(obj, '__class_getitem__'):
trả về obj.__class_getitem__(x)
# Else, đưa ra một ngoại lệ
khác:
nâng cao TypeError(
Đối tượng f"'{class_of_obj.__name__}' không thể đăng ký được"
)
Trong Python, tất cả các lớp đều là phiên bản của các lớp khác. Lớp của một lớp được gọi là metaclass của lớp đó và hầu hết các lớp đều có lớp type làm siêu dữ liệu của chúng. type không định nghĩa __getitem__(), nghĩa là các biểu thức như list[int], dict[str, float] và tuple[str, bytes] đều dẫn đến __class_getitem__() được gọi:
>>> # list có "loại" lớp làm siêu dữ liệu của nó, giống như hầu hết các lớp:
>>> loại (danh sách)
<lớp 'loại'>
>>> loại(dict) == loại(danh sách) == loại(tuple) == loại(str) == loại(byte)
đúng
>>> # "list[int]" gọi "list.__class_getitem__(int)"
>>> danh sách[int]
danh sách[int]
>>> # list.__class_getitem__ trả về một đối tượng GenericAlias:
>>> loại(danh sách[int])
<class 'types.GenericAlias'>
Tuy nhiên, nếu một lớp có siêu dữ liệu tùy chỉnh xác định __getitem__(), việc đăng ký lớp đó có thể dẫn đến hành vi khác. Bạn có thể tìm thấy ví dụ về điều này trong mô-đun enum:
>>> từ nhập enum Enum
>>> Menu lớp(Enum):
... """Thực đơn bữa sáng"""
... SPAM = 'thư rác'
... BACON = 'thịt xông khói'
...
>>> Các lớp # Enum có siêu dữ liệu tùy chỉnh:
>>> loại(Thực đơn)
<lớp 'enum.EnumMeta'>
>>> # EnumMeta định nghĩa __getitem__,
>>> # so __class_getitem__ không được gọi,
>>> # and kết quả không phải là đối tượng GenericAlias:
>>> Thực đơn['SPAM']
<Menu.SPAM: 'thư rác'>
>>> gõ(Menu['SPAM'])
<enum 'Thực đơn'>
Xem thêm
- PEP 560 - Hỗ trợ cốt lõi cho việc gõ mô-đun và các loại chung
Giới thiệu
__class_getitem__()và nêu rõ thời điểm subscription dẫn đến__class_getitem__()được gọi thay vì__getitem__()
3.3.6. Mô phỏng các đối tượng có thể gọi được¶
3.3.7. Mô phỏng các loại container¶
Các phương thức sau đây có thể được định nghĩa để triển khai các đối tượng vùng chứa. Không ai trong số chúng được cung cấp bởi chính lớp object. Các vùng chứa thường là sequences (chẳng hạn như lists hoặc tuples) hoặc mappings (như dictionaries), nhưng cũng có thể đại diện cho các vùng chứa khác. Tập hợp các phương thức đầu tiên được sử dụng để mô phỏng một chuỗi hoặc để mô phỏng một ánh xạ; sự khác biệt là đối với một chuỗi, các khóa được phép phải là số nguyên k mà 0 <= k < N trong đó N là độ dài của chuỗi hoặc đối tượng slice, xác định một phạm vi mục. Chúng tôi cũng khuyên rằng các ánh xạ nên cung cấp các phương thức keys(), values(), items(), get(), clear(), setdefault(), pop(), popitem(), copy() và update() hoạt động tương tự như các phương thức dành cho các đối tượng dictionary tiêu chuẩn của Python. Mô-đun collections.abc cung cấp MutableMapping abstract base class để giúp tạo các phương thức đó từ bộ cơ sở gồm __getitem__(), __setitem__(), __delitem__() và keys().
Các chuỗi có thể thay đổi sẽ cung cấp các phương thức append(), clear(), count(), extend(), index(), insert(), pop(), remove() và reverse(), giống như các đối tượng list tiêu chuẩn của Python. Cuối cùng, các loại trình tự nên triển khai phép cộng (nghĩa là nối) và phép nhân (nghĩa là lặp lại) bằng cách xác định các phương thức __add__(), __radd__(), __iadd__(), __mul__(), __rmul__() và __imul__() được mô tả bên dưới; họ không nên định nghĩa các toán tử số khác.
Chúng tôi khuyến nghị rằng cả ánh xạ và trình tự đều nên triển khai phương pháp __contains__() để cho phép sử dụng hiệu quả toán tử in; để ánh xạ, in sẽ tìm kiếm các khóa của ánh xạ; đối với các chuỗi, nó sẽ tìm kiếm thông qua các giá trị. Chúng tôi khuyến nghị thêm rằng cả ánh xạ và trình tự đều nên triển khai phương pháp __iter__() để cho phép lặp lại hiệu quả thông qua vùng chứa; để ánh xạ, __iter__() sẽ lặp qua các phím của đối tượng; đối với các chuỗi, nó sẽ lặp qua các giá trị.
- object.__len__(self)¶
Được gọi để triển khai chức năng tích hợp
len(). Phải trả về độ dài của đối tượng, một số nguyên>=0. Ngoài ra, một đối tượng không xác định phương thức__bool__()và có phương thức__len__()trả về 0 được coi là sai trong ngữ cảnh Boolean.Trong CPython, độ dài được yêu cầu tối đa là
sys.maxsize. Nếu độ dài lớn hơnsys.maxsizethì một số tính năng (chẳng hạn nhưlen()) có thể tăngOverflowError. Để ngăn chặn việc tăngOverflowErrorbằng cách kiểm tra giá trị thực, đối tượng phải xác định phương thức__bool__().
- object.__length_hint__(self)¶
Được gọi để triển khai
operator.length_hint(). Nên trả về độ dài ước tính cho đối tượng (có thể lớn hơn hoặc nhỏ hơn độ dài thực tế). Độ dài phải là số nguyên>=0. Giá trị trả về cũng có thể làNotImplemented, được xử lý giống như khi phương thức__length_hint__hoàn toàn không tồn tại. Phương pháp này hoàn toàn là một sự tối ưu hóa và không bao giờ cần thiết cho tính chính xác.Added in version 3.4.
- object.__getitem__(self, subscript)¶
Được gọi để triển khai subscription, tức là
self[subscript]. Xem Đăng ký và cắt lát để biết chi tiết về cú pháp.Có hai loại đối tượng tích hợp hỗ trợ đăng ký qua
__getitem__():sequences, trong đó subscript (còn gọi là index) phải là số nguyên hoặc đối tượng
slice. Xem sequence documentation để biết hành vi dự kiến, bao gồm việc xử lý các đối tượngslicevà các chỉ số tiêu cực.mappings, trong đó subscript còn được gọi là key. Xem mapping documentation để biết hành vi dự kiến.
Nếu subscript thuộc loại không phù hợp,
__getitem__()sẽ tăngTypeError. Nếu subscript có giá trị không phù hợp,__getitem__()sẽ tăngLookupErrorhoặc một trong các lớp con của nó (IndexErrorcho chuỗi;KeyErrorcho ánh xạ).Ghi chú
Việc cắt lát được xử lý bởi
__getitem__(),__setitem__()và__delitem__(). Một cuộc gọi nhưa[1:2] = b
được dịch sang
a[lát(1, 2, Không có)] = b
vân vân. Các phần tử bị thiếu luôn được điền bằng
None.Ghi chú
Giao thức lặp trình tự (ví dụ: được sử dụng trong các vòng lặp
for), hy vọng rằngIndexErrorsẽ được nâng lên đối với các chỉ mục không hợp lệ để cho phép phát hiện chính xác phần cuối của chuỗi.Ghi chú
Khi subscripting a class, phương thức lớp đặc biệt
__class_getitem__()có thể được gọi thay vì__getitem__(). Xem __class_getitem__ so với __getitem__ để biết thêm chi tiết.
- object.__setitem__(self, key, value)¶
Được gọi để thực hiện gán cho
self[key]. Lưu ý tương tự như đối với__getitem__(). Điều này chỉ nên được triển khai cho ánh xạ nếu đối tượng hỗ trợ thay đổi giá trị cho khóa hoặc nếu có thể thêm khóa mới hoặc cho chuỗi nếu các phần tử có thể được thay thế. Các ngoại lệ tương tự sẽ được đưa ra đối với các giá trị key không đúng như đối với phương pháp__getitem__().
- object.__delitem__(self, key)¶
Được gọi để thực hiện xóa
self[key]. Lưu ý tương tự như đối với__getitem__(). Điều này chỉ nên được triển khai cho ánh xạ nếu đối tượng hỗ trợ loại bỏ khóa hoặc cho chuỗi nếu các phần tử có thể bị xóa khỏi chuỗi. Các ngoại lệ tương tự sẽ được đưa ra đối với các giá trị key không đúng như đối với phương pháp__getitem__().
- object.__missing__(self, key)¶
Được gọi bởi
dict.__getitem__()để triển khaiself[key]cho các lớp con dict khi khóa không có trong từ điển.
- object.__iter__(self)¶
Phương thức này được gọi khi cần có iterator cho vùng chứa. Phương thức này sẽ trả về một đối tượng lặp mới có thể lặp qua tất cả các đối tượng trong vùng chứa. Để ánh xạ, nó sẽ lặp lại các khóa của vùng chứa.
- object.__reversed__(self)¶
Được gọi (nếu có) bởi
reversed()tích hợp để thực hiện phép lặp ngược. Nó sẽ trả về một đối tượng lặp mới lặp lại tất cả các đối tượng trong vùng chứa theo thứ tự ngược lại.Nếu phương thức
__reversed__()không được cung cấp,reversed()tích hợp sẽ quay lại sử dụng giao thức trình tự (__len__()và__getitem__()). Các đối tượng hỗ trợ giao thức trình tự chỉ nên cung cấp__reversed__()nếu chúng có thể cung cấp cách triển khai hiệu quả hơn giao thức doreversed()cung cấp.
Các toán tử kiểm tra tư cách thành viên (in và not in) thường được triển khai dưới dạng lặp qua một vùng chứa. Tuy nhiên, các đối tượng vùng chứa có thể cung cấp phương thức đặc biệt sau đây với cách triển khai hiệu quả hơn, điều này cũng không yêu cầu đối tượng phải lặp lại.
- object.__contains__(self, item)¶
Được kêu gọi thực hiện các toán tử thử nghiệm thành viên. Sẽ trả về true nếu item nằm trong self, ngược lại là false. Đối với các đối tượng ánh xạ, điều này nên xem xét các khóa của ánh xạ thay vì các giá trị hoặc cặp mục khóa.
Đối với các đối tượng không xác định
__contains__(), kiểm tra tư cách thành viên trước tiên sẽ thử lặp qua__iter__(), sau đó thử giao thức lặp trình tự cũ qua__getitem__(), xem this section in the language reference.
3.3.8. Mô phỏng các loại số¶
Các phương pháp sau đây có thể được định nghĩa để mô phỏng các đối tượng số. Các phương thức tương ứng với các phép toán không được hỗ trợ bởi loại số cụ thể được triển khai (ví dụ: các phép toán theo bit cho các số không nguyên) sẽ không được xác định.
- object.__add__(self, other)¶
- object.__sub__(self, other)¶
- object.__mul__(self, other)¶
- object.__matmul__(self, other)¶
- object.__truediv__(self, other)¶
- object.__floordiv__(self, other)¶
- object.__mod__(self, other)¶
- object.__divmod__(self, other)¶
- object.__pow__(self, other[, modulo])¶
- object.__lshift__(self, other)¶
- object.__rshift__(self, other)¶
- object.__and__(self, other)¶
- object.__xor__(self, other)¶
- object.__or__(self, other)¶
Các phương thức này được gọi để thực hiện các phép toán số học nhị phân (
+,-,*,@,/,//,%,divmod(),pow(),**,<<,>>,&,^,|). Ví dụ: để đánh giá biểu thứcx + y, trong đó x là một phiên bản của lớp có phương thức__add__(),type(x).__add__(x, y)sẽ được gọi. Phương thức__divmod__()phải tương đương với việc sử dụng__floordiv__()và__mod__(); nó không nên liên quan đến__truediv__(). Lưu ý rằng__pow__()phải được xác định để chấp nhận đối số thứ ba tùy chọn nếu phiên bản ba đối số của hàmpow()tích hợp được hỗ trợ.Nếu một trong những phương thức đó không hỗ trợ thao tác với các đối số được cung cấp thì nó sẽ trả về
NotImplemented.
- object.__radd__(self, other)¶
- object.__rsub__(self, other)¶
- object.__rmul__(self, other)¶
- object.__rmatmul__(self, other)¶
- object.__rtruediv__(self, other)¶
- object.__rfloordiv__(self, other)¶
- object.__rmod__(self, other)¶
- object.__rdivmod__(self, other)¶
- object.__rpow__(self, other[, modulo])¶
- object.__rlshift__(self, other)¶
- object.__rrshift__(self, other)¶
- object.__rand__(self, other)¶
- object.__rxor__(self, other)¶
- object.__ror__(self, other)¶
Các phương thức này được gọi để thực hiện các phép toán số học nhị phân (
+,-,*,@,/,//,%,divmod(),pow(),**,<<,>>,&,^,|) với phản xạ (hoán đổi) toán hạng. Các hàm này chỉ được gọi nếu toán hạng có kiểu khác nhau, khi toán hạng bên trái không hỗ trợ phép toán tương ứng [3], hoặc lớp của toán hạng bên phải được dẫn xuất từ lớp của toán hạng bên trái. [4] Ví dụ: để đánh giá biểu thứcx - y, trong đó y là một phiên bản của lớp có phương thức__rsub__(),type(y).__rsub__(y, x)được gọi nếutype(x).__sub__(x, y)trả vềNotImplementedhoặctype(y)là lớp con củatype(x). [5]Lưu ý rằng
__rpow__()phải được xác định để chấp nhận đối số thứ ba tùy chọn nếu phiên bản ba đối số của hàmpow()tích hợp được hỗ trợ.Thay đổi trong phiên bản 3.14:
pow()ba đối số bây giờ hãy thử gọi__rpow__()nếu cần. Trước đây nó chỉ được gọi trongpow()hai đối số và toán tử lũy thừa nhị phân.Ghi chú
Nếu loại toán hạng bên phải là lớp con của loại toán hạng bên trái và lớp con đó cung cấp cách triển khai khác của phương thức được phản ánh cho thao tác, thì phương thức này sẽ được gọi trước phương thức không được phản ánh của toán hạng bên trái. Hành vi này cho phép các lớp con ghi đè hoạt động của tổ tiên chúng.
- object.__iadd__(self, other)¶
- object.__isub__(self, other)¶
- object.__imul__(self, other)¶
- object.__imatmul__(self, other)¶
- object.__itruediv__(self, other)¶
- object.__ifloordiv__(self, other)¶
- object.__imod__(self, other)¶
- object.__ipow__(self, other[, modulo])¶
- object.__ilshift__(self, other)¶
- object.__irshift__(self, other)¶
- object.__iand__(self, other)¶
- object.__ixor__(self, other)¶
- object.__ior__(self, other)¶
Các phương thức này được gọi để thực hiện các phép gán số học tăng cường (
+=,-=,*=,@=,/=,//=,%=,**=,<<=,>>=,&=,^=,|=). Các phương thức này sẽ cố gắng thực hiện thao tác tại chỗ (sửa đổi self) và trả về kết quả (có thể là, nhưng không nhất thiết phải là self). Nếu một phương thức cụ thể không được xác định hoặc nếu phương thức đó trả vềNotImplementedthì phép gán tăng cường sẽ quay trở lại các phương thức thông thường. Chẳng hạn, nếu x là một phiên bản của một lớp có phương thức__iadd__(), thìx += ytương đương vớix = x.__iadd__(y). Nếu__iadd__()không tồn tại hoặc nếux.__iadd__(y)trả vềNotImplemented, thìx.__add__(y)vày.__radd__(x)sẽ được xem xét, như khi đánh giáx + y. Trong một số trường hợp nhất định, phép gán tăng cường có thể dẫn đến các lỗi không mong muốn (xem Tại sao a_tuple[i] += ['item'] lại đưa ra ngoại lệ khi tính năng bổ sung hoạt động?), nhưng trên thực tế, hành vi này là một phần của mô hình dữ liệu.
- object.__neg__(self)¶
- object.__pos__(self)¶
- object.__abs__(self)¶
- object.__invert__(self)¶
Được gọi để thực hiện các phép toán số học đơn phân (
-,+,abs()và~).
- object.__complex__(self)¶
- object.__int__(self)¶
- object.__float__(self)¶
Được gọi để triển khai các hàm dựng sẵn
complex(),int()vàfloat(). Nên trả về một giá trị thuộc loại thích hợp.
- object.__index__(self)¶
Được gọi để triển khai
operator.index()và bất cứ khi nào Python cần chuyển đổi một cách dễ dàng đối tượng số thành đối tượng số nguyên (chẳng hạn như khi cắt hoặc trong các hàmbin(),hex()vàoct()tích hợp sẵn). Sự hiện diện của phương thức này chỉ ra rằng đối tượng số là một kiểu số nguyên. Phải trả về một số nguyên.Nếu
__int__(),__float__()và__complex__()không được xác định thì các hàm tích hợp tương ứngint(),float()vàcomplex()sẽ quay trở lại__index__().
- object.__round__(self[, ndigits])¶
- object.__trunc__(self)¶
- object.__floor__(self)¶
- object.__ceil__(self)¶
Được gọi để triển khai hàm tích hợp
round()vàmath. Các hàmtrunc(),floor()vàceil(). Trừ khi ndigits được chuyển tới__round__(), tất cả các phương thức này sẽ trả về giá trị của đối tượng bị cắt bớt thànhIntegral(thường làint).Thay đổi trong phiên bản 3.14:
int()không còn ủy quyền cho phương thức__trunc__()nữa.
3.3.9. Với Trình quản lý bối cảnh câu lệnh¶
context manager là một đối tượng xác định bối cảnh thời gian chạy sẽ được thiết lập khi thực thi câu lệnh with. Trình quản lý bối cảnh xử lý việc nhập và thoát khỏi bối cảnh thời gian chạy mong muốn để thực thi khối mã. Trình quản lý bối cảnh thường được gọi bằng câu lệnh with (được mô tả trong phần Tuyên bố with), nhưng cũng có thể được sử dụng bằng cách gọi trực tiếp các phương thức của chúng.
Các ứng dụng điển hình của trình quản lý bối cảnh bao gồm lưu và khôi phục các loại trạng thái toàn cầu khác nhau, khóa và mở khóa tài nguyên, đóng các tệp đã mở, v.v.
Để biết thêm thông tin về trình quản lý bối cảnh, hãy xem Các loại trình quản lý bối cảnh. Bản thân lớp object không cung cấp các phương thức quản lý bối cảnh.
- object.__enter__(self)¶
Nhập bối cảnh thời gian chạy liên quan đến đối tượng này. Câu lệnh
withsẽ liên kết giá trị trả về của phương thức này với (các) mục tiêu được chỉ định trong mệnh đềascủa câu lệnh, nếu có.
- object.__exit__(self, exc_type, exc_value, traceback)¶
Thoát khỏi bối cảnh thời gian chạy liên quan đến đối tượng này. Các tham số mô tả ngoại lệ khiến ngữ cảnh bị thoát. Nếu ngữ cảnh được thoát mà không có ngoại lệ, cả ba đối số sẽ là
None.Nếu một ngoại lệ được cung cấp và phương thức muốn loại bỏ ngoại lệ đó (tức là ngăn chặn nó được lan truyền), thì nó sẽ trả về một giá trị thực. Nếu không, ngoại lệ sẽ được xử lý bình thường khi thoát khỏi phương thức này.
Lưu ý rằng các phương thức
__exit__()không được lấy lại ngoại lệ đã truyền vào; đây là trách nhiệm của người gọi.
3.3.10. Tùy chỉnh các đối số vị trí trong khớp mẫu lớp¶
Khi sử dụng tên lớp trong một mẫu, theo mặc định, các đối số vị trí trong mẫu không được phép, tức là case MyClass(x, y) thường không hợp lệ nếu không có hỗ trợ đặc biệt trong MyClass. Để có thể sử dụng loại mẫu đó, lớp cần xác định thuộc tính __match_args__.
- object.__match_args__¶
Biến lớp này có thể được gán một bộ chuỗi. Khi lớp này được sử dụng trong mẫu lớp có đối số vị trí, mỗi đối số vị trí sẽ được chuyển đổi thành đối số từ khóa, sử dụng giá trị tương ứng trong __match_args__ làm từ khóa. Việc thiếu thuộc tính này tương đương với việc đặt nó thành
().
Ví dụ: nếu MyClass.__match_args__ là ("left", "center", "right") thì có nghĩa là case MyClass(x, y) tương đương với case MyClass(left=x, center=y). Lưu ý rằng số lượng đối số trong mẫu phải nhỏ hơn hoặc bằng số phần tử trong __match_args__; nếu nó lớn hơn, nỗ lực khớp mẫu sẽ tăng TypeError.
Added in version 3.10.
Xem thêm
- PEP 634 - Khớp mẫu cấu trúc
Đặc tả cho câu lệnh
matchcủa Python.
3.3.11. Mô phỏng các loại bộ đệm¶
Zz000zz cung cấp một cách để các đối tượng Python có khả năng truy cập hiệu quả vào mảng bộ nhớ cấp thấp. Giao thức này được triển khai bởi các loại dựng sẵn như bytes và memoryview và các thư viện của bên thứ ba có thể xác định các loại bộ đệm bổ sung.
Mặc dù các loại bộ đệm thường được triển khai bằng C, nhưng cũng có thể triển khai giao thức bằng Python.
- object.__buffer__(self, flags)¶
Được gọi khi bộ đệm được yêu cầu từ self (ví dụ: bởi hàm tạo
memoryview). Đối số flags là một số nguyên biểu thị loại bộ đệm được yêu cầu, ví dụ như ảnh hưởng đến việc bộ đệm được trả về là chỉ đọc hay có thể ghi.inspect.BufferFlagscung cấp một cách thuận tiện để diễn giải các cờ. Phương thức này phải trả về một đối tượngmemoryview.Thread safety: Trong free-threaded Python, việc triển khai phải quản lý mọi bộ đếm xuất nội bộ bằng các hoạt động nguyên tử. Phương thức này phải an toàn để gọi đồng thời từ nhiều luồng và dữ liệu cơ bản của bộ đệm được trả về phải duy trì hiệu lực cho đến khi lệnh gọi
__release_buffer__()tương ứng hoàn tất. Xem An toàn luồng cho các đối tượng MemoryView để biết chi tiết.
- object.__release_buffer__(self, buffer)¶
Được gọi khi bộ đệm không còn cần thiết nữa. Đối số buffer là một đối tượng
memoryviewđã được trả về trước đó bởi__buffer__(). Phương thức này phải giải phóng mọi tài nguyên liên quan đến bộ đệm. Phương thức này sẽ trả vềNone.Thread safety: Trong free-threaded Python, mọi sự giảm bộ đếm xuất đều phải sử dụng các phép toán nguyên tử. Việc dọn dẹp tài nguyên phải an toàn theo luồng, vì bản phát hành cuối cùng có thể chạy đua với các bản phát hành đồng thời từ các luồng khác.
Các đối tượng bộ đệm không cần thực hiện bất kỳ việc dọn dẹp nào đều không bắt buộc phải triển khai phương pháp này.
Added in version 3.12.
Xem thêm
- PEP 688 - Làm cho giao thức bộ đệm có thể truy cập được bằng Python
Giới thiệu các phương thức Python
__buffer__và__release_buffer__.collections.abc.BufferABC cho các loại bộ đệm.
3.3.12. Chú thích¶
Các hàm, lớp và mô-đun có thể chứa annotations, đây là một cách để liên kết thông tin (thường là type hints) với một ký hiệu.
- object.__annotations__¶
Thuộc tính này chứa các chú thích cho một đối tượng. Đó là lazily evaluated, vì vậy việc truy cập vào thuộc tính có thể thực thi mã tùy ý và đưa ra các ngoại lệ. Nếu đánh giá thành công, thuộc tính sẽ được đặt thành ánh xạ từ điển từ tên biến đến chú thích.
Thay đổi trong phiên bản 3.14: Các chú thích bây giờ được đánh giá một cách lười biếng.
- object.__annotate__(format)¶
Một annotate function. Trả về tên thuộc tính/tham số ánh xạ đối tượng từ điển mới cho các giá trị chú thích của chúng.
Lấy một tham số định dạng chỉ định định dạng mà các giá trị chú thích sẽ được cung cấp. Nó phải là thành viên của enum
annotationlib.Formathoặc một số nguyên có giá trị tương ứng với thành viên của enum.Nếu chức năng chú thích không hỗ trợ định dạng được yêu cầu thì nó phải tăng
NotImplementedError. Các hàm chú thích phải luôn hỗ trợ định dạngVALUE; họ không được tăngNotImplementedError()khi được gọi với định dạng này.Khi được gọi với định dạng
VALUE, hàm chú thích có thể tăngNameError; nó không được tăngNameErrorkhi được gọi yêu cầu bất kỳ định dạng nào khác.Nếu một đối tượng không có bất kỳ chú thích nào, tốt nhất nên đặt
__annotate__thànhNone(không thể xóa nó), thay vì đặt thành một hàm trả về một lệnh trống.Added in version 3.14.
Xem thêm
- PEP 649 --- Đánh giá trì hoãn chú thích bằng cách sử dụng bộ mô tả
Giới thiệu tính năng đánh giá lười biếng các chú thích và hàm
__annotate__.
3.3.13. Tra cứu phương pháp đặc biệt¶
Đối với các lớp tùy chỉnh, các lệnh gọi ngầm của các phương thức đặc biệt chỉ được đảm bảo hoạt động chính xác nếu được xác định trên loại đối tượng chứ không phải trong từ điển đối tượng của đối tượng. Hành vi đó là lý do tại sao đoạn mã sau đưa ra một ngoại lệ:
>>> lớp C:
... vượt qua
...
>>> c = C()
>>> c.__len__ = lambda: 5
>>> len(c)
Traceback (cuộc gọi gần đây nhất):
Tệp "<stdin>", dòng 1, trong <module>
TypeError: đối tượng loại 'C' không có len()
Lý do đằng sau hành vi này nằm ở một số phương thức đặc biệt như __hash__() và __repr__() được thực hiện bởi tất cả các đối tượng, bao gồm cả đối tượng kiểu. Nếu việc tra cứu ngầm của các phương thức này sử dụng quy trình tra cứu thông thường, thì chúng sẽ thất bại khi được gọi trên chính đối tượng kiểu đó:
>>> 1 .__hash__() == hàm băm(1)
đúng
>>> int.__hash__() == băm(int)
Traceback (cuộc gọi gần đây nhất):
Tệp "<stdin>", dòng 1, trong <module>
TypeError: bộ mô tả '__hash__' của đối tượng 'int' cần một đối số
Việc cố gắng gọi không chính xác một phương thức không liên kết của một lớp theo cách này đôi khi được gọi là 'nhầm lẫn siêu dữ liệu' và có thể tránh được bằng cách bỏ qua thể hiện khi tra cứu các phương thức đặc biệt:
>>> gõ(1).__hash__(1) == băm(1)
đúng
>>> gõ(int).__hash__(int) == băm(int)
đúng
Ngoài việc bỏ qua bất kỳ thuộc tính phiên bản nào để đảm bảo tính chính xác, việc tra cứu phương thức đặc biệt tiềm ẩn nói chung cũng bỏ qua phương thức __getattribute__() ngay cả đối với siêu dữ liệu của đối tượng:
>>> lớp Meta(loại):
... def __getattribute__(*args):
... print("Siêu lớp getattribute được gọi")
... kiểu trả về.__getattribute__(*args)
...
>>> lớp C(đối tượng, metaclass=Meta):
... chắc chắn __len__(tự):
... trả về 10
... def __getattribute__(*args):
... print("Lớp getattribute được gọi")
... trả về đối tượng.__getattribute__(*args)
...
>>> c = C()
>>> c.__len__() tra cứu # Explicit qua phiên bản
Lớp getattribute được gọi
10
>>> type(c).__len__(c) # Explicit tra cứu qua kiểu
Thuộc tính getattribute metaclass được gọi
10
>>> tra cứu len(c) # Implicit
10
Việc bỏ qua máy __getattribute__() theo cách này cung cấp phạm vi đáng kể cho việc tối ưu hóa tốc độ trong trình thông dịch, với cái giá là phải linh hoạt trong việc xử lý các phương thức đặc biệt (phương thức đặc biệt must được đặt trên chính đối tượng lớp để được trình thông dịch gọi một cách nhất quán).
3.4. Coroutine¶
3.4.1. Đối tượng chờ đợi¶
Đối tượng awaitable thường triển khai phương thức __await__(). Coroutine objects được trả về từ các hàm async def có thể chờ được.
Ghi chú
Các đối tượng generator iterator được trả về từ các trình tạo được trang trí bằng types.coroutine() cũng có thể được chờ đợi, nhưng chúng không triển khai __await__().
- object.__await__(self)¶
Phải trả lại iterator. Nên được sử dụng để triển khai các đối tượng awaitable. Ví dụ:
asyncio.Futuretriển khai phương thức này để tương thích với biểu thứcawait. Bản thân lớpobjectkhông thể chờ đợi được và không cung cấp phương thức này.
Added in version 3.5.
Xem thêm
PEP 492 để biết thêm thông tin về các đối tượng có thể chờ đợi.
3.4.2. Đối tượng Coroutine¶
Coroutine objects là các đối tượng awaitable. Việc thực thi coroutine có thể được kiểm soát bằng cách gọi __await__() và lặp lại kết quả. Khi coroutine thực thi xong và trả về, iterator sẽ tăng StopIteration và thuộc tính value của ngoại lệ giữ giá trị trả về. Nếu coroutine đưa ra một ngoại lệ, nó sẽ được truyền bởi iterator. Coroutine không được trực tiếp đưa ra các ngoại lệ StopIteration chưa được xử lý.
Coroutine cũng có các phương thức được liệt kê bên dưới, tương tự như các phương thức của trình tạo (xem Phương pháp tạo-lặp). Tuy nhiên, không giống như các trình tạo, coroutine không hỗ trợ trực tiếp việc lặp.
Thay đổi trong phiên bản 3.5.2: Đó là một RuntimeError chờ đợi trên một coroutine nhiều lần.
- coroutine.send(value)¶
Bắt đầu hoặc tiếp tục thực thi coroutine. Nếu value là
None, điều này tương đương với việc nâng cao trình lặp được trả về bởi__await__(). Nếu value không phải làNone, thì phương thức này ủy quyền cho phương thứcsend()của iterator đã khiến coroutine tạm dừng. Kết quả (giá trị trả về,StopIterationhoặc ngoại lệ khác) giống như khi lặp qua giá trị trả về__await__(), được mô tả ở trên.
- coroutine.throw(value)¶
- coroutine.throw(type[, value[, traceback]])
Tăng ngoại lệ được chỉ định trong coroutine. Phương thức này ủy quyền cho phương thức
throw()của trình vòng lặp đã khiến coroutine tạm dừng, nếu nó có phương thức như vậy. Nếu không, ngoại lệ sẽ được đưa ra tại điểm tạm dừng. Kết quả (giá trị trả về,StopIterationhoặc ngoại lệ khác) giống như khi lặp qua giá trị trả về__await__(), được mô tả ở trên. Nếu ngoại lệ không được ghi lại trong coroutine, nó sẽ truyền trở lại người gọi.Thay đổi trong phiên bản 3.12: Chữ ký thứ hai (type[, value[, traceback]]) không được dùng nữa và có thể bị xóa trong phiên bản Python trong tương lai.
- coroutine.close()¶
Làm cho coroutine tự dọn dẹp và thoát ra. Nếu coroutine bị tạm dừng, trước tiên, phương thức này sẽ ủy quyền cho phương thức
close()của trình vòng lặp khiến coroutine bị tạm dừng, nếu nó có phương thức như vậy. Sau đó, nó tăngGeneratorExittại điểm treo, khiến coroutine tự dọn sạch ngay lập tức. Cuối cùng, coroutine được đánh dấu là đã thực thi xong, ngay cả khi nó chưa bao giờ được bắt đầu.Các đối tượng Coroutine sẽ tự động được đóng bằng quy trình trên khi chúng sắp bị phá hủy.
3.4.3. Trình lặp không đồng bộ¶
Một asynchronous iterator có thể gọi mã không đồng bộ trong phương thức __anext__ của nó.
Các trình vòng lặp không đồng bộ có thể được sử dụng trong câu lệnh async for.
Bản thân lớp object không cung cấp các phương thức này.
- object.__aiter__(self)¶
Phải trả về một đối tượng asynchronous iterator.
- object.__anext__(self)¶
Phải trả về awaitable dẫn đến giá trị tiếp theo của trình vòng lặp. Sẽ xuất hiện lỗi
StopAsyncIterationkhi quá trình lặp kết thúc.
Một ví dụ về đối tượng lặp không đồng bộ:
Trình đọc lớp:
dòng đọc không đồng bộ (tự):
...
chắc chắn __aiter__(tự):
tự trở về
async def __anext__(self):
val = đang chờ self.readline()
nếu giá trị == b'':
nâng cao StopAsyncIteration
giá trị trả lại
Added in version 3.5.
Thay đổi trong phiên bản 3.7: Trước Python 3.7, __aiter__() có thể trả về awaitable sẽ phân giải thành asynchronous iterator.
Bắt đầu với Python 3.7, __aiter__() phải trả về một đối tượng trình vòng lặp không đồng bộ. Trả lại bất cứ thứ gì khác sẽ dẫn đến lỗi TypeError.
3.4.4. Trình quản lý bối cảnh không đồng bộ¶
Một asynchronous context manager là một context manager có thể tạm dừng thực thi trong các phương thức __aenter__ và __aexit__ của nó.
Trình quản lý bối cảnh không đồng bộ có thể được sử dụng trong câu lệnh async with.
Bản thân lớp object không cung cấp các phương thức này.
- object.__aenter__(self)¶
Về mặt ngữ nghĩa tương tự như
__enter__(), điểm khác biệt duy nhất là nó phải trả về awaitable.
- object.__aexit__(self, exc_type, exc_value, traceback)¶
Về mặt ngữ nghĩa tương tự như
__exit__(), điểm khác biệt duy nhất là nó phải trả về awaitable.
Một ví dụ về lớp trình quản lý bối cảnh không đồng bộ
lớp AsyncContextManager:
async def __aenter__(self):
đang chờ nhật ký('nhập ngữ cảnh')
async def __aexit__(self, exc_type, exc, tb):
đang chờ nhật ký ('thoát bối cảnh')
Added in version 3.5.
Chú thích cuối trang