Đây là một kỹ thuật để trích xuất tất cả các mô-đun đã nhập từ ứng dụng Python được đóng gói dưới dạng tệp
gdb target_application148, sau đó giải mã chúng. Chương trình đích cần được chạy từ đầu, nhưng không cần biểu tượng gỡ lỗi [giả sử đang sử dụng bản dựng Python chưa sửa đổi]
Điều này ban đầu được thực hiện trên Linux 64 bit với Python 3. 6 mục tiêu. Kể từ đó, các tập lệnh Python đã được cập nhật để xử lý các tệp pyc cho Python 2. 7 - 3. 9
Học thuyết
Trong Python, chúng ta có thể tận dụng thực tế là bất kỳ quá trình nhập mô-đun nào liên quan đến tệp
gdb target_application149 cuối cùng sẽ đến dưới dạng đối tượng mã Python sẵn sàng thực thi tại chức năng này
PyObject* PyEval_EvalCode[PyObject *co, PyObject *globals, PyObject *locals];
Nếu một điểm ngắt được đặt ở đây trong gdb, thì có thể gọi triển khai C cho
gdb target_application150 để kết xuất mã byte vào tệp. Thuận tiện là định dạng
gdb target_application148 chỉ đơn giản là một
gdb target_application152 được sắp xếp theo thứ tự với một tiêu đề nhỏ
Tập lệnh
gdb target_application0 bên dưới có thể được sử dụng để chuyển đổi các đối tượng mã sắp xếp thô này thành. pyc và dịch ngược chúng nếu muốn
Tập lệnh
gdb target_application1 có thể được sử dụng để tạo các tệp soái ca thô từ các tệp nguồn Python để chứng minh hoặc kiểm tra điều này mà không cần trích xuất mã soái ca từ thời gian chạy
Tiêu đề tệp gdb target_application
2
Định dạng của tiêu đề pyc đã thay đổi giữa các phiên bản. Các tập lệnh xử lý việc này, nhưng để hoàn thiện [vì tôi không tìm thấy nó được ghi lại ở bất kỳ nơi nào khác cùng một lúc], đây là định dạng tiêu đề cho mỗi phiên bản
Tất cả các trường tại thời điểm viết được viết dưới dạng giá trị 32-bit nhỏ
- Trăn 2. 7.
gdb target_application
3 - Trăn >= 3. 2 [PEP-3147].
gdb target_application
4 - Trăn >= 3. 8 [PEP-0552].
gdb target_application
5
Những chi tiết này cũng được ghi chú trong các bình luận mã
Triển khai trong GDB
Bắt đầu trình gỡ lỗi ở trạng thái đã dừng
gdb target_application
Sau đó, trong bảng điều khiển GDB
________số 8Giờ đây, GDB có thể được tự động kết xuất mọi
gdb target_application152 được đánh giá trong thời gian chạy vào đĩa. Bạn có thể muốn kiểm tra và xác thực một kết xuất theo cách thủ công trước khi tiếp tục với phiên bản tự động của
gdb target_application7
gdb target_application0
Đối số đầu tiên của
gdb target_application8 phải nằm trong sổ đăng ký
gdb target_application9 trên x86_64 Linux, nhưng nó có thể khác trên nền tảng của bạn. Bạn có thể cần phải tự tìm vị trí của đối số đầu tiên, nhưng khi bạn biết vị trí đó, nó có thể được thay thế ở trên
thử nghiệm
Tập lệnh
gdb target_application1 có thể được sử dụng để tạo đối tượng mã được sắp xếp theo thứ tự từ tệp nguồn Python để thử nghiệm
gdb target_application4
Tiêu đề cho tệp
gdb target_application2 đã thay đổi nhiều lần cho đến nay. Nếu bạn đang gặp lỗi về
# Wait for the Python library to load if the symbol can't be found before runtime
catch load
# Run the program
run
# Continue until gdb breaks where the target Python .so is loading
continue
# ...
# Break on the target function
break PyEval_EvalCode
2, hãy sử dụng bài kiểm tra này để xác nhận tập lệnh hoạt động trên phiên bản Python của bạn Có phần nào của Python có vẻ kỳ diệu không? . Làm thế nào để một trình tạo ghi nhớ trạng thái của các biến mỗi khi nó mang lại một giá trị và tại sao bạn không bao giờ phải cấp phát bộ nhớ như các ngôn ngữ khác? . Hướng dẫn này sẽ hướng dẫn bạn qua mã nguồn CPython
Bạn sẽ bao gồm tất cả các khái niệm đằng sau phần bên trong của CPython, cách chúng hoạt động và giải thích trực quan khi bạn tiếp tục
Bạn sẽ học cách
- Đọc và điều hướng mã nguồn
- Biên dịch CPython từ mã nguồn
- Điều hướng và hiểu hoạt động bên trong của các khái niệm như danh sách, từ điển và trình tạo
- Chạy bộ thử nghiệm
- Sửa đổi hoặc nâng cấp các thành phần của thư viện CPython để đóng góp chúng cho các phiên bản sau
Vâng, đây là một bài viết rất dài. Nếu bạn vừa pha cho mình một tách trà, cà phê hoặc đồ uống yêu thích của mình, trời sẽ lạnh vào cuối Phần 1
Hướng dẫn này được chia thành năm phần. Dành thời gian của bạn cho từng phần và đảm bảo rằng bạn đã thử các bản trình diễn và các thành phần tương tác. Bạn có thể cảm nhận được thành tích mà bạn nắm bắt được các khái niệm cốt lõi của Python có thể giúp bạn trở thành một lập trình viên Python giỏi hơn
Tải xuống miễn phí. Nhận một chương mẫu từ CPython Internals. Hướng dẫn về Trình thông dịch Python 3 chỉ cho bạn cách mở khóa hoạt động bên trong của ngôn ngữ Python, biên dịch trình thông dịch Python từ mã nguồn và tham gia phát triển CPython
Phần 1. Giới thiệu về CPython
Khi bạn gõ
gdb target_application757 tại bàn điều khiển hoặc cài đặt bản phân phối Python từ python. org, bạn đang chạy CPython. CPython là một trong nhiều thời gian chạy Python, được duy trì và viết bởi các nhóm nhà phát triển khác nhau. Một số thời gian chạy khác mà bạn có thể đã nghe là PyPy, Cython và Jython
Điều độc đáo về CPython là nó chứa cả thời gian chạy và đặc tả ngôn ngữ dùng chung mà tất cả thời gian chạy Python sử dụng. CPython là triển khai "chính thức" hoặc tham chiếu của Python
Đặc tả ngôn ngữ Python là tài liệu mô tả ngôn ngữ Python. Ví dụ: nó nói rằng
gdb target_application758 là từ khóa dành riêng và
gdb target_application759 được sử dụng để lập chỉ mục, cắt và tạo danh sách trống
Hãy suy nghĩ về những gì bạn mong đợi bên trong bản phân phối Python trên máy tính của bạn
- Khi bạn nhập
gdb target_application
757 mà không có tệp hoặc mô-đun, nó sẽ đưa ra lời nhắc tương tác - Bạn có thể nhập các mô-đun tích hợp từ thư viện chuẩn như
gdb target_application
761 - Bạn có thể cài đặt các gói từ internet bằng cách sử dụng
gdb target_application
762 - Bạn có thể kiểm tra các ứng dụng của mình bằng thư viện
gdb target_application
763 tích hợp
Đây đều là một phần của bản phân phối CPython. Có nhiều thứ hơn là một trình biên dịch
Ghi chú. Bài viết này được viết chống lại phiên bản 3. 8. 0b4 của mã nguồn CPython
Loại bỏ các quảng cáoCó gì trong Mã nguồn?
Bản phân phối nguồn CPython đi kèm với một loạt các công cụ, thư viện và thành phần. Chúng ta sẽ khám phá những điều đó trong bài viết này. Đầu tiên chúng ta sẽ tập trung vào trình biên dịch
Để tải xuống bản sao của mã nguồn CPython, bạn có thể sử dụng
gdb target_application764 để kéo phiên bản mới nhất về bản sao đang hoạt động cục bộ
gdb target_application5
Ghi chú. Nếu bạn không có sẵn Git, bạn có thể tải xuống nguồn trong tệp ZIP trực tiếp từ trang web GitHub
Bên trong thư mục
gdb target_application765 mới được tải xuống, bạn sẽ tìm thấy các thư mục con sau
gdb target_application7
Tiếp theo, chúng tôi sẽ biên dịch CPython từ mã nguồn. Bước này yêu cầu trình biên dịch C và một số công cụ xây dựng, phụ thuộc vào hệ điều hành bạn đang sử dụng
Biên dịch CPython [macOS]
Biên dịch CPython trên macOS rất đơn giản. Trước tiên, bạn sẽ cần bộ công cụ biên dịch C thiết yếu. Công cụ phát triển dòng lệnh là một ứng dụng mà bạn có thể cập nhật trong macOS thông qua App Store. Bạn cần thực hiện cài đặt ban đầu trên thiết bị đầu cuối
Để mở một thiết bị đầu cuối trong macOS, hãy chuyển đến Launchpad, sau đó chọn Khác rồi chọn ứng dụng Terminal. Bạn sẽ muốn lưu ứng dụng này vào Dock của mình, vì vậy hãy nhấp chuột phải vào Biểu tượng và chọn Keep in Dock
Bây giờ, trong thiết bị đầu cuối, hãy cài đặt trình biên dịch C và bộ công cụ bằng cách chạy lệnh sau
gdb target_application8
Lệnh này sẽ bật lên với lời nhắc tải xuống và cài đặt một bộ công cụ, bao gồm Git, Make và trình biên dịch GNU C
Bạn cũng sẽ cần một bản sao OpenSSL đang hoạt động để sử dụng cho việc tìm nạp các gói từ PyPi. trang web tổ chức. Nếu sau này bạn có kế hoạch sử dụng bản dựng này để cài đặt các gói bổ sung, thì cần phải xác thực SSL
Cách đơn giản nhất để cài đặt OpenSSL trên macOS là sử dụng HomeBrew. Nếu bạn đã cài đặt HomeBrew, bạn có thể cài đặt các phụ thuộc cho CPython bằng lệnh
gdb target_application766
gdb target_application0
Bây giờ bạn đã có các phần phụ thuộc, bạn có thể chạy tập lệnh
gdb target_application767, kích hoạt hỗ trợ SSL bằng cách khám phá vị trí mà HomeBrew đã cài đặt và bật móc gỡ lỗi
gdb target_application768
gdb target_application3
Điều này sẽ tạo ra một
gdb target_application769 trong thư mục gốc của kho lưu trữ mà bạn có thể sử dụng để tự động hóa quá trình xây dựng. Bước
gdb target_application770 chỉ cần chạy một lần. Bạn có thể xây dựng nhị phân CPython bằng cách chạy
gdb target_application6
Cờ ________ 1771 cho phép ________ 1772 chạy 2 công việc cùng lúc. Nếu bạn có 4 lõi, bạn có thể thay đổi thành 4. Cờ
gdb target_application773 ngăn
gdb target_application769 in mọi lệnh mà nó chạy ra bàn điều khiển. Bạn có thể loại bỏ cái này, nhưng đầu ra rất dài dòng
Trong quá trình xây dựng, bạn có thể gặp một số lỗi và trong bản tóm tắt, nó sẽ thông báo cho bạn rằng không phải tất cả các gói đều có thể được xây dựng. Ví dụ:
gdb target_application775,
gdb target_application776,
gdb target_application777,
gdb target_application778,
gdb target_application779,
gdb target_application780 và
gdb target_application781 sẽ không thể xây dựng với bộ hướng dẫn này. Không sao nếu bạn không có kế hoạch phát triển dựa trên các gói đó. Nếu đúng như vậy, hãy xem trang web hướng dẫn dành cho nhà phát triển để biết thêm thông tin
Quá trình xây dựng sẽ mất vài phút và tạo một tệp nhị phân có tên là
gdb target_application782. Mỗi khi bạn thay đổi mã nguồn, bạn sẽ cần chạy lại
gdb target_application772 với cùng các cờ. Tệp nhị phân
gdb target_application782 là tệp nhị phân gỡ lỗi của CPython. Thực thi
gdb target_application782 để xem REPL đang hoạt động
gdb target_application2
Ghi chú. Vâng, đúng vậy, bản dựng macOS có phần mở rộng tệp cho
gdb target_application786. Điều này không phải vì nó là tệp nhị phân của Windows. Vì macOS có hệ thống tệp không phân biệt chữ hoa chữ thường và khi làm việc với tệp nhị phân, các nhà phát triển không muốn mọi người vô tình tham chiếu đến thư mục
gdb target_application787 nên
gdb target_application786 đã được thêm vào để tránh sự mơ hồ. Nếu sau này bạn chạy
gdb target_application789 hoặc
gdb target_application790, nó sẽ đổi tên tệp trở lại
gdb target_application757Loại bỏ các quảng cáo
Biên dịch CPython [Linux]
Đối với Linux, bước đầu tiên là tải xuống và cài đặt ________ 1772, ________ 1793, ________ 1767 và ________ 1795
Đối với Fedora Core, RHEL, CentOS hoặc các hệ thống dựa trên yum khác
gdb target_application3
Đối với Debian, Ubuntu hoặc các hệ thống dựa trên
gdb target_application796 khác
gdb target_application5
Sau đó cài đặt các gói cần thiết, cho Fedora Core, RHEL, CentOS hoặc các hệ thống dựa trên yum khác
gdb target_application6
Đối với Debian, Ubuntu hoặc các hệ thống dựa trên
gdb target_application796 khác
gdb target_application70
Bây giờ bạn đã có các phần phụ thuộc, bạn có thể chạy tập lệnh
gdb target_application767, kích hoạt móc gỡ lỗi
gdb target_application768
gdb target_application71
Xem lại đầu ra để đảm bảo rằng hỗ trợ OpenSSL được đánh dấu là
gdb target_application800. Nếu không, hãy kiểm tra bản phân phối của bạn để biết hướng dẫn cài đặt tiêu đề cho OpenSSL
Tiếp theo, bạn có thể xây dựng tệp nhị phân CPython bằng cách chạy tệp
gdb target_application769 đã tạo
gdb target_application6
Trong quá trình xây dựng, bạn có thể gặp một số lỗi và trong bản tóm tắt, nó sẽ thông báo cho bạn rằng không phải tất cả các gói đều có thể được xây dựng. Không sao nếu bạn không có kế hoạch phát triển dựa trên các gói đó. Nếu đúng như vậy, hãy xem trang web hướng dẫn dành cho nhà phát triển để biết thêm thông tin
Quá trình xây dựng sẽ mất vài phút và tạo một tệp nhị phân có tên là
gdb target_application757. Đây là nhị phân gỡ lỗi của CPython. Thực thi
gdb target_application803 để xem REPL đang hoạt động
gdb target_application73
Biên dịch CPython [Windows]
Bên trong thư mục PC là tệp dự án Visual Studio để xây dựng và khám phá CPython. Để sử dụng tính năng này, bạn cần cài đặt Visual Studio trên PC của mình
Phiên bản mới nhất của Visual Studio, Visual Studio 2019, giúp làm việc với Python và mã nguồn CPython dễ dàng hơn, vì vậy nó được khuyến nghị sử dụng trong hướng dẫn này. Nếu bạn đã cài đặt Visual Studio 2017, nó cũng sẽ hoạt động tốt
Không có tính năng trả phí nào được yêu cầu để biên dịch CPython hoặc hướng dẫn này. Bạn có thể sử dụng phiên bản Cộng đồng của Visual Studio, được cung cấp miễn phí trên trang web Visual Studio của Microsoft
Khi bạn đã tải xuống trình cài đặt, bạn sẽ được yêu cầu chọn thành phần nào bạn muốn cài đặt. Mức tối thiểu cho hướng dẫn này là
- Khối lượng công việc Phát triển Python
- Các công cụ phát triển gốc Python tùy chọn
- Python 3 64-bit [3. 7. 2] [có thể bỏ chọn nếu bạn đã có Python 3. 7 đã cài đặt]
Bất kỳ tính năng tùy chọn nào khác có thể được bỏ chọn nếu bạn muốn tận tâm hơn với dung lượng ổ đĩa
Trình cài đặt sau đó sẽ tải xuống và cài đặt tất cả các thành phần cần thiết. Quá trình cài đặt có thể mất một giờ, vì vậy bạn có thể muốn đọc tiếp và quay lại phần này
Khi quá trình cài đặt hoàn tất, hãy nhấp vào nút Khởi chạy để khởi động Visual Studio. Bạn sẽ được nhắc đăng nhập. Nếu bạn có tài khoản Microsoft, bạn có thể đăng nhập hoặc bỏ qua bước đó
Khi Visual Studio khởi động, bạn sẽ được nhắc Mở Dự án. Một lối tắt để bắt đầu với cấu hình Git và nhân bản CPython là chọn tùy chọn Clone or check out code
Đối với URL của dự án, hãy nhập
gdb target_application804 để sao chép
Sau đó, Visual Studio sẽ tải xuống một bản sao CPython từ GitHub bằng phiên bản Git đi kèm với Visual Studio. Bước này cũng giúp bạn tránh được rắc rối khi phải cài đặt Git trên Windows. Quá trình tải xuống có thể mất 10 phút
Khi dự án đã được tải xuống, bạn cần trỏ nó đến tệp Giải pháp
gdb target_application805, bằng cách nhấp vào Giải pháp và Dự án và chọn
gdb target_application806
Khi giải pháp được tải, nó sẽ nhắc bạn nhắm mục tiêu lại dự án bên trong giải pháp cho phiên bản trình biên dịch C/C++ mà bạn đã cài đặt. Visual Studio cũng sẽ nhắm mục tiêu phiên bản Windows SDK mà bạn đã cài đặt
Đảm bảo rằng bạn thay đổi phiên bản Windows SDK thành phiên bản được cài đặt mới nhất và bộ công cụ nền tảng thành phiên bản mới nhất. Nếu bạn bỏ lỡ cửa sổ này, bạn có thể nhấp chuột phải vào Giải pháp trong cửa sổ Giải pháp và Dự án và nhấp vào Giải pháp nhắm mục tiêu lại
Khi quá trình này hoàn tất, bạn cần tải xuống một số tệp nguồn để có thể xây dựng toàn bộ gói CPython. Bên trong thư mục
gdb target_application807 có tệp
gdb target_application808 tự động hóa việc này cho bạn. Mở lời nhắc dòng lệnh bên trong
gdb target_application807 đã tải xuống và chạy
gdb target_application810
gdb target_application74
Tiếp theo, quay lại trong Visual Studio, xây dựng CPython bằng cách nhấn Ctrl + Shift +B, or choosing Build Solution from the top menu. If you receive any errors about the Windows SDK being missing, make sure you set the right targeting settings in the Retarget Solution window. You should also see Windows Kits inside your Start Menu, and Windows Software Development Kit inside of that menu.
Giai đoạn xây dựng lần đầu tiên có thể mất 10 phút hoặc hơn. Sau khi quá trình xây dựng hoàn tất, bạn có thể thấy một vài cảnh báo mà bạn có thể bỏ qua và cuối cùng sẽ hoàn tất
Để bắt đầu phiên bản gỡ lỗi của CPython, hãy nhấn F5 và CPython sẽ bắt đầu ở chế độ Gỡ lỗi thẳng vào REPL.
Khi quá trình này hoàn tất, bạn có thể chạy bản dựng Phát hành bằng cách thay đổi cấu hình bản dựng từ Gỡ lỗi thành Phát hành trên thanh menu trên cùng và chạy lại Giải pháp bản dựng. Bây giờ bạn có cả hai phiên bản Gỡ lỗi và Phát hành của tệp nhị phân CPython trong
gdb target_application811
Bạn có thể thiết lập Visual Studio để có thể mở REPL bằng bản Phát hành hoặc Gỡ lỗi bằng cách chọn
gdb target_application812->______2813->
gdb target_application814 từ menu trên cùng
Sau đó nhấp vào Thêm môi trường và sau đó nhắm mục tiêu nhị phân Gỡ lỗi hoặc Phát hành. Nhị phân gỡ lỗi sẽ kết thúc bằng
gdb target_application815, ví dụ:
gdb target_application816 và
gdb target_application817. Rất có thể bạn sẽ muốn sử dụng tệp nhị phân gỡ lỗi vì nó đi kèm với hỗ trợ Gỡ lỗi trong Visual Studio và sẽ hữu ích cho hướng dẫn này
Trong cửa sổ Thêm môi trường, nhắm mục tiêu tệp
gdb target_application816 làm trình thông dịch bên trong
gdb target_application819 và
gdb target_application817 làm trình thông dịch cửa sổ
Bây giờ, bạn có thể bắt đầu phiên REPL bằng cách nhấp vào Mở cửa sổ tương tác trong cửa sổ Môi trường Python và bạn sẽ thấy REPL cho phiên bản Python đã biên dịch
Trong hướng dẫn này sẽ có các phiên REPL với các lệnh ví dụ. Tôi khuyến khích bạn sử dụng nhị phân Gỡ lỗi để chạy các phiên REPL này trong trường hợp bạn muốn đặt bất kỳ điểm dừng nào trong mã
Cuối cùng, để điều hướng mã dễ dàng hơn, trong Chế độ xem giải pháp, hãy nhấp vào nút chuyển đổi bên cạnh biểu tượng Trang chủ để chuyển sang chế độ xem Thư mục
Bây giờ bạn đã có một phiên bản CPython được biên dịch và sẵn sàng hoạt động, hãy cùng tìm hiểu cách thức hoạt động của trình biên dịch CPython
Loại bỏ các quảng cáoTrình biên dịch làm gì?
Mục đích của trình biên dịch là chuyển đổi ngôn ngữ này sang ngôn ngữ khác. Hãy nghĩ về một trình biên dịch giống như một dịch giả. Bạn sẽ thuê một người phiên dịch để nghe bạn nói tiếng Anh và sau đó nói bằng tiếng Nhật
Một số trình biên dịch sẽ biên dịch thành mã máy cấp thấp có thể được thực thi trực tiếp trên hệ thống. Các trình biên dịch khác sẽ biên dịch thành một ngôn ngữ trung gian, được thực thi bởi một máy ảo
Một quyết định quan trọng cần đưa ra khi chọn trình biên dịch là các yêu cầu về tính di động của hệ thống. Java và. NET CLR sẽ biên dịch thành Ngôn ngữ trung gian để mã được biên dịch có thể di chuyển trên nhiều kiến trúc hệ thống. C, Go, C++ và Pascal sẽ biên dịch thành một tệp thực thi cấp thấp sẽ chỉ hoạt động trên các hệ thống tương tự như hệ thống được biên dịch
Vì các ứng dụng Python thường được phân phối dưới dạng mã nguồn nên vai trò của bộ thực thi Python là chuyển đổi mã nguồn Python và thực thi nó trong một bước. Trong nội bộ, thời gian chạy CPython sẽ biên dịch mã của bạn. Một quan niệm sai lầm phổ biến là Python là một ngôn ngữ thông dịch. Nó thực sự được tổng hợp
Mã Python không được biên dịch thành mã máy. Nó được biên dịch thành một ngôn ngữ trung gian cấp thấp đặc biệt gọi là bytecode mà chỉ CPython mới hiểu được. Mã này được lưu trữ trong các tệp
gdb target_application821 trong một thư mục ẩn và được lưu vào bộ đệm để thực thi. Nếu bạn chạy cùng một ứng dụng Python hai lần mà không thay đổi mã nguồn, lần thứ hai sẽ luôn nhanh hơn nhiều. Điều này là do nó tải bytecode đã biên dịch và thực thi trực tiếp
Tại sao CPython được viết bằng C mà không phải Python?
Chữ C trong CPython là tham chiếu đến ngôn ngữ lập trình C, ngụ ý rằng bản phân phối Python này được viết bằng ngôn ngữ C
Tuyên bố này phần lớn là sự thật. trình biên dịch trong CPython được viết bằng C thuần túy. Tuy nhiên, nhiều mô-đun thư viện tiêu chuẩn được viết bằng Python thuần túy hoặc kết hợp giữa C và Python
Vậy tại sao CPython được viết bằng C mà không phải Python?
Câu trả lời nằm ở cách trình biên dịch hoạt động. Có hai loại trình biên dịch
- Trình biên dịch tự lưu trữ là trình biên dịch được viết bằng ngôn ngữ mà chúng biên dịch, chẳng hạn như trình biên dịch Go
- Trình biên dịch nguồn-đến-nguồn là trình biên dịch được viết bằng ngôn ngữ khác đã có sẵn trình biên dịch
Nếu bạn đang viết một ngôn ngữ lập trình mới từ đầu, bạn cần một ứng dụng thực thi để biên dịch trình biên dịch của mình. Bạn cần một trình biên dịch để thực thi mọi thứ, vì vậy khi các ngôn ngữ mới được phát triển, chúng thường được viết trước bằng một ngôn ngữ cũ hơn, lâu đời hơn
Một ví dụ điển hình là ngôn ngữ lập trình Go. Trình biên dịch Go đầu tiên được viết bằng C, sau đó khi Go có thể được biên dịch, trình biên dịch được viết lại bằng Go
CPython giữ di sản C của nó. nhiều mô-đun thư viện tiêu chuẩn, như mô-đun ________ 2822 hoặc mô-đun ________ 2823, được viết bằng C để truy cập API hệ điều hành cấp thấp. Các API trong nhân Windows và Linux để tạo ổ cắm mạng, làm việc với hệ thống tệp hoặc tương tác với màn hình đều được viết bằng C. Thật hợp lý khi lớp mở rộng của Python được tập trung vào ngôn ngữ C. Ở phần sau của bài viết này, chúng ta sẽ đề cập đến Thư viện chuẩn Python và các mô-đun C
Có một trình biên dịch Python được viết bằng Python gọi là PyPy. Logo của PyPy là một Ouroboros để thể hiện bản chất tự lưu trữ của trình biên dịch
Một ví dụ khác về trình biên dịch chéo cho Python là Jython. Jython được viết bằng Java và biên dịch từ mã nguồn Python thành Java bytecode. Cũng giống như cách CPython giúp dễ dàng nhập các thư viện C và sử dụng chúng từ Python, Jython giúp dễ dàng nhập và tham chiếu các mô-đun và lớp Java
Đặc tả ngôn ngữ Python
Chứa trong mã nguồn CPython là định nghĩa của ngôn ngữ Python. Đây là đặc tả tham chiếu được sử dụng bởi tất cả các trình thông dịch Python
Thông số kỹ thuật ở cả định dạng người đọc được và máy đọc được. Bên trong tài liệu là giải thích chi tiết về ngôn ngữ Python, những gì được phép và cách mỗi câu lệnh nên hoạt động
Tài liệu
Nằm bên trong thư mục
gdb target_application824 là các giải thích về reStructuredText của từng tính năng trong ngôn ngữ Python. Điều này tạo thành hướng dẫn tham khảo Python chính thức trên tài liệu. con trăn. tổ chức
Bên trong thư mục là các tệp bạn cần hiểu toàn bộ ngôn ngữ, cấu trúc và từ khóa
gdb target_application75
Bên trong
gdb target_application825, tài liệu về câu lệnh ghép, bạn có thể xem một ví dụ đơn giản xác định câu lệnh
gdb target_application826
Câu lệnh
gdb target_application826 có thể được sử dụng theo nhiều cách trong Python, cách đơn giản nhất là khởi tạo trình quản lý ngữ cảnh và khối mã lồng nhau
gdb target_application76
Bạn có thể gán kết quả cho một biến bằng cách sử dụng từ khóa
gdb target_application828
gdb target_application77
Bạn cũng có thể xâu chuỗi các trình quản lý ngữ cảnh cùng với dấu phẩy
gdb target_application78
Tiếp theo, chúng ta sẽ khám phá tài liệu có thể đọc được trên máy tính của ngôn ngữ Python
Văn phạm
Tài liệu chứa thông số kỹ thuật mà con người có thể đọc được của ngôn ngữ và thông số kỹ thuật mà máy có thể đọc được nằm trong một tệp duy nhất,
gdb target_application829
Tệp ngữ pháp được viết bằng ký hiệu ngữ cảnh có tên là Biểu mẫu Backus-Naur [BNF]. BNF không dành riêng cho Python và thường được sử dụng làm ký hiệu cho ngữ pháp trong nhiều ngôn ngữ khác
Khái niệm cấu trúc ngữ pháp trong ngôn ngữ lập trình được lấy cảm hứng từ tác phẩm của Noam Chomsky về Cấu trúc cú pháp vào những năm 1950
Tệp ngữ pháp của Python sử dụng đặc tả BNF mở rộng [EBNF] với cú pháp biểu thức chính quy. Vì vậy, trong tệp ngữ pháp bạn có thể sử dụng
gdb target_application
830 để lặp lạigdb target_application
831 để lặp lại ít nhất một lầngdb target_application
759 cho các bộ phận tùy chọngdb target_application
833 cho các lựa chọn thay thếgdb target_application
834 để nhóm
Nếu bạn tìm kiếm câu lệnh
gdb target_application826 trong tệp ngữ pháp, ở khoảng dòng 80, bạn sẽ thấy các định nghĩa cho câu lệnh
gdb target_application826
gdb target_application79
Bất cứ điều gì trong dấu ngoặc kép là một chuỗi ký tự, đó là cách từ khóa được xác định. Vì vậy,
gdb target_application837 được chỉ định là
- Bắt đầu bằng từ
gdb target_application
826 - Tiếp theo là một
gdb target_application
839, là mộtgdb target_application
840 và [tùy chọn], từgdb target_application
828, và một biểu thức - Theo dõi một hoặc nhiều mục, mỗi mục được phân tách bằng dấu phẩy
- Kết thúc bằng một
gdb target_application
842 - Theo sau là một
gdb target_application
843
Có tham chiếu đến một số định nghĩa khác trong hai dòng này
gdb target_application
843 đề cập đến một khối mã có một hoặc nhiều câu lệnhgdb target_application
840 đề cập đến một tuyên bố đơn giản được đánh giágdb target_application
846 đề cập đến một biểu thức đơn giản
Nếu bạn muốn khám phá những điều đó một cách chi tiết, toàn bộ ngữ pháp Python được định nghĩa trong tệp duy nhất này
Nếu bạn muốn xem một ví dụ gần đây về cách sử dụng ngữ pháp, trong PEP 572, toán tử dấu hai chấm bằng đã được thêm vào tệp ngữ pháp trong cam kết Git này
Sử dụng gdb target_application
847
Bản thân tệp ngữ pháp không bao giờ được sử dụng bởi trình biên dịch Python. Thay vào đó, một bảng phân tích cú pháp được tạo bởi một công cụ có tên là
gdb target_application847 được sử dụng.
gdb target_application847 đọc tệp ngữ pháp và chuyển đổi nó thành bảng phân tích cú pháp. Nếu bạn thay đổi tệp ngữ pháp, bạn phải tạo lại bảng phân tích cú pháp và biên dịch lại Python
Ghi chú. Ứng dụng
gdb target_application847 được viết lại bằng Python 3. 8 từ C đến Python thuần túy
Để xem hoạt động của
gdb target_application847, hãy thay đổi một phần ngữ pháp Python. Xung quanh dòng 51, bạn sẽ thấy định nghĩa của câu lệnh
gdb target_application852
gdb target_application80
Thay đổi dòng đó để chấp nhận từ khóa
gdb target_application853 hoặc
gdb target_application854 làm từ khóa
gdb target_application81
Bây giờ bạn cần xây dựng lại các tệp ngữ pháp. Trên macOS và Linux, hãy chạy
gdb target_application855 để chạy
gdb target_application847 trên tệp ngữ pháp đã thay đổi. Đối với Windows, không có cách nào được hỗ trợ chính thức để chạy
gdb target_application847. Tuy nhiên, bạn có thể sao chép ngã ba của tôi và chạy
gdb target_application858 từ trong thư mục
gdb target_application807
Bạn sẽ thấy một kết quả tương tự như thế này, cho thấy rằng các tệp
gdb target_application860 và
gdb target_application861 mới đã được tạo
gdb target_application82
Ghi chú.
gdb target_application847 hoạt động bằng cách chuyển đổi các câu lệnh EBNF thành Máy tự động hữu hạn không xác định [NFA], sau đó được chuyển thành Máy tự động hữu hạn xác định [DFA]. DFA được trình phân tích cú pháp sử dụng làm bảng phân tích cú pháp theo cách đặc biệt chỉ dành cho CPython. Kỹ thuật này được hình thành tại Đại học Stanford và phát triển vào những năm 1980, ngay trước khi Python ra đời
Với các bảng phân tích cú pháp được tạo lại, bạn cần biên dịch lại CPython để xem cú pháp mới. Sử dụng các bước biên dịch giống như bạn đã sử dụng trước đó cho hệ điều hành của mình
Nếu mã được biên dịch thành công, bạn có thể thực thi mã nhị phân CPython mới của mình và bắt đầu REPL
Trong REPL, bây giờ bạn có thể thử định nghĩa một hàm và thay vì sử dụng câu lệnh
gdb target_application852, hãy sử dụng từ khóa thay thế
gdb target_application864 mà bạn đã biên dịch thành ngữ pháp Python
gdb target_application83
Tốt lắm. Bạn đã thay đổi cú pháp CPython và biên dịch phiên bản CPython của riêng bạn. vận chuyển nó
Tiếp theo, chúng ta sẽ khám phá các mã thông báo và mối quan hệ của chúng với ngữ pháp
mã thông báo
Bên cạnh tệp ngữ pháp trong thư mục
gdb target_application865 là tệp
gdb target_application866, chứa từng loại duy nhất được tìm thấy dưới dạng nút lá trong cây phân tích cú pháp. Chúng tôi sẽ đề cập sâu về cây phân tích cú pháp sau. Mỗi mã thông báo cũng có một tên và một ID duy nhất được tạo. Tên được sử dụng để làm cho nó đơn giản hơn để tham khảo trong mã thông báo
Ghi chú. Tệp
gdb target_application866 là một tính năng mới trong Python 3. 8
Ví dụ: dấu ngoặc đơn bên trái được gọi là ________ 2868 và dấu chấm phẩy được gọi là ________ 2869. Bạn sẽ thấy những mã thông báo này sau trong bài viết
gdb target_application84
Cũng như với tệp
gdb target_application865, nếu bạn thay đổi tệp
gdb target_application866, bạn cần chạy lại
gdb target_application847
Để xem mã thông báo đang hoạt động, bạn có thể sử dụng mô-đun ________ 2873 trong Python. Tạo một tập lệnh Python đơn giản có tên là
gdb target_application874
gdb target_application85
Đối với phần còn lại của hướng dẫn này,
gdb target_application875 sẽ đề cập đến phiên bản đã biên dịch của CPython. Tuy nhiên, lệnh thực tế sẽ phụ thuộc vào hệ thống của bạn
Cho cửa sổ
gdb target_application86
cho Linux
gdb target_application87
Đối với macOS
gdb target_application88
Sau đó chuyển tệp này qua một mô-đun được tích hợp trong thư viện chuẩn có tên là
gdb target_application873. Bạn sẽ thấy danh sách mã thông báo, theo dòng và ký tự. Sử dụng cờ
gdb target_application877 để xuất tên mã thông báo chính xác
gdb target_application89
Ở đầu ra, cột đầu tiên là phạm vi của tọa độ dòng/cột, cột thứ hai là tên của mã thông báo và cột cuối cùng là giá trị của mã thông báo
Ở đầu ra, mô-đun
gdb target_application873 đã ngụ ý một số mã thông báo không có trong tệp. Mã thông báo
gdb target_application879 cho
gdb target_application880 và một dòng trống ở cuối, cung cấp cho
gdb target_application881 để đóng phần khai báo hàm và một
gdb target_application882 để kết thúc tệp
Cách tốt nhất là có một dòng trống ở cuối tệp nguồn Python của bạn. Nếu bạn bỏ qua nó, CPython sẽ thêm nó cho bạn, với một hình phạt nhỏ về hiệu suất
Mô-đun
gdb target_application873 được viết bằng Python thuần túy và nằm ở
gdb target_application884 trong mã nguồn CPython
Quan trọng. Có hai mã thông báo trong mã nguồn CPython. một cái được viết bằng Python, được trình bày ở đây và một cái khác được viết bằng C. Mã thông báo được viết bằng Python có nghĩa là một tiện ích và mã được viết bằng C được sử dụng bởi trình biên dịch Python. Họ có đầu ra và hành vi giống hệt nhau. Phiên bản viết bằng C được thiết kế để thực hiện và mô-đun bằng Python được thiết kế để gỡ lỗi
Để xem phần đọc chi tiết của mã thông báo C, bạn có thể chạy Python với cờ
gdb target_application885. Sử dụng tập lệnh
gdb target_application874 mà bạn đã tạo trước đó, hãy chạy tập lệnh đó như sau
gdb target_application00
Trong kết quả, bạn có thể thấy rằng nó đánh dấu
gdb target_application864 như một từ khóa. Trong chương tiếp theo, chúng ta sẽ xem cách thực thi mã nhị phân Python đến mã thông báo và điều gì xảy ra từ đó để thực thi mã của bạn
Bây giờ bạn đã có cái nhìn tổng quan về ngữ pháp Python và mối quan hệ giữa mã thông báo và câu lệnh, có một cách để chuyển đổi đầu ra
gdb target_application847 thành biểu đồ tương tác
Đây là một ảnh chụp màn hình của Python 3. ngữ văn 8a2
Gói Python được sử dụng để tạo biểu đồ này,
gdb target_application889, sẽ được trình bày trong chương sauLoại bỏ các quảng cáo
Quản lý bộ nhớ trong CPython
Xuyên suốt bài viết này, bạn sẽ thấy các tham chiếu đến một đối tượng
gdb target_application890. Đấu trường là một trong những cấu trúc quản lý bộ nhớ của CPython. Mã nằm trong
gdb target_application891 và chứa một trình bao bọc xung quanh các chức năng cấp phát và hủy cấp phát bộ nhớ của C
Trong chương trình C được viết theo cách truyền thống, nhà phát triển nên cấp phát bộ nhớ cho cấu trúc dữ liệu trước khi ghi vào dữ liệu đó. Việc phân bổ này đánh dấu bộ nhớ thuộc về tiến trình với hệ điều hành
Nhà phát triển cũng có thể giải phóng hoặc “giải phóng” bộ nhớ đã cấp phát khi bộ nhớ không còn được sử dụng nữa và đưa nó trở lại bảng khối bộ nhớ trống của hệ điều hành. Nếu một quá trình phân bổ bộ nhớ cho một biến, chẳng hạn như trong một hàm hoặc vòng lặp, khi chức năng đó hoàn thành, bộ nhớ sẽ không tự động được trả lại cho hệ điều hành trong C. Vì vậy, nếu nó không được giải phóng rõ ràng trong mã C, nó sẽ gây rò rỉ bộ nhớ. Quá trình này sẽ tiếp tục chiếm nhiều bộ nhớ hơn mỗi khi chức năng đó chạy cho đến khi hệ thống hết bộ nhớ và gặp sự cố
Python nhận trách nhiệm đó từ lập trình viên và sử dụng hai thuật toán. bộ đếm tham chiếu và bộ thu gom rác
Bất cứ khi nào một trình thông dịch được khởi tạo, một
gdb target_application890 được tạo và đính kèm một trong các trường trong trình thông dịch. Trong vòng đời của trình thông dịch CPython, nhiều đấu trường có thể được phân bổ. Chúng được kết nối với một danh sách được liên kết. Đấu trường lưu trữ danh sách các con trỏ tới Đối tượng Python dưới dạng
gdb target_application893. Bất cứ khi nào một đối tượng Python mới được tạo, một con trỏ tới nó sẽ được thêm vào bằng cách sử dụng
gdb target_application894. Lệnh gọi hàm này lưu trữ một con trỏ trong danh sách của đấu trường,
gdb target_application895
Mặc dù Python không có con trỏ nhưng vẫn có một số kỹ thuật thú vị để mô phỏng hành vi của con trỏ
gdb target_application890 phục vụ chức năng thứ hai, đó là phân bổ và tham chiếu danh sách các khối bộ nhớ thô. Ví dụ: một
gdb target_application897 sẽ cần thêm bộ nhớ nếu bạn đã thêm hàng nghìn giá trị bổ sung. Mã C của đối tượng
gdb target_application897 không cấp phát bộ nhớ trực tiếp. Đối tượng nhận các khối bộ nhớ thô từ
gdb target_application890 bằng cách gọi
gdb target_application000 từ
gdb target_application001 với kích thước bộ nhớ được yêu cầu. Nhiệm vụ này được hoàn thành bởi một trừu tượng khác trong
gdb target_application002. Trong mô-đun cấp phát đối tượng, bộ nhớ có thể được cấp phát, giải phóng và cấp phát lại cho Đối tượng Python
Một danh sách liên kết của các khối được phân bổ được lưu trữ bên trong đấu trường, để khi một trình thông dịch bị dừng, tất cả các khối bộ nhớ được quản lý có thể được giải phóng trong một lần bằng cách sử dụng
gdb target_application003
Lấy ví dụ về
gdb target_application893. Nếu bạn
gdb target_application005 một đối tượng vào cuối danh sách Python, bạn không cần phân bổ lại bộ nhớ được sử dụng trong danh sách hiện có trước đó. Phương thức
gdb target_application005 gọi
gdb target_application007 xử lý cấp phát bộ nhớ cho danh sách. Mỗi đối tượng danh sách giữ một danh sách dung lượng bộ nhớ được phân bổ. Nếu mục bạn đang thêm vào vừa với bộ nhớ trống hiện có, mục đó sẽ được thêm vào một cách đơn giản. Nếu danh sách cần thêm dung lượng bộ nhớ, nó sẽ được mở rộng. Danh sách được mở rộng theo độ dài 0, 4, 8, 16, 25, 35, 46, 58, 72, 88
gdb target_application008 được gọi để mở rộng bộ nhớ được phân bổ trong danh sách.
gdb target_application008 là trình bao bọc API cho
gdb target_application010
Python cũng có một trình bao bọc đặc biệt cho lệnh gọi C
gdb target_application011, đặt kích thước tối đa của cấp phát bộ nhớ để giúp ngăn lỗi tràn bộ đệm [Xem
gdb target_application012]
Tóm tắt
- Việc phân bổ các khối bộ nhớ thô được thực hiện thông qua
gdb target_application
013 - Các con trỏ tới các đối tượng Python được lưu trữ trong
gdb target_application
890 gdb target_application
890 cũng lưu trữ danh sách liên kết của các khối bộ nhớ được cấp phát
Thông tin thêm về API được trình bày chi tiết trên tài liệu CPython
Đếm tham chiếu
Để tạo một biến trong Python, bạn phải gán một giá trị cho một biến được đặt tên duy nhất
gdb target_application01
Bất cứ khi nào một giá trị được gán cho một biến trong Python, tên của biến đó sẽ được kiểm tra trong phạm vi cục bộ và toàn cục để xem nó đã tồn tại chưa
Vì
gdb target_application016 chưa có trong từ điển
gdb target_application017 hoặc
gdb target_application018 nên đối tượng mới này được tạo và giá trị được gán là hằng số
gdb target_application019
Hiện tại có một tham chiếu đến
gdb target_application016, vì vậy bộ đếm tham chiếu cho
gdb target_application016 được tăng thêm 1
Bạn sẽ thấy các lệnh gọi hàm
gdb target_application022 và
gdb target_application023 trong toàn bộ mã nguồn C cho CPython. Các hàm này tăng và giảm số lượng tham chiếu đến đối tượng đó
Các tham chiếu đến một đối tượng bị giảm khi một biến nằm ngoài phạm vi mà nó được khai báo. Phạm vi trong Python có thể đề cập đến một hàm hoặc phương thức, mức hiểu hoặc hàm lambda. Đây là một số phạm vi theo nghĩa đen hơn, nhưng có nhiều phạm vi ngầm định khác, chẳng hạn như truyền biến cho lệnh gọi hàm
Việc xử lý các tham chiếu tăng và giảm dựa trên ngôn ngữ được tích hợp trong trình biên dịch CPython và vòng lặp thực thi cốt lõi,
gdb target_application024, mà chúng tôi sẽ đề cập chi tiết sau trong bài viết này
Bất cứ khi nào
gdb target_application023 được gọi và bộ đếm trở thành 0, hàm
gdb target_application026 được gọi. Đối với đối tượng đó,
gdb target_application003 được gọi cho tất cả bộ nhớ đã được cấp phát
Thu gom rác thải
Bao lâu rác của bạn được thu gom?
Khi bạn làm xong việc gì đó, bạn vứt bỏ nó và ném vào thùng rác. Nhưng thùng rác đó sẽ không được thu gom ngay lập tức. Bạn cần đợi xe rác đến và lấy nó đi
CPython có nguyên tắc tương tự, sử dụng thuật toán thu gom rác. Trình thu gom rác của CPython được bật theo mặc định, diễn ra trong nền và hoạt động để giải phóng bộ nhớ đã được sử dụng cho các đối tượng không còn được sử dụng
Vì thuật toán thu gom rác phức tạp hơn nhiều so với bộ đếm tham chiếu, nên nó không xảy ra mọi lúc, nếu không, nó sẽ tiêu tốn một lượng lớn tài nguyên CPU. Nó xảy ra định kỳ, sau một số hoạt động nhất định
Thư viện chuẩn của CPython đi kèm với mô-đun Python để giao tiếp với đấu trường và trình thu gom rác, mô-đun
gdb target_application028. Đây là cách sử dụng mô-đun
gdb target_application028 ở chế độ gỡ lỗi
>>>
gdb target_application02
Điều này sẽ in số liệu thống kê bất cứ khi nào bộ thu gom rác được chạy
Bạn có thể lấy ngưỡng mà sau đó bộ thu gom rác được chạy bằng cách gọi
gdb target_application030
>>>
gdb target_application03
Bạn cũng có thể nhận được số lượng ngưỡng hiện tại
>>>
gdb target_application04
Cuối cùng, bạn có thể chạy thủ công thuật toán thu thập
>>>
gdb target_application05
Điều này sẽ gọi
gdb target_application031 bên trong tệp
gdb target_application032 chứa việc triển khai thuật toán thu gom rácLoại bỏ các quảng cáo
Sự kết luận
Trong Phần 1, bạn đã trình bày về cấu trúc của kho mã nguồn, cách biên dịch từ nguồn và đặc tả ngôn ngữ Python. Những khái niệm cốt lõi này sẽ rất quan trọng trong Phần 2 khi bạn tìm hiểu sâu hơn về quy trình phiên dịch Python
Phần 2. Quy trình phiên dịch Python
Bây giờ bạn đã xem phần quản lý bộ nhớ và ngữ pháp Python, bạn có thể làm theo quy trình từ cách nhập
gdb target_application757 đến phần mã của bạn được thực thi
Có năm cách nhị phân
gdb target_application757 có thể được gọi
- Để chạy một lệnh duy nhất với
gdb target_application
035 và lệnh Python - Để bắt đầu một mô-đun với
gdb target_application
036 và tên của một mô-đun - Để chạy một tệp có tên tệp
- Để chạy đầu vào
gdb target_application
037 bằng shell pipe - Để bắt đầu REPL và thực hiện từng lệnh một
Python có rất nhiều cách để thực thi các tập lệnh, nó có thể hơi quá sức. Darren Jones đã tổng hợp một khóa học tuyệt vời về cách chạy các tập lệnh Python nếu bạn muốn tìm hiểu thêm
Ba tệp nguồn bạn cần kiểm tra để xem quy trình này là
gdb target_application
038 là một điểm vào đơn giảngdb target_application
039 chứa mã để tập hợp toàn bộ quá trình, tải cấu hình, thực thi mã và xóa bộ nhớgdb target_application
040 tải cấu hình từ môi trường hệ thống và hợp nhất nó với bất kỳ cờ dòng lệnh nào
Sơ đồ này cho thấy mỗi chức năng đó được gọi như thế nào
Chế độ thực thi được xác định từ cấu hình
Kiểu mã nguồn CPython
Tương tự như hướng dẫn kiểu PEP8 cho mã Python, có một hướng dẫn kiểu chính thức cho mã CPython C, được thiết kế ban đầu vào năm 2001 và được cập nhật cho các phiên bản hiện đại
Có một số tiêu chuẩn đặt tên giúp ích khi điều hướng mã nguồn
Sử dụng tiền tố
gdb target_application
041 cho các hàm công khai, không bao giờ cho các hàm tĩnh. Tiền tốgdb target_application
042 được dành riêng cho các thói quen dịch vụ toàn cầu nhưgdb target_application
043. Các nhóm quy trình cụ thể [như API loại đối tượng cụ thể] sử dụng tiền tố dài hơn, chẳng hạn nhưgdb target_application
044 cho các hàm chuỗiCác hàm và biến công khai sử dụng MixedCase với dấu gạch dưới, như thế này. ________ 3045, ________ 3046, ________ 3047
Đôi khi, một chức năng "nội bộ" phải được hiển thị cho trình tải. Chúng tôi sử dụng tiền tố
gdb target_application
048 cho việc này, ví dụ:gdb target_application
049Macro phải có tiền tố MixedCase và sau đó sử dụng chữ hoa, ví dụ:
gdb target_application
050,gdb target_application
051
Thiết lập cấu hình thời gian chạy
Trong các đường bơi, bạn có thể thấy rằng trước khi bất kỳ mã Python nào được thực thi, bộ thực thi trước tiên sẽ thiết lập cấu hình. Cấu hình của thời gian chạy là cấu trúc dữ liệu được xác định trong
gdb target_application052 có tên là
gdb target_application053
Cấu trúc dữ liệu cấu hình bao gồm những thứ như
- Cờ thời gian chạy cho các chế độ khác nhau như chế độ gỡ lỗi và tối ưu hóa
- Chế độ thực thi, chẳng hạn như tên tệp đã được chuyển chưa,
gdb target_application
037 đã được cung cấp hay tên mô-đun - Tùy chọn mở rộng, được chỉ định bởi
gdb target_application
055 - Biến môi trường cho cài đặt thời gian chạy
Dữ liệu cấu hình chủ yếu được sử dụng bởi thời gian chạy CPython để bật và tắt các tính năng khác nhau
Python cũng đi kèm với một số Tùy chọn Giao diện Dòng lệnh. Trong Python, bạn có thể bật chế độ dài dòng bằng cờ
gdb target_application056. Ở chế độ dài dòng, Python sẽ in thông báo ra màn hình khi các mô-đun được tải
gdb target_application06
Bạn sẽ thấy hàng trăm dòng trở lên với tất cả các lần nhập gói trang web người dùng của bạn và bất kỳ thứ gì khác trong môi trường hệ thống
Bạn có thể xem định nghĩa của cờ này trong
gdb target_application052 bên trong
gdb target_application058 cho
gdb target_application053
gdb target_application07
Trong
gdb target_application040, logic để đọc cài đặt từ các biến môi trường và cờ dòng lệnh thời gian chạy được thiết lập
Trong hàm
gdb target_application061, các biến môi trường được đọc và sử dụng để gán giá trị cho cài đặt cấu hình
gdb target_application08
Đối với cài đặt dài dòng, bạn có thể thấy rằng giá trị của
gdb target_application062 được sử dụng để đặt giá trị của
gdb target_application063, nếu tìm thấy
gdb target_application062. Nếu biến môi trường không tồn tại thì giá trị mặc định của
gdb target_application065 sẽ được giữ nguyên
Sau đó, trong
gdb target_application066 trong
gdb target_application067 một lần nữa, cờ dòng lệnh được sử dụng để đặt giá trị, nếu được cung cấp
gdb target_application09
Giá trị này sau đó được sao chép vào biến toàn cục
gdb target_application068 bằng hàm
gdb target_application069
Trong phiên Python, bạn có thể truy cập các cờ thời gian chạy, như chế độ dài dòng, chế độ im lặng, sử dụng bộ dữ liệu có tên
gdb target_application070. Các cờ
gdb target_application071 đều có sẵn trong từ điển
gdb target_application072
>>>
gdb target_application30
Ngoài cấu hình thời gian chạy trong
gdb target_application073, còn có cấu hình bản dựng nằm bên trong
gdb target_application074 trong thư mục gốc. Tệp này được tạo động trong bước
gdb target_application767 trong quy trình xây dựng hoặc bởi Visual Studio cho các hệ thống Windows
Bạn có thể xem cấu hình bản dựng bằng cách chạy
gdb target_application31Loại bỏ các quảng cáo
Đọc tệp/Đầu vào
Khi CPython có cấu hình thời gian chạy và các đối số dòng lệnh, nó có thể thiết lập những gì nó cần để thực thi
Tác vụ này được xử lý bởi hàm
gdb target_application076 bên trong
gdb target_application039. Tùy thuộc vào phiên bản
gdb target_application078 mới được tạo, CPython giờ đây sẽ thực thi mã được cung cấp qua một số tùy chọn
Nhập thông qua gdb target_application
035
Đơn giản nhất là cung cấp cho CPython một lệnh với tùy chọn
gdb target_application035 và một chương trình Python bên trong dấu ngoặc kép
Ví dụ
gdb target_application32
Đây là sơ đồ đầy đủ về cách điều này xảy ra
Đầu tiên, hàm
gdb target_application081 được thực thi bên trong
gdb target_application039 lấy lệnh được truyền trong
gdb target_application035 làm đối số trong kiểu C
gdb target_application084. Loại
gdb target_application084 thường được sử dụng làm loại lưu trữ cấp thấp cho dữ liệu Unicode trên CPython vì kích thước của loại có thể lưu trữ các ký tự UTF8
Khi chuyển đổi
gdb target_application084 thành chuỗi Python, tệp
gdb target_application087 có hàm trợ giúp
gdb target_application088 trả về một
gdb target_application001, loại
gdb target_application090. Mã hóa thành UTF8 sau đó được thực hiện bởi
gdb target_application091 trên đối tượng Python
gdb target_application090 để chuyển đổi nó thành đối tượng Python
gdb target_application093
Khi quá trình này hoàn tất, sau đó,
gdb target_application081 sẽ chuyển đối tượng byte Python sang
gdb target_application095 để thực thi, nhưng trước tiên hãy chuyển đổi lại loại
gdb target_application093 thành loại
gdb target_application090
gdb target_application33
Việc chuyển đổi
gdb target_application084 thành Unicode, byte và sau đó là một chuỗi tương đương như sau
gdb target_application34
Hàm
gdb target_application095 là một phần của
gdb target_application300. Mục đích của nó là biến lệnh đơn giản này thành một mô-đun Python và sau đó gửi lệnh đó để được thực thi. Vì một mô-đun Python cần phải có
gdb target_application301 để được thực thi dưới dạng một mô-đun độc lập, nên nó sẽ tự động tạo mô-đun đó
gdb target_application35
Khi
gdb target_application095 đã tạo một mô-đun và một từ điển, nó sẽ gọi
gdb target_application303, tạo một tên tệp giả và sau đó gọi trình phân tích cú pháp Python để tạo AST từ chuỗi và trả về một mô-đun,
gdb target_application304
gdb target_application36
Bạn sẽ đi sâu vào mã AST và Trình phân tích cú pháp trong phần tiếp theo
Nhập thông qua gdb target_application
036
Một cách khác để thực thi các lệnh Python là sử dụng tùy chọn
gdb target_application036 với tên của một mô-đun. Ví dụ điển hình là
gdb target_application307 để chạy module unittest trong thư viện chuẩn
Khả năng thực thi các mô-đun dưới dạng tập lệnh ban đầu được đề xuất trong PEP 338 và sau đó là tiêu chuẩn cho nhập tương đối rõ ràng được xác định trong PEP366
Việc sử dụng cờ
gdb target_application036 ngụ ý rằng trong gói mô-đun, bạn muốn thực thi bất cứ thứ gì bên trong
gdb target_application301. Điều đó cũng ngụ ý rằng bạn muốn tìm kiếm mô-đun có tên
gdb target_application310
Cơ chế tìm kiếm này là lý do tại sao bạn không cần nhớ nơi lưu trữ mô-đun
gdb target_application763 trên hệ thống tệp của mình
Bên trong
gdb target_application039 có một chức năng được gọi khi dòng lệnh được chạy với cờ
gdb target_application036. Tên của mô-đun được truyền dưới dạng đối số
gdb target_application314
CPython sau đó sẽ nhập một mô-đun thư viện chuẩn,
gdb target_application315 và thực thi nó bằng cách sử dụng
gdb target_application316. Quá trình nhập được thực hiện bằng hàm C API
gdb target_application317, được tìm thấy trong tệp
gdb target_application318
gdb target_application37
Trong hàm này, bạn cũng sẽ thấy 2 hàm C API khác.
gdb target_application316 và
gdb target_application320. Bởi vì
gdb target_application317 trả về một
gdb target_application322, loại đối tượng cốt lõi, bạn cần gọi các hàm đặc biệt để lấy các thuộc tính và gọi nó
Trong Python, nếu bạn có một đối tượng và muốn lấy một thuộc tính, thì bạn có thể gọi
gdb target_application323. Trong API C, cuộc gọi này là
gdb target_application320, được tìm thấy trong
gdb target_application325. Nếu bạn muốn chạy một hàm có thể gọi được, bạn sẽ đặt nó trong dấu ngoặc đơn hoặc bạn có thể chạy thuộc tính
gdb target_application326 trên bất kỳ đối tượng Python nào. Phương thức
gdb target_application326 được triển khai bên trong
gdb target_application325
gdb target_application38
Mô-đun
gdb target_application315 được viết bằng Python thuần túy và nằm trong
gdb target_application330
Thực thi
gdb target_application331 tương đương với việc chạy
gdb target_application332. Mô-đun
gdb target_application315 được tạo để trừu tượng hóa quá trình định vị và thực thi các mô-đun trên một hệ điều hành
gdb target_application315 thực hiện một số việc để chạy mô-đun đích
- Các cuộc gọi
gdb target_application
335 cho tên mô-đun bạn đã cung cấp - Đặt
gdb target_application
336 [tên mô-đun] thành một không gian tên có tên làgdb target_application
301 - Thực thi mô-đun trong không gian tên
gdb target_application
301
Mô-đun
gdb target_application315 cũng hỗ trợ thực thi các thư mục và tệp zip
Nhập thông qua Tên tệp
Nếu đối số đầu tiên của
gdb target_application757 là một tên tệp, chẳng hạn như
gdb target_application341, thì CPython sẽ mở một bộ điều khiển tệp, tương tự như sử dụng
gdb target_application342 trong Python và chuyển bộ điều khiển đó tới
gdb target_application343 bên trong
gdb target_application300
Có 3 con đường mà hàm này có thể đi
- Nếu đường dẫn tệp là tệp
gdb target_application
821, nó sẽ gọigdb target_application
346 - Nếu đường dẫn tệp là tệp script [______3347] thì nó sẽ chạy ____3348
- Nếu đường dẫn tệp là
gdb target_application
037 vì người dùng đã chạygdb target_application
350 thì hãy coigdb target_application
037 là phần xử lý tệp và chạygdb target_application
348
gdb target_application39
Nhập qua Tệp Với gdb target_application
348
Đối với
gdb target_application037 và các tệp tập lệnh cơ bản, CPython sẽ chuyển phần xử lý tệp cho
gdb target_application348 nằm trong tệp
gdb target_application356
Mục đích của
gdb target_application348 tương tự như
gdb target_application095 được sử dụng cho đầu vào
gdb target_application035. CPython sẽ tải xử lý tệp vào
gdb target_application360. Chúng tôi sẽ đề cập đến các mô-đun Trình phân tích cú pháp và AST trong phần tiếp theo. Vì đây là tập lệnh đầy đủ nên không cần bước
gdb target_application361 được sử dụng bởi
gdb target_application035
gdb target_application60
Giống hệt với
gdb target_application095, sau khi
gdb target_application348 đã tạo một mô-đun Python từ tệp, nó sẽ gửi mô-đun đó tới
gdb target_application365 để được thực thi
gdb target_application365 được tìm thấy trong
gdb target_application300 và gửi mô-đun tới AST để được biên dịch thành một đối tượng mã. Các đối tượng mã là một định dạng được sử dụng để lưu trữ các hoạt động của mã byte và định dạng được lưu giữ trong các tệp
gdb target_application821
gdb target_application61
Chúng tôi sẽ đề cập đến trình biên dịch CPython và mã byte trong phần tiếp theo. Cuộc gọi đến
gdb target_application369 là một chức năng bao bọc đơn giản gọi
gdb target_application370 trong tệp
gdb target_application371. Hàm
gdb target_application370 là vòng đánh giá chính cho CPython, nó lặp qua từng câu lệnh mã byte và thực thi nó trên máy cục bộ của bạn
Nhập thông qua Mã byte được biên dịch với gdb target_application
346
Trong
gdb target_application343 có một điều khoản dành cho người dùng cung cấp đường dẫn tệp đến tệp
gdb target_application821. Nếu đường dẫn tệp kết thúc bằng
gdb target_application821 thì thay vì tải tệp dưới dạng tệp văn bản thuần túy và phân tích cú pháp, nó sẽ giả định rằng tệp
gdb target_application821 chứa một đối tượng mã được ghi vào đĩa
Hàm
gdb target_application346 bên trong
gdb target_application300 sau đó sắp xếp đối tượng mã từ tệp
gdb target_application821 bằng cách sử dụng trình điều khiển tệp. Marshaling là thuật ngữ kỹ thuật để sao chép nội dung của tệp vào bộ nhớ và chuyển đổi chúng thành cấu trúc dữ liệu cụ thể. Cấu trúc dữ liệu đối tượng mã trên đĩa là cách trình biên dịch CPython lưu vào bộ đệm mã đã biên dịch để không cần phân tích cú pháp mỗi khi tập lệnh được gọi
gdb target_application62
Khi đối tượng mã đã được sắp xếp theo thứ tự vào bộ nhớ, nó sẽ được gửi tới
gdb target_application369, gọi
gdb target_application382 để thực thi mãLoại bỏ các quảng cáo
Từ vựng và phân tích cú pháp
Trong quá trình khám phá cách đọc và thực thi các tệp Python, chúng tôi đã tìm hiểu sâu về trình phân tích cú pháp và các mô-đun AST, với các lệnh gọi hàm tới
gdb target_application360
Gắn bó với
gdb target_application300, hàm
gdb target_application360 sẽ xử lý tệp, cờ trình biên dịch và phiên bản
gdb target_application890 và chuyển đổi đối tượng tệp thành đối tượng nút bằng cách sử dụng
gdb target_application387
Với đối tượng nút, sau đó nó sẽ chuyển đổi nó thành một mô-đun bằng cách sử dụng hàm AST
gdb target_application388
gdb target_application63
Đối với
gdb target_application387, chúng tôi chuyển sang
gdb target_application390 và giai đoạn trình phân tích cú pháp mã thông báo của trình thông dịch CPython. Chức năng này có hai nhiệm vụ quan trọng
- Khởi tạo trạng thái tokenizer
gdb target_application
391 bằng cách sử dụnggdb target_application
392 tronggdb target_application
393 - Chuyển đổi mã thông báo thành cây phân tích cú pháp cụ thể [danh sách
gdb target_application
394] bằng cách sử dụnggdb target_application
395 tronggdb target_application
390
gdb target_application64
gdb target_application391 [được định nghĩa trong
gdb target_application398] là cấu trúc dữ liệu để lưu trữ tất cả dữ liệu tạm thời được tạo bởi tokenizer. Nó được trả về trình phân tích cú pháp mã thông báo vì cấu trúc dữ liệu được yêu cầu bởi
gdb target_application395 để phát triển cây cú pháp cụ thể
Bên trong
gdb target_application395, nó sẽ sử dụng cấu trúc
gdb target_application391 và thực hiện lệnh gọi tới
gdb target_application602 trong một vòng lặp cho đến khi hết tệp và không thể tìm thấy thêm mã thông báo nào nữa
gdb target_application602, được định nghĩa trong
gdb target_application393 hoạt động giống như một trình vòng lặp. Nó sẽ tiếp tục trả lại mã thông báo tiếp theo trong cây phân tích cú pháp
gdb target_application602 là một trong những hàm phức tạp nhất trong toàn bộ cơ sở mã CPython. Nó có hơn 640 dòng và bao gồm nhiều thập kỷ di sản với các trường hợp cạnh, các tính năng ngôn ngữ mới và cú pháp
Một trong những ví dụ đơn giản hơn sẽ là phần chuyển đổi ngắt dòng mới thành mã thông báo NEWLINE
gdb target_application65
Trong trường hợp này,
gdb target_application606 là mã thông báo, với giá trị được xác định trong
gdb target_application607. Tất cả các mã thông báo là các giá trị
gdb target_application608 không đổi và tệp
gdb target_application607 đã được tạo trước đó khi chúng tôi chạy
gdb target_application855
Loại
gdb target_application394 được trả về bởi
gdb target_application387 sẽ rất cần thiết cho giai đoạn tiếp theo, chuyển đổi cây phân tích cú pháp thành Cây cú pháp trừu tượng [AST]
gdb target_application66
Vì CST là một cây cú pháp, ID mã thông báo và ký hiệu nên trình biên dịch sẽ khó đưa ra quyết định nhanh chóng dựa trên ngôn ngữ Python
Đó là lý do tại sao giai đoạn tiếp theo là chuyển đổi CST thành AST, một cấu trúc cấp cao hơn nhiều. Nhiệm vụ này được thực hiện bởi mô-đun
gdb target_application613, có cả API C và Python
Trước khi bạn chuyển sang AST, có một cách để truy cập đầu ra từ giai đoạn trình phân tích cú pháp. CPython có một mô-đun thư viện tiêu chuẩn
gdb target_application614, hiển thị các hàm C bằng API Python
Mô-đun được ghi lại dưới dạng chi tiết triển khai của CPython để bạn không thấy nó trong các trình thông dịch Python khác. Ngoài ra, đầu ra từ các chức năng không dễ đọc
Đầu ra sẽ ở dạng số, sử dụng mã thông báo và số ký hiệu được tạo bởi giai đoạn
gdb target_application855, được lưu trữ trong
gdb target_application607
>>>
gdb target_application67
Để dễ hiểu hơn, bạn có thể lấy tất cả các số trong mô-đun
gdb target_application617 và
gdb target_application618, đặt chúng vào từ điển và thay thế đệ quy các giá trị trong đầu ra của
gdb target_application619 bằng tên
gdb target_application68
Bạn có thể chạy
gdb target_application620 với một biểu thức đơn giản, chẳng hạn như
gdb target_application621 để xem cách biểu diễn này dưới dạng cây phân tích cú pháp
>>>
gdb target_application69
Ở đầu ra, bạn có thể thấy các ký hiệu bằng chữ thường, chẳng hạn như ________ 3622 và mã thông báo bằng chữ hoa, chẳng hạn như ________ 3623
Loại bỏ các quảng cáoCây cú pháp trừu tượng
Giai đoạn tiếp theo trong trình thông dịch CPython là chuyển đổi CST do trình phân tích cú pháp tạo ra thành thứ gì đó hợp lý hơn để có thể thực thi. Cấu trúc là một biểu diễn cấp cao hơn của mã, được gọi là Cây cú pháp trừu tượng [AST]
AST được tạo nội tuyến với quy trình thông dịch CPython, nhưng bạn cũng có thể tạo chúng bằng cả Python bằng cách sử dụng mô-đun
gdb target_application624 trong Thư viện chuẩn cũng như thông qua API C
Trước khi đi sâu vào triển khai C của AST, sẽ rất hữu ích nếu bạn hiểu AST trông như thế nào đối với một đoạn mã Python đơn giản
Để làm điều này, đây là một ứng dụng đơn giản có tên là
gdb target_application889 cho hướng dẫn này. Nó hiển thị các hướng dẫn AST và mã byte [mà chúng tôi sẽ trình bày sau] trong giao diện người dùng web
Để cài đặt
gdb target_application889
gdb target_application20
Sau đó, mở REPL bằng cách chạy
gdb target_application757 tại dòng lệnh không có đối số
>>>
gdb target_application21
Bạn sẽ thấy thông báo trên dòng lệnh rằng máy chủ web đã khởi động trên cổng
gdb target_application628. Nếu bạn đang sử dụng cổng đó cho mục đích khác, bạn có thể thay đổi cổng đó bằng cách gọi số
gdb target_application629 hoặc một số cổng khác
Trong trình duyệt web, bạn có thể xem phân tích chi tiết về chức năng của mình
Biểu đồ dưới cùng bên trái là hàm bạn đã khai báo trong REPL, được biểu diễn dưới dạng Cây cú pháp trừu tượng. Mỗi nút trong cây là một loại AST. Chúng được tìm thấy trong mô-đun
gdb target_application624 và tất cả đều kế thừa từ
gdb target_application631
Một số nút có các thuộc tính liên kết chúng với các nút con, không giống như CST, có thuộc tính nút con chung
Ví dụ: nếu bạn nhấp vào nút Chỉ định ở giữa, nút này sẽ liên kết đến dòng
gdb target_application632
Nó có hai thuộc tính
gdb target_application
633 là danh sách các tên cần gán. Nó là một danh sách bởi vì bạn có thể gán cho nhiều biến với một biểu thức duy nhất bằng cách giải néngdb target_application
634 là giá trị cần gán, trong trường hợp này là câu lệnhgdb target_application
635,gdb target_application
621
Nếu bạn nhấp vào câu lệnh
gdb target_application635, nó sẽ hiển thị các thuộc tính liên quan
gdb target_application
638. nút bên trái của toán tửgdb target_application
639. toán tử, trong trường hợp này, một nútgdb target_application
640 [gdb target_application
831] để bổ sunggdb target_application
642. nút bên phải của toán tử
Biên dịch AST trong C không phải là một nhiệm vụ đơn giản, vì vậy mô-đun
gdb target_application613 có hơn 5000 dòng mã
Có một vài điểm vào, tạo thành một phần của API công khai của AST. Trong phần cuối cùng về từ vựng và trình phân tích cú pháp, bạn đã dừng khi gọi tới số
gdb target_application388. Đến giai đoạn này, trình thông dịch Python đã tạo ra một CST ở định dạng cây
gdb target_application645
Sau đó nhảy vào
gdb target_application388 bên trong
gdb target_application613, bạn có thể thấy nó nhận được cây
gdb target_application645, tên tệp, cờ trình biên dịch và
gdb target_application890
Kiểu trả về từ hàm này là
gdb target_application650, được xác định trong
gdb target_application651.
gdb target_application650 là cấu trúc vùng chứa cho một trong 5 loại mô-đun trong Python
gdb target_application
653gdb target_application
654gdb target_application
655gdb target_application
656gdb target_application
657
Trong
gdb target_application651, bạn có thể thấy rằng loại
gdb target_application655 yêu cầu trường
gdb target_application660, đây là loại
gdb target_application661. Loại
gdb target_application661 cũng được định nghĩa trong
gdb target_application651
gdb target_application22
Các loại AST đều được liệt kê trong
gdb target_application664. Bạn sẽ thấy các loại mô-đun, loại câu lệnh, loại biểu thức, toán tử và khả năng hiểu đều được liệt kê. Tên của các loại trong tài liệu này liên quan đến các lớp được tạo bởi AST và các lớp tương tự có tên trong thư viện mô-đun chuẩn
gdb target_application624
Các thông số và tên trong
gdb target_application651 tương quan trực tiếp với những thông số được chỉ định trong
gdb target_application664
gdb target_application23
Tệp tiêu đề C và các cấu trúc ở đó để chương trình
gdb target_application613 có thể nhanh chóng tạo các cấu trúc có con trỏ tới dữ liệu liên quan
Nhìn vào
gdb target_application388 bạn có thể thấy rằng nó thực chất là một câu lệnh
gdb target_application670 xung quanh kết quả từ
gdb target_application671.
gdb target_application672 là một trong những chức năng cốt lõi được AST sử dụng để xác định loại nút trong cây cú pháp cụ thể là gì. Trong trường hợp của
gdb target_application388, nó chỉ nhìn vào nút đầu tiên, vì vậy nó chỉ có thể là một trong các loại mô-đun được xác định là
gdb target_application653,
gdb target_application654,
gdb target_application655,
gdb target_application656
Kết quả của
gdb target_application672 sẽ là một biểu tượng hoặc loại mã thông báo mà chúng ta đã rất quen thuộc ở giai đoạn này
Đối với
gdb target_application679, kết quả phải là một
gdb target_application653. Các mô-đun là một loạt các câu lệnh, trong đó có một số loại. Logic để duyệt qua các nút con của
gdb target_application681 và tạo các nút câu lệnh nằm trong
gdb target_application682. Hàm này được gọi một lần nếu chỉ có 1 câu lệnh trong mô-đun hoặc vòng lặp nếu có nhiều câu lệnh. Kết quả
gdb target_application653 sau đó được trả về với
gdb target_application890
Đối với
gdb target_application685, kết quả phải là một
gdb target_application655. Kết quả từ
gdb target_application687, là con đầu tiên của
gdb target_application681 được truyền cho
gdb target_application689, trả về loại
gdb target_application661.
gdb target_application661 này được gửi đến
gdb target_application692 bằng PyArena để tạo một nút biểu thức, sau đó được trả lại như một kết quả
gdb target_application24
Bên trong hàm
gdb target_application682, có một câu lệnh
gdb target_application670 khác cho từng loại câu lệnh có thể có [
gdb target_application695,
gdb target_application696, v.v.] và mã để xác định các đối số cho lớp nút
Một trong những hàm đơn giản hơn là đối với biểu thức lũy thừa, i. e. ,
gdb target_application697 là 2 mũ 4. Hàm này bắt đầu bằng cách lấy
gdb target_application698, là số
gdb target_application699 trong ví dụ của chúng ta, sau đó nếu nó có một con, nó sẽ trả về biểu thức nguyên tử. Nếu nó có nhiều hơn một con, nó sẽ lấy bên tay phải [số
gdb target_application200] và trả về một
gdb target_application635 [phép toán nhị phân] với toán tử là
gdb target_application202 [lũy thừa], bàn tay trái của
gdb target_application203 [2] và bàn tay phải
gdb target_application25
Bạn có thể thấy kết quả của việc này nếu bạn gửi một hàm ngắn tới mô-đun
gdb target_application889
>>>
gdb target_application26
Trong giao diện người dùng, bạn cũng có thể thấy các thuộc tính tương ứng
Tóm lại, mỗi loại câu lệnh và biểu thức đều có một hàm
gdb target_application206 tương ứng để tạo ra nó. Các đối số được xác định trong
gdb target_application664 và được hiển thị thông qua mô-đun
gdb target_application624 trong thư viện chuẩn. Nếu một biểu thức hoặc câu lệnh có con, thì nó sẽ gọi hàm con
gdb target_application209 tương ứng trong một lần duyệt theo chiều sâuLoại bỏ các quảng cáo
Sự kết luận
Tính linh hoạt và API thực thi cấp thấp của CPython khiến nó trở thành ứng cử viên lý tưởng cho một công cụ viết kịch bản nhúng. Bạn sẽ thấy CPython được sử dụng trong nhiều ứng dụng giao diện người dùng, chẳng hạn như Thiết kế trò chơi, đồ họa 3D và tự động hóa hệ thống
Quá trình thông dịch linh hoạt và hiệu quả, và bây giờ bạn đã hiểu về cách thức hoạt động của nó, bạn đã sẵn sàng để hiểu trình biên dịch
Phần 3. Vòng lặp thực thi và trình biên dịch CPython
Trong Phần 2, bạn đã thấy cách trình thông dịch CPython nhận đầu vào, chẳng hạn như tệp hoặc chuỗi và chuyển đổi nó thành Cây cú pháp trừu tượng hợp lý. Chúng tôi vẫn chưa ở giai đoạn mã này có thể được thực thi. Tiếp theo, chúng ta phải đi sâu hơn để chuyển đổi Cây cú pháp trừu tượng thành một tập hợp các lệnh tuần tự mà CPU có thể hiểu được
Biên soạn
Bây giờ trình thông dịch có một AST với các thuộc tính cần thiết cho từng thao tác, hàm, lớp và không gian tên. Công việc của trình biên dịch là biến AST thành thứ mà CPU có thể hiểu được
Nhiệm vụ biên dịch này được chia thành 2 phần
- Duyệt qua cây và tạo biểu đồ luồng điều khiển, biểu thị trình tự logic để thực hiện
- Chuyển đổi các nút trong CFG thành các câu lệnh nhỏ hơn, có thể thực thi được, được gọi là mã byte
Trước đó, chúng ta đã xem cách tệp được thực thi và hàm
gdb target_application348 trong
gdb target_application300. Bên trong chức năng này, chúng tôi đã chuyển đổi điều khiển
gdb target_application212 thành một
gdb target_application304, loại
gdb target_application650. Nhiệm vụ này đã được hoàn thành bởi
gdb target_application360, lần lượt gọi
gdb target_application216,
gdb target_application217 và sau đó là AST
gdb target_application27
Mô-đun kết quả từ cuộc gọi đến được gửi tới
gdb target_application365 vẫn trong
gdb target_application300. Đây là một chức năng nhỏ nhận
gdb target_application220 từ
gdb target_application221 và gửi nó tới
gdb target_application369. Bạn sẽ giải quyết
gdb target_application369 trong phần tiếp theo
gdb target_application28
Hàm
gdb target_application221 là điểm vào chính của trình biên dịch CPython. Nó lấy một mô-đun Python làm đối số chính, cùng với tên của tệp, toàn cầu, cục bộ và
gdb target_application890, tất cả được tạo trước đó trong quy trình thông dịch
Bây giờ chúng ta đang bắt đầu tìm hiểu sâu về trình biên dịch CPython, với hàng thập kỷ phát triển và lý thuyết Khoa học Máy tính đằng sau nó. Đừng để bị trì hoãn bởi ngôn ngữ. Khi chúng tôi chia nhỏ trình biên dịch thành các bước hợp lý, nó sẽ có ý nghĩa
Trước khi trình biên dịch bắt đầu, một trạng thái trình biên dịch chung được tạo. Loại này,
gdb target_application226 được định nghĩa trong
gdb target_application227 và chứa các thuộc tính được trình biên dịch sử dụng để ghi nhớ các cờ trình biên dịch, ngăn xếp và
gdb target_application890
gdb target_application29
Bên trong
gdb target_application221, có 11 bước chính diễn ra
- Tạo một thuộc tính
gdb target_application
230 trống cho mô-đun nếu nó không tồn tại - Tạo một thuộc tính
gdb target_application
231 trống cho mô-đun nếu nó không tồn tại - Đặt tên tệp của trạng thái trình biên dịch chung thành đối số tên tệp
- Đặt trường cấp phát bộ nhớ cho trình biên dịch thành trường được sử dụng bởi trình thông dịch
- Sao chép bất kỳ cờ
gdb target_application
232 nào trong mô-đun sang các cờ tương lai trong trình biên dịch - Hợp nhất các cờ thời gian chạy được cung cấp bởi dòng lệnh hoặc biến môi trường
- Kích hoạt bất kỳ tính năng
gdb target_application
232 nào trong trình biên dịch - Đặt mức tối ưu hóa thành đối số được cung cấp hoặc mặc định
- Xây dựng bảng ký hiệu từ đối tượng mô-đun
- Chạy trình biên dịch với trạng thái trình biên dịch và trả về đối tượng mã
- Giải phóng mọi bộ nhớ được cấp phát bởi trình biên dịch
gdb target_application30
Cờ tương lai và cờ biên dịch
Trước khi trình biên dịch chạy, có hai loại cờ để chuyển đổi các tính năng bên trong trình biên dịch. Chúng đến từ hai nơi
- Trạng thái trình thông dịch, có thể là các tùy chọn dòng lệnh, được đặt trong
gdb target_application
074 hoặc thông qua các biến môi trường - Việc sử dụng các câu lệnh
gdb target_application
232 bên trong mã nguồn thực tế của mô-đun
Để phân biệt hai loại cờ, hãy nghĩ rằng cờ
gdb target_application232 là bắt buộc do cú pháp hoặc tính năng trong mô-đun cụ thể đó. Ví dụ: Python3. 7 đã giới thiệu đánh giá chậm các gợi ý loại thông qua cờ tương lai
gdb target_application237
gdb target_application31
Mã sau câu lệnh này có thể sử dụng các gợi ý loại chưa được giải quyết, do đó, câu lệnh
gdb target_application232 là bắt buộc. Nếu không, mô-đun sẽ không nhập. Sẽ không thể duy trì được nếu yêu cầu người nhập mô-đun bật cờ trình biên dịch cụ thể này theo cách thủ công
Các cờ trình biên dịch khác dành riêng cho môi trường, vì vậy chúng có thể thay đổi cách mã thực thi hoặc cách trình biên dịch chạy, nhưng chúng không nên liên kết với nguồn giống như cách mà các câu lệnh
gdb target_application232 thực hiện
Một ví dụ về cờ trình biên dịch sẽ là cờ
gdb target_application240 để tối ưu hóa việc sử dụng các câu lệnh
gdb target_application758. Cờ này vô hiệu hóa bất kỳ câu lệnh
gdb target_application758 nào, có thể đã được đưa vào mã cho mục đích gỡ lỗi. Nó cũng có thể được kích hoạt với cài đặt biến môi trường
gdb target_application243
Bảng biểu tượng
Trong
gdb target_application221 có một tham chiếu đến một
gdb target_application245 và một cuộc gọi đến
gdb target_application246 với mô-đun sẽ được thực thi
Mục đích của bảng ký hiệu là cung cấp danh sách các không gian tên, toàn cầu và cục bộ để trình biên dịch sử dụng để tham chiếu và giải quyết các phạm vi
Cấu trúc
gdb target_application245 trong
gdb target_application248 được ghi lại rõ ràng, vì vậy rõ ràng mỗi trường dùng để làm gì. Cần có một phiên bản có thể ký hiệu cho trình biên dịch, do đó, không gian tên trở nên cần thiết
Nếu bạn tạo một hàm có tên là
gdb target_application249 trong một mô-đun và khai báo một hàm khác có cùng tên trong một mô-đun khác, bạn muốn chắc chắn rằng hàm nào được gọi. Biểu tượng phục vụ mục đích này, cũng như đảm bảo rằng các biến được khai báo trong phạm vi hẹp không tự động trở thành biến toàn cầu [xét cho cùng, đây không phải là JavaScript]
gdb target_application32
Một số API bảng biểu tượng được hiển thị thông qua mô-đun
gdb target_application245 trong thư viện tiêu chuẩn. Bạn có thể cung cấp một biểu thức hoặc một mô-đun và nhận một phiên bản
gdb target_application251
Bạn có thể cung cấp một chuỗi có biểu thức Python và
gdb target_application252 của
gdb target_application253 hoặc một mô-đun, hàm hoặc lớp và
gdb target_application254 của
gdb target_application255 để lấy bảng ký hiệu
Lặp lại các phần tử trong bảng, chúng ta có thể thấy một số trường công khai và riêng tư và các loại của chúng
>>>
gdb target_application33
Mã C phía sau tất cả nằm trong
gdb target_application256 và giao diện chính là hàm
gdb target_application246
Tương tự như hàm AST cấp cao nhất mà chúng tôi đã đề cập trước đó, hàm
gdb target_application246 chuyển đổi giữa các loại có thể có của
gdb target_application650 [Mô-đun, Biểu thức, Tương tác, Bộ, Loại chức năng] và truy cập từng câu lệnh bên trong chúng
Hãy nhớ rằng,
gdb target_application650 là một phiên bản AST, do đó, bây giờ sẽ khám phá đệ quy các nút và nhánh của cây và thêm các mục vào symtable
gdb target_application34
Vì vậy, đối với một mô-đun,
gdb target_application246 sẽ lặp qua từng câu lệnh trong mô-đun và gọi
gdb target_application262.
gdb target_application262 là một câu lệnh
gdb target_application670 khổng lồ với trường hợp cho từng loại câu lệnh [được định nghĩa trong
gdb target_application664]
Đối với mỗi loại câu lệnh, có logic cụ thể cho loại câu lệnh đó. Ví dụ, một định nghĩa hàm có logic cụ thể cho
- Nếu độ sâu đệ quy vượt quá giới hạn, hãy tăng lỗi độ sâu đệ quy
- Tên của hàm sẽ được thêm làm biến cục bộ
- Các giá trị mặc định cho các đối số tuần tự sẽ được giải quyết
- Các giá trị mặc định cho các đối số từ khóa sẽ được giải quyết
- Mọi chú thích cho các đối số hoặc kiểu trả về đều được giải quyết
- Bất kỳ chức năng trang trí được giải quyết
- Khối mã chứa nội dung của hàm được truy cập trong
gdb target_application
266 - Các đối số được truy cập
- Phần thân của hàm được thăm
Ghi chú. Nếu bạn đã từng thắc mắc tại sao các đối số mặc định của Python lại có thể thay đổi, thì lý do nằm ở hàm này. Bạn có thể thấy chúng là một con trỏ tới biến trong symtable. Không có công việc bổ sung nào được thực hiện để sao chép bất kỳ giá trị nào sang loại không thay đổi
gdb target_application35
Khi symtable kết quả đã được tạo, nó sẽ được gửi lại để sử dụng cho trình biên dịch
Quy trình biên dịch cốt lõi
Giờ đây,
gdb target_application221 đã có trạng thái trình biên dịch, một symtable và một mô-đun ở dạng AST, quá trình biên dịch thực sự có thể bắt đầu
Mục đích của trình biên dịch cốt lõi là để
- Chuyển đổi trạng thái, symtable và AST thành Control-Flow-Graph [CFG]
- Bảo vệ giai đoạn thực thi khỏi các ngoại lệ trong thời gian chạy bằng cách bắt bất kỳ lỗi logic và mã nào và nêu chúng tại đây
Bạn có thể gọi trình biên dịch CPython bằng mã Python bằng cách gọi hàm tích hợp sẵn
gdb target_application268. Nó trả về một phiên bản
gdb target_application269
>>>
gdb target_application36
Tương tự như với hàm
gdb target_application270, một biểu thức đơn giản phải có chế độ là
gdb target_application271 và một mô-đun, hàm hoặc lớp phải có chế độ là
gdb target_application272
Mã được biên dịch có thể được tìm thấy trong thuộc tính
gdb target_application273 của đối tượng mã
>>>
gdb target_application37
Ngoài ra còn có một mô-đun
gdb target_application274 trong thư viện tiêu chuẩn, phân tách các hướng dẫn mã byte và có thể in chúng trên màn hình hoặc cung cấp cho bạn danh sách các phiên bản
gdb target_application275
Nếu bạn nhập
gdb target_application274 và cung cấp cho hàm
gdb target_application277 thuộc tính
gdb target_application273 của đối tượng mã, nó sẽ tách nó ra và in hướng dẫn trên REPL
>>>
gdb target_application38
gdb target_application279,
gdb target_application280,
gdb target_application281 và
gdb target_application282 đều là các lệnh mã byte. Chúng được gọi là mã byte vì ở dạng nhị phân, chúng dài một byte. Tuy nhiên, kể từ Python 3. 6, định dạng lưu trữ đã được thay đổi thành
gdb target_application283, vì vậy bây giờ về mặt kỹ thuật, chúng là mã từ, không phải mã byte
Danh sách đầy đủ các hướng dẫn mã byte có sẵn cho từng phiên bản Python và nó thay đổi giữa các phiên bản. Ví dụ, trong Python 3. 7, một số hướng dẫn mã byte mới đã được giới thiệu để tăng tốc độ thực hiện các lệnh gọi phương thức cụ thể
Trong phần trước, chúng ta đã khám phá gói
gdb target_application889. Điều này bao gồm trực quan hóa loại đối tượng mã bằng cách chạy trình biên dịch. Nó cũng hiển thị các hoạt động Bytecode bên trong các đối tượng mã
Thực thi lại instaviz để xem đối tượng mã và mã byte cho hàm được xác định trên REPL
>>>
gdb target_application39
Nếu bây giờ chúng ta chuyển sang
gdb target_application285, một chức năng được sử dụng để chuyển sang các chức năng biên dịch khác nhau tùy thuộc vào loại mô-đun. Chúng tôi sẽ giả sử rằng
gdb target_application304 là một
gdb target_application653. Mô-đun được biên dịch sang trạng thái trình biên dịch và sau đó
gdb target_application288 được chạy để tạo một
gdb target_application220
Đối tượng mã mới được trả lại cho
gdb target_application221 và được gửi đi để thực thi
gdb target_application50
Hàm
gdb target_application291 có một số cờ tối ưu hóa, sau đó lặp lại từng câu lệnh trong mô-đun và truy cập nó, tương tự như cách hoạt động của hàm
gdb target_application245
gdb target_application51
Loại câu lệnh được xác định thông qua lệnh gọi hàm
gdb target_application293, hàm này xem xét loại của nút AST
Thông qua một số macro thông minh,
gdb target_application294 gọi một hàm trong
gdb target_application227 cho từng loại câu lệnh
gdb target_application52
Đối với một
gdb target_application296 [thể loại cho một câu lệnh], trình biên dịch sau đó sẽ thả vào
gdb target_application297 và chuyển qua tất cả các loại câu lệnh tiềm năng được tìm thấy trong
gdb target_application664
gdb target_application53
Ví dụ, hãy tập trung vào câu lệnh
gdb target_application299, trong Python là
gdb target_application54
Nếu câu lệnh là loại ________ 5299, nó sẽ gọi ________ 6301. Có một hàm
gdb target_application302 tương đương cho tất cả các loại câu lệnh và biểu thức. Các loại đơn giản hơn tạo các hướng dẫn mã byte nội tuyến, một số loại câu lệnh phức tạp hơn gọi các hàm khác
Nhiều câu lệnh có thể có câu lệnh phụ. Vòng lặp
gdb target_application303 có phần thân, nhưng bạn cũng có thể có các biểu thức phức tạp trong phép gán và trình vòng lặp
Các câu lệnh
gdb target_application304 của trình biên dịch sẽ gửi các khối đến trạng thái của trình biên dịch. Các khối này chứa các lệnh, cấu trúc dữ liệu lệnh trong
gdb target_application227 có mã lệnh, bất kỳ đối số nào và khối đích [nếu đây là lệnh nhảy], nó cũng chứa số dòng
Đối với câu lệnh nhảy, chúng có thể là câu lệnh nhảy tuyệt đối hoặc tương đối. Câu lệnh nhảy được sử dụng để “nhảy” từ thao tác này sang thao tác khác. Các câu lệnh nhảy tuyệt đối chỉ định số thao tác chính xác trong đối tượng mã được biên dịch, trong khi các câu lệnh nhảy tương đối chỉ định mục tiêu nhảy liên quan đến thao tác khác
gdb target_application55
Vì vậy, một khối khung [loại
gdb target_application306], chứa các trường sau
- Một con trỏ
gdb target_application
307, liên kết đến danh sách các khối cho trạng thái trình biên dịch - Một danh sách các hướng dẫn
gdb target_application
308, với cả kích thước danh sách được phân bổgdb target_application
309 và số được sử dụnggdb target_application
310 - Khối tiếp theo sau khối này
gdb target_application
311 - Liệu khối có được “nhìn thấy” bởi trình hợp dịch khi duyệt theo chiều sâu trước hay không
- Nếu khối này có opcode
gdb target_application
282 [gdb target_application
313] - Độ sâu của ngăn xếp khi khối này được nhập vào [______6314]
- Phần bù hướng dẫn cho trình biên dịch hợp ngữ
gdb target_application56
Câu lệnh
gdb target_application299 ở đâu đó ở giữa về độ phức tạp. Có 15 bước trong quá trình biên dịch câu lệnh
gdb target_application299 với cú pháp
gdb target_application317
- Tạo một khối mã mới có tên là
gdb target_application
318, khối này cấp phát bộ nhớ và tạo một con trỏgdb target_application
306 - Tạo một khối mã mới có tên là
gdb target_application
320 - Tạo một khối mã mới có tên là
gdb target_application
321 - Đẩy một khối khung loại
gdb target_application
322 vào ngăn xếp với khối đầu vào là khốigdb target_application
318 và khối khối đầu ra làgdb target_application
321 - Truy cập biểu thức trình vòng lặp, biểu thức này sẽ thêm bất kỳ thao tác nào cho trình vòng lặp
- Thêm hoạt động
gdb target_application
325 vào trạng thái trình biên dịch - Chuyển sang khối
gdb target_application
318 - Gọi
gdb target_application
327 gọigdb target_application
328 để thêm hoạt độnggdb target_application
329 với đối số của khốigdb target_application
320 - Truy cập vào
gdb target_application
331 và thêm bất kỳ mã đặc biệt nào, chẳng hạn như giải nén bộ dữ liệu, vào khốigdb target_application
318 - Truy cập từng câu lệnh trong phần thân của vòng lặp for
- Gọi
gdb target_application
333 gọigdb target_application
328 để thêm hoạt độnggdb target_application
335 cho biết sau khi phần thân được thực thi, nhảy trở lại bắt đầu vòng lặp - Di chuyển đến khối
gdb target_application
320 - Đưa khối khung
gdb target_application
322 ra khỏi ngăn xếp - Truy cập các câu lệnh bên trong phần
gdb target_application
338 của vòng lặp for - Sử dụng khối
gdb target_application
321
Nhắc lại cấu trúc
gdb target_application306. Bạn có thể thấy trong quá trình biên dịch câu lệnh for, các khối khác nhau được tạo và đẩy vào ngăn xếp và khối khung của trình biên dịch như thế nào
gdb target_application57
Tùy thuộc vào loại hoạt động, có các đối số khác nhau được yêu cầu. Ví dụ: chúng tôi đã sử dụng
gdb target_application333 và
gdb target_application327 ở đây, đề cập đến “THÊM Thao tác với Nhảy đến một vị trí TƯƠNG QUAN” và “THÊM Thao tác với Nhảy đến một vị trí TUYỆT ĐỐI”. Điều này đề cập đến các macro
gdb target_application343 và
gdb target_application333 gọi
gdb target_application345 và đặt đối số
gdb target_application346 thành 0 và 1 tương ứng
Có một số macro khác, chẳng hạn như
gdb target_application347 gọi
gdb target_application348 để thêm một thao tác với đối số số nguyên hoặc
gdb target_application349 gọi
gdb target_application350 để thêm một thao tác với đối số
gdb target_application001
Khi các giai đoạn này đã hoàn thành, trình biên dịch có một danh sách các khối khung, mỗi khối chứa một danh sách các hướng dẫn và một con trỏ tới khối tiếp theo
Cuộc họp
Với trạng thái trình biên dịch, trình hợp dịch thực hiện “tìm kiếm theo chiều sâu” của các khối và hợp nhất các hướng dẫn thành một chuỗi mã byte đơn. Trạng thái trình biên dịch chương trình được khai báo trong
gdb target_application227
gdb target_application58
Hàm
gdb target_application288 có một vài nhiệm vụ
- Tính số khối để cấp phát bộ nhớ
- Đảm bảo rằng mọi khối rơi ra khỏi cuối đều trả về
gdb target_application
354, đây là lý do tại sao mọi hàm trả về ________ 6354, cho dù có tồn tại câu lệnh ________ 6356 hay không - Giải quyết bất kỳ phần bù nào của câu lệnh nhảy được đánh dấu là tương đối
- Gọi
gdb target_application
357 để thực hiện tìm kiếm theo chiều sâu của các khối - Phát ra tất cả các hướng dẫn cho trình biên dịch
- Gọi
gdb target_application
358 với trạng thái trình biên dịch để tạogdb target_application
220
gdb target_application59
Tìm kiếm theo chiều sâu được thực hiện bởi hàm
gdb target_application357 trong
gdb target_application227, theo sau các con trỏ
gdb target_application311 trong mỗi khối, đánh dấu chúng là đã nhìn thấy bằng cách chuyển đổi
gdb target_application363 và sau đó thêm chúng vào danh sách trình biên dịch mã
gdb target_application364 theo thứ tự ngược lại
Hàm lặp lại danh sách đặt hàng sau của trình biên dịch chương trình hợp ngữ và đối với mỗi khối, nếu nó có thao tác nhảy, hãy gọi đệ quy
gdb target_application357 cho bước nhảy đó
gdb target_application60
Tạo đối tượng mã
Nhiệm vụ của
gdb target_application358 là đi qua trạng thái trình biên dịch, một số thuộc tính của trình biên dịch chương trình hợp ngữ và đưa chúng vào một
gdb target_application220 bằng cách gọi
gdb target_application368
Tên biến, hằng được đặt làm thuộc tính cho đối tượng mã
gdb target_application61
Bạn cũng có thể nhận thấy rằng mã byte được gửi tới
gdb target_application369 trước khi nó được gửi tới
gdb target_application370. Chức năng này là một phần của quá trình tối ưu hóa bytecode trong
gdb target_application371
Trình tối ưu hóa lỗ nhìn trộm xem qua các hướng dẫn mã byte và trong một số trường hợp nhất định, hãy thay thế chúng bằng các hướng dẫn khác. Ví dụ: có một trình tối ưu hóa được gọi là "mở ra liên tục", vì vậy nếu bạn đặt câu lệnh sau vào tập lệnh của mình
gdb target_application62
Nó tối ưu hóa điều đó để
gdb target_application63
Vì 1 và 5 là các giá trị không đổi nên kết quả phải luôn giống nhau
Sự kết luận
Chúng ta có thể kết hợp tất cả các giai đoạn này với mô-đun instaviz
gdb target_application64
Sẽ tạo ra một biểu đồ AST
Với các hướng dẫn mã byte theo trình tự
Ngoài ra, đối tượng mã có tên biến, hằng số và mã nhị phân
gdb target_application273
Chấp hành
Trong
gdb target_application300, chúng tôi đã chia tay ngay trước cuộc gọi tới
gdb target_application369
Cuộc gọi này nhận một đối tượng mã, được tìm nạp từ tệp
gdb target_application821 đã được sắp xếp theo thứ tự hoặc được biên dịch qua các giai đoạn AST và trình biên dịch
gdb target_application369 sẽ vượt qua toàn cầu, địa phương,
gdb target_application890 và biên dịch
gdb target_application220 thành
gdb target_application370 trong
gdb target_application382
Giai đoạn này hình thành thành phần thực thi của CPython. Mỗi hoạt động mã byte được thực hiện và thực thi bằng cách sử dụng hệ thống dựa trên “Khung ngăn xếp”
Khung ngăn xếp là gì?
Khung ngăn xếp là một loại dữ liệu được sử dụng bởi nhiều thời gian chạy, không chỉ Python, cho phép các hàm được gọi và các biến được trả về giữa các hàm. Khung ngăn xếp cũng chứa các đối số, biến cục bộ và thông tin trạng thái khác
Thông thường, một Khung ngăn xếp tồn tại cho mọi lệnh gọi hàm và chúng được xếp chồng lên nhau theo thứ tự. Bạn có thể thấy ngăn xếp khung của CPython bất cứ khi nào một ngoại lệ không được xử lý và ngăn xếp được in trên màn hình
gdb target_application370 là API công khai để đánh giá một đối tượng mã. Logic để đánh giá được phân chia giữa
gdb target_application382 và
gdb target_application383, cả hai đều nằm trong
gdb target_application024
API công khai
gdb target_application370 sẽ xây dựng khung thực thi từ đầu ngăn xếp bằng cách gọi
gdb target_application382
Việc xây dựng khung thực thi đầu tiên có nhiều bước
- Đối số từ khóa và vị trí được giải quyết
- Việc sử dụng
gdb target_application
387 vàgdb target_application
388 trong các định nghĩa hàm đã được giải quyết - Các đối số được thêm dưới dạng biến cục bộ vào phạm vi
- Các đồng quy trình và Trình tạo được tạo, bao gồm cả Trình tạo không đồng bộ
Đối tượng khung trông như thế này
Hãy bước qua các trình tự đó
1. Xây dựng trạng thái chủ đề
Trước khi một khung có thể được thực thi, nó cần được tham chiếu từ một luồng. CPython có thể có nhiều luồng chạy cùng một lúc trong một trình thông dịch. Trạng thái Trình thông dịch bao gồm danh sách các luồng đó dưới dạng danh sách được liên kết. Cấu trúc luồng được gọi là
gdb target_application389 và có nhiều tài liệu tham khảo xuyên suốt
gdb target_application024
Đây là cấu trúc của đối tượng trạng thái luồng
2. xây dựng khung
Đầu vào của
gdb target_application370 và do đó
gdb target_application382 có các đối số cho
gdb target_application
393. mộtgdb target_application
220gdb target_application
395. mộtgdb target_application
396 với tên biến là khóa và giá trị của chúnggdb target_application
397. mộtgdb target_application
396 với tên biến là khóa và giá trị của chúng
Các đối số khác là tùy chọn và không được sử dụng cho API cơ bản
gdb target_application
399. mộtgdb target_application
500 với các giá trị đối số vị trí theo thứ tự vàgdb target_application
501 cho số lượng giá trịgdb target_application
502. một danh sách các tên đối số từ khóagdb target_application
503. một danh sách các giá trị đối số từ khóa vàgdb target_application
504 cho số lượng chúnggdb target_application
505. một danh sách các giá trị mặc định cho các đối số vị trí vàgdb target_application
506 cho độ dàigdb target_application
507. một từ điển với các giá trị mặc định cho các đối số từ khóagdb target_application
508. một bộ có chuỗi để hợp nhất vào trường đối tượng mãgdb target_application
509gdb target_application
510. tên cho câu lệnh đánh giá này dưới dạng một chuỗigdb target_application
511. tên đủ điều kiện cho tuyên bố đánh giá này dưới dạng một chuỗi
gdb target_application65
3. Chuyển đổi tham số từ khóa thành từ điển
Nếu định nghĩa hàm chứa một kiểu bắt tất cả kiểu
gdb target_application388 cho các đối số từ khóa, thì một từ điển mới sẽ được tạo và các giá trị được sao chép qua. Sau đó, tên
gdb target_application503 được đặt làm biến, như trong ví dụ này
gdb target_application66
Logic để tạo từ điển đối số từ khóa nằm trong phần tiếp theo của _PyEval_EvalCodeWithName[]
gdb target_application67
Biến
gdb target_application514 sẽ tham chiếu đến một
gdb target_application515 nếu tìm thấy bất kỳ đối số từ khóa nào
4. Chuyển đổi các đối số vị trí thành các biến
Tiếp theo, mỗi đối số vị trí [nếu được cung cấp] được đặt làm biến cục bộ
gdb target_application68
Ở cuối vòng lặp, bạn sẽ thấy một lệnh gọi tới
gdb target_application516 cùng với giá trị, vì vậy nếu một đối số vị trí được xác định bằng một giá trị, thì giá trị đó khả dụng trong phạm vi này
gdb target_application69
Ngoài ra, bộ đếm tham chiếu cho các biến đó được tăng lên, vì vậy trình thu gom rác sẽ không xóa chúng cho đến khi khung được đánh giá
5. Đóng gói các đối số vị trí vào gdb target_application
387
Tương tự như
gdb target_application388, một đối số chức năng được thêm vào trước bằng một số
gdb target_application830 có thể được đặt để bắt tất cả các đối số vị trí còn lại. Đối số này là một bộ và tên
gdb target_application387 được đặt làm biến cục bộ
gdb target_application700
6. Đang tải đối số từ khóa
Nếu hàm được gọi với các đối số và giá trị từ khóa, thì từ điển
gdb target_application514 được tạo ở bước 4 hiện chứa đầy bất kỳ đối số từ khóa nào còn lại do người gọi chuyển không phân giải thành đối số được đặt tên hoặc đối số vị trí
Ví dụ: đối số
gdb target_application203 không phải là vị trí hoặc được đặt tên, vì vậy nó được thêm vào
gdb target_application523
>>>
gdb target_application701
Đối số chỉ theo vị trí là một tính năng mới trong Python 3. 8. Được giới thiệu trong PEP570, đối số chỉ vị trí là cách ngăn người dùng API của bạn sử dụng đối số vị trí bằng cú pháp từ khóa
Ví dụ: chức năng đơn giản này chuyển đổi Farenheit thành Celcius. Lưu ý, việc sử dụng
gdb target_application524 làm đối số đặc biệt sẽ tách biệt các đối số chỉ vị trí với các đối số khác
gdb target_application702
Tất cả các đối số ở bên trái của
gdb target_application524 chỉ được gọi là đối số vị trí và các đối số ở bên phải có thể được gọi là đối số vị trí hoặc từ khóa
>>>
gdb target_application703
Gọi hàm bằng cách sử dụng đối số từ khóa thành đối số chỉ vị trí sẽ tăng
gdb target_application526
>>>
gdb target_application704
Độ phân giải của các giá trị từ điển đối số từ khóa xuất hiện sau khi giải nén tất cả các đối số khác. Các đối số chỉ vị trí PEP570 được hiển thị bằng cách bắt đầu vòng lặp đối số từ khóa tại
gdb target_application527. Nếu ký hiệu
gdb target_application524 được sử dụng trên đối số thứ 3, giá trị của
gdb target_application527 sẽ là
gdb target_application699.
gdb target_application531 được gọi cho mỗi đối số còn lại để thêm nó vào từ điển
gdb target_application397, vì vậy khi thực thi, mỗi đối số từ khóa là các biến cục bộ có phạm vi
gdb target_application705
Ở cuối vòng lặp, bạn sẽ thấy lệnh gọi tới
gdb target_application516 với giá trị. Nếu một đối số từ khóa được xác định bằng một giá trị, giá trị đó khả dụng trong phạm vi này
gdb target_application706
7. Thêm các đối số vị trí bị thiếu
Bất kỳ đối số vị trí nào được cung cấp cho lệnh gọi hàm không có trong danh sách đối số vị trí sẽ được thêm vào bộ dữ liệu
gdb target_application387 nếu bộ dữ liệu này không tồn tại, sẽ xảy ra lỗi
gdb target_application707
8. Thêm đối số từ khóa bị thiếu
Bất kỳ đối số từ khóa nào được cung cấp cho lệnh gọi hàm không có trong danh sách đối số từ khóa được đặt tên sẽ được thêm vào từ điển
gdb target_application388 nếu từ điển này không tồn tại, sẽ xảy ra lỗi
gdb target_application708
9. Thu gọn đóng cửa
Bất kỳ tên bao đóng nào cũng được thêm vào danh sách tên biến tự do của đối tượng mã
gdb target_application709
10. Tạo Trình tạo, Coroutines và Trình tạo không đồng bộ
Nếu đối tượng mã được đánh giá có cờ là trình tạo, trình tạo coroutine hoặc trình tạo không đồng bộ, thì một khung mới được tạo bằng một trong các phương thức duy nhất trong thư viện Trình tạo, Coroutine hoặc Async và khung hiện tại được thêm làm thuộc tính
Khung mới sau đó được trả lại và khung ban đầu không được đánh giá. Khung chỉ được đánh giá khi phương thức trình tạo/coroutine/async được gọi để thực thi mục tiêu của nó
gdb target_application710
Cuối cùng,
gdb target_application536 được gọi với khung mới
gdb target_application711
Thực thi khung
Như đã đề cập trước đó trong các chương trình biên dịch và AST, đối tượng mã chứa mã hóa nhị phân của mã byte sẽ được thực thi. Nó cũng chứa một danh sách các biến và một bảng ký hiệu
Các biến cục bộ và toàn cục được xác định trong thời gian chạy dựa trên cách hàm, mô-đun hoặc khối đó được gọi. Thông tin này được thêm vào khung bằng hàm
gdb target_application382. Có những cách sử dụng khung khác, chẳng hạn như trình trang trí coroutine, tự động tạo một khung với mục tiêu là một biến
API công khai,
gdb target_application536 gọi chức năng đánh giá khung được định cấu hình của trình thông dịch trong thuộc tính
gdb target_application539. Đánh giá khung có thể cắm được trong Python 3. 7 với PEP 523
gdb target_application383 là chức năng mặc định và thật bất thường khi sử dụng bất kỳ chức năng nào khác ngoài chức năng này
Các khung được thực thi trong vòng thực thi chính bên trong
gdb target_application383. Chức năng này là chức năng trung tâm kết hợp mọi thứ lại với nhau và đưa mã của bạn vào cuộc sống. Nó chứa nhiều thập kỷ tối ưu hóa vì ngay cả một dòng mã cũng có thể có tác động đáng kể đến hiệu suất của toàn bộ CPython
Mọi thứ được thực thi trong CPython đều đi qua chức năng này
Ghi chú. Một điều bạn có thể nhận thấy khi đọc
gdb target_application024, là số lần macro C đã được sử dụng. C Macro là một cách để có mã tuân thủ KHÔ mà không cần thực hiện các lệnh gọi hàm. Trình biên dịch chuyển đổi macro thành mã C và sau đó biên dịch mã được tạo
Nếu bạn muốn xem mã mở rộng, bạn có thể chạy
gdb target_application543 trên Linux và macOS
gdb target_application712
Ngoài ra, Visual Studio Code có thể thực hiện mở rộng macro nội tuyến sau khi bạn đã cài đặt tiện ích mở rộng C/C++ chính thức
Chúng ta có thể từng bước thực thi khung trong Python 3. 7 trở lên bằng cách bật thuộc tính theo dõi trên chuỗi hiện tại
Ví dụ mã này đặt chức năng theo dõi toàn cầu thành một chức năng có tên là
gdb target_application544 lấy ngăn xếp từ khung hiện tại, in các mã lệnh đã được phân tách ra màn hình và một số thông tin bổ sung để gỡ lỗi
gdb target_application713
Điều này in mã trong mỗi ngăn xếp và trỏ đến thao tác tiếp theo trước khi nó được thực thi. Khi một khung trả về một giá trị, câu lệnh trả về được in
Danh sách hướng dẫn đầy đủ có sẵn trên tài liệu mô-đun
gdb target_application274
ngăn xếp giá trị
Bên trong vòng đánh giá cốt lõi, một ngăn xếp giá trị được tạo. Ngăn xếp này là danh sách các con trỏ tới các phiên bản
gdb target_application001 tuần tự
Một cách để nghĩ về ngăn xếp giá trị giống như một cái chốt gỗ mà bạn có thể xếp các hình trụ lên đó. Bạn sẽ chỉ thêm hoặc xóa một mục tại một thời điểm. Điều này được thực hiện bằng cách sử dụng macro
gdb target_application547, trong đó
gdb target_application548 là một con trỏ tới một
gdb target_application001
Ví dụ: nếu bạn đã tạo một
gdb target_application550 với giá trị 10 và đẩy nó vào ngăn xếp giá trị
gdb target_application714
Hành động này sẽ có tác dụng sau
Trong hoạt động tiếp theo, để tìm nạp giá trị đó, bạn sẽ sử dụng macro
gdb target_application551 để lấy giá trị cao nhất từ ngăn xếp
gdb target_application715
Hành động này sẽ trả về giá trị cao nhất và kết thúc bằng một ngăn xếp giá trị trống
Nếu bạn thêm 2 giá trị vào ngăn xếp
gdb target_application716
Chúng sẽ kết thúc theo thứ tự mà chúng được thêm vào, vì vậy
gdb target_application548 sẽ được đẩy lên vị trí thứ hai trong ngăn xếp
Nếu bạn lấy giá trị cao nhất trong ngăn xếp, bạn sẽ nhận được một con trỏ tới
gdb target_application553 vì nó ở trên cùng
Nếu bạn cần tìm nạp con trỏ tới giá trị cao nhất trong ngăn xếp mà không cần bật nó lên, bạn có thể sử dụng thao tác ________ 6554, trong đó _________ 6555 là vị trí ngăn xếp
gdb target_application717
0 đại diện cho đỉnh của ngăn xếp, 1 sẽ là vị trí thứ hai
Để sao chép giá trị ở đầu ngăn xếp, có thể sử dụng macro
gdb target_application556 hoặc bằng cách sử dụng opcode
gdb target_application557
gdb target_application718
Hành động này sẽ sao chép giá trị ở trên cùng để tạo thành 2 con trỏ tới cùng một đối tượng
Có một macro xoay vòng
gdb target_application558 hoán đổi giá trị thứ nhất và thứ hai
Mỗi opcodes có một “hiệu ứng ngăn xếp” được xác định trước, được tính toán bởi hàm
gdb target_application559 bên trong
gdb target_application227. Hàm này trả về delta theo số lượng giá trị bên trong ngăn xếp cho mỗi opcode
Thí dụ. Thêm một mục vào một danh sách
Trong Python, khi bạn tạo một danh sách, phương thức
gdb target_application005 có sẵn trên đối tượng danh sách
gdb target_application719
Trong đó
gdb target_application562 là một đối tượng, bạn muốn thêm vào cuối danh sách
Có 2 thao tác liên quan đến thao tác này.
gdb target_application563, để tải đối tượng
gdb target_application562 lên đầu ngăn xếp giá trị từ danh sách
gdb target_application397 trong khung và
gdb target_application566 để thêm đối tượng
Lần đầu tiên khám phá
gdb target_application563, có 5 bước
Con trỏ tới
gdb target_application
562 được tải từgdb target_application
569, trong đó biến cần tải là đối số hoạt động. Danh sách các con trỏ biến được lưu trữ tronggdb target_application
570, là bản sao của thuộc tính PyFramegdb target_application
571. Đối số hoạt động là một số, trỏ đến chỉ mục trong con trỏ mảnggdb target_application
570. Điều này có nghĩa là việc tải cục bộ chỉ đơn giản là sao chép con trỏ thay vì phải tra cứu tên biếnNếu biến không còn tồn tại, lỗi biến cục bộ không liên kết sẽ xuất hiện
Bộ đếm tham chiếu cho
gdb target_application
634 [trong trường hợp của chúng tôi làgdb target_application
562] được tăng thêm 1Con trỏ tới
gdb target_application
562 được đẩy lên đầu ngăn xếp giá trịMacro
gdb target_application
576 được gọi, nếu tính năng theo dõi được bật, vòng lặp sẽ lặp lại [với tất cả tính năng theo dõi], nếu tính năng theo dõi không được bật, mộtgdb target_application
577 được gọi tớigdb target_application
578, quay trở lại đầu vòng lặp cho lệnh tiếp theo
gdb target_application720
Bây giờ con trỏ tới
gdb target_application562 ở trên cùng của ngăn xếp giá trị. Lệnh tiếp theo
gdb target_application566 được chạy
Nhiều hoạt động mã byte đang tham chiếu đến các loại cơ sở, như PyUnicode, PyNumber. Ví dụ:
gdb target_application566 nối thêm một đối tượng vào cuối danh sách. Để đạt được điều này, nó bật con trỏ từ ngăn xếp giá trị và trả con trỏ về đối tượng cuối cùng trong ngăn xếp. Macro là lối tắt cho
gdb target_application721
Bây giờ con trỏ tới ________ 6562 được lưu dưới dạng ________ 6555. Con trỏ danh sách được tải từ
gdb target_application584
Sau đó, danh sách API C cho Python được gọi cho
gdb target_application585 và
gdb target_application555. Mã cho điều này nằm bên trong
gdb target_application587, mà chúng ta sẽ xem xét trong chương tiếp theo
Một cuộc gọi đến
gdb target_application588 được thực hiện, dự đoán rằng hoạt động tiếp theo sẽ là
gdb target_application335. Macro
gdb target_application588 có các câu lệnh
gdb target_application577 do trình biên dịch tạo cho mỗi câu lệnh
gdb target_application592 của hoạt động tiềm năng. Điều này có nghĩa là CPU có thể nhảy tới lệnh đó và không phải thực hiện lại vòng lặp
gdb target_application722
dự đoán opcode. Một số opcode có xu hướng đi theo cặp, do đó có thể dự đoán mã thứ hai khi mã thứ nhất được chạy. Ví dụ:
gdb target_application593 thường được theo sau bởi
gdb target_application594 hoặc
gdb target_application595
“Việc xác minh dự đoán tốn một bài kiểm tra tốc độ cao duy nhất của biến đăng ký so với hằng số. Nếu ghép nối tốt, thì dự đoán nhánh bên trong của chính bộ xử lý có khả năng thành công cao, dẫn đến quá trình chuyển đổi gần như bằng không sang opcode tiếp theo. Một dự đoán thành công sẽ lưu một chuyến đi qua eval-loop bao gồm cả nhánh trường hợp chuyển đổi không thể đoán trước của nó. Kết hợp với dự đoán nhánh bên trong của bộ xử lý, PREDICT thành công có tác dụng làm cho hai opcode chạy như thể chúng là một opcode mới với các phần thân được kết hợp. ”
Nếu thu thập số liệu thống kê opcode, bạn có hai lựa chọn
- Luôn bật các dự đoán và giải thích kết quả như thể một số opcode đã được kết hợp
- Tắt dự đoán để bộ đếm tần số opcode cập nhật cho cả hai opcode
Dự đoán opcode bị vô hiệu hóa với mã luồng vì mã sau cho phép CPU ghi lại thông tin dự đoán nhánh riêng cho từng opcode
Một số thao tác, chẳng hạn như
gdb target_application596,
gdb target_application597, có một đối số thao tác tham chiếu đến một hàm được biên dịch khác. Trong những trường hợp này, một khung khác được đẩy vào ngăn xếp khung trong luồng và vòng lặp đánh giá được chạy cho chức năng đó cho đến khi chức năng hoàn thành. Mỗi khi một khung hình mới được tạo và đẩy vào ngăn xếp, giá trị của khung hình
gdb target_application598 được đặt thành khung hình hiện tại trước khi khung hình mới được tạo
Việc lồng các khung này sẽ rõ ràng khi bạn nhìn thấy dấu vết ngăn xếp, hãy lấy tập lệnh ví dụ này
gdb target_application723
Gọi cái này trên dòng lệnh sẽ cung cấp cho bạn
gdb target_application724
Trong
gdb target_application599, hàm
gdb target_application600 được sử dụng để in dấu vết ngược lại
gdb target_application725
Ở đây, bạn có thể thấy rằng khung hiện tại, được tìm nạp bằng cách gọi
gdb target_application601 và cha của cha mẹ được đặt làm khung, bởi vì bạn không muốn thấy lệnh gọi tới
gdb target_application600 hoặc
gdb target_application603 trong quá trình theo dõi, vì vậy các khung chức năng đó sẽ bị bỏ qua
Sau đó, con trỏ
gdb target_application598 được đưa lên đầu
gdb target_application601 là API Python để lấy thuộc tính
gdb target_application606 của luồng hiện tại
Đây là giao diện trực quan của ngăn xếp khung đó, với 3 khung, mỗi khung có đối tượng mã của nó và trạng thái luồng trỏ đến khung hiện tại
Sự kết luận
Trong Phần này, bạn đã khám phá yếu tố phức tạp nhất của CPython. trình biên dịch. Tác giả đầu tiên của Python, Guido van Rossum, đã tuyên bố rằng trình biên dịch của CPython nên "câm" để mọi người có thể hiểu được nó
Bằng cách chia nhỏ quá trình biên dịch thành các bước nhỏ hợp lý, nó sẽ dễ hiểu hơn nhiều
Trong chương tiếp theo, chúng tôi kết nối quá trình biên dịch với cơ sở của tất cả các mã Python,
gdb target_application607
Phần 4. Các đối tượng trong Python
CPython đi kèm với một tập hợp các loại cơ bản như chuỗi, danh sách, bộ dữ liệu, từ điển và đối tượng
Tất cả các loại này đều được tích hợp sẵn. Bạn không cần nhập bất kỳ thư viện nào, kể cả từ thư viện chuẩn. Ngoài ra, việc khởi tạo các loại tích hợp này có một số phím tắt tiện dụng
Ví dụ, để tạo một danh sách mới, bạn có thể gọi
gdb target_application726
Hoặc, bạn có thể sử dụng dấu ngoặc vuông
gdb target_application727
Các chuỗi có thể được khởi tạo từ một chuỗi ký tự bằng cách sử dụng dấu ngoặc kép hoặc dấu ngoặc đơn. Chúng tôi đã khám phá các định nghĩa ngữ pháp trước đó khiến trình biên dịch diễn giải các dấu ngoặc kép dưới dạng một chuỗi ký tự
Tất cả các kiểu trong Python kế thừa từ
gdb target_application607, một kiểu cơ sở tích hợp sẵn. Ngay cả các chuỗi, bộ dữ liệu và danh sách kế thừa từ
gdb target_application607. Trong quá trình xem qua mã C, bạn đã đọc rất nhiều tài liệu tham khảo về
gdb target_application322, cấu trúc C-API cho một
gdb target_application607
Vì C không hướng đối tượng như Python nên các đối tượng trong C không kế thừa lẫn nhau.
gdb target_application001 là cấu trúc dữ liệu cho phần đầu bộ nhớ của đối tượng Python
Phần lớn API đối tượng cơ sở được khai báo trong
gdb target_application325, như hàm
gdb target_application614, mà hàm
gdb target_application615 tích hợp sẵn. Bạn cũng sẽ tìm thấy
gdb target_application616 và các API khác
Tất cả các chức năng này có thể được ghi đè trong một đối tượng tùy chỉnh bằng cách triển khai các phương thức "dunder" trên một đối tượng Python
gdb target_application728
Mã này được triển khai trong
gdb target_application617, bên trong
gdb target_application325. Loại đối tượng mục tiêu,
gdb target_application555 sẽ được suy ra thông qua lệnh gọi tới
gdb target_application620 và nếu trường
gdb target_application621 được đặt, thì con trỏ hàm được gọi. Nếu trường
gdb target_application621 không được đặt, tôi. e. đối tượng không khai báo phương thức
gdb target_application623 tùy chỉnh, thì hành vi mặc định được chạy, đó là trả về
gdb target_application624 với tên loại và ID
gdb target_application729
Trường ob_type cho một
gdb target_application322 nhất định sẽ trỏ đến cấu trúc dữ liệu
gdb target_application626, được định nghĩa trong
gdb target_application627. Cấu trúc dữ liệu này liệt kê tất cả các hàm dựng sẵn, dưới dạng các trường và đối số mà chúng sẽ nhận được
Lấy
gdb target_application621 làm ví dụ
gdb target_application730
Trong đó
gdb target_application629 là một
gdb target_application630 cho
gdb target_application631, một hàm lấy 1 con trỏ tới
gdb target_application001 [
gdb target_application633]
Một số API dunder là tùy chọn, vì chúng chỉ áp dụng cho một số loại nhất định, chẳng hạn như số
gdb target_application731
Một trình tự, giống như một danh sách sẽ thực hiện các phương pháp sau
gdb target_application732
Tất cả các chức năng tích hợp này được gọi là Mô hình dữ liệu Python. Một trong những tài nguyên tuyệt vời cho Mô hình dữ liệu Python là “Fluent Python” của Luciano Ramalho
Loại đối tượng cơ sở
Trong
gdb target_application325, việc triển khai cơ sở của loại
gdb target_application607 được viết dưới dạng mã C thuần túy. Có một số triển khai cụ thể của logic cơ bản, như so sánh nông
Không phải tất cả các phương thức trong đối tượng Python đều là một phần của Mô hình dữ liệu, do đó đối tượng Python có thể chứa các thuộc tính [thuộc tính lớp hoặc thuộc tính thể hiện] và phương thức
Một cách đơn giản để nghĩ về một đối tượng Python bao gồm 2 thứ
- Mô hình dữ liệu cốt lõi, với các con trỏ tới các hàm được biên dịch
- Một từ điển với bất kỳ thuộc tính và phương thức tùy chỉnh nào
Mô hình dữ liệu cốt lõi được xác định trong
gdb target_application626 và các chức năng được xác định trong
gdb target_application
325 cho các phương pháp tích hợpgdb target_application
638 cho loạigdb target_application
639gdb target_application
640 cho loạigdb target_application
641gdb target_application
642 cho loạigdb target_application
093gdb target_application
644 cho loạigdb target_application
645gdb target_application
646 cho loạigdb target_application
647 trừu tượng, được sử dụng trong lập trình metagdb target_application
648 được sử dụng cho loại đối tượnggdb target_application
649 tích hợpgdb target_application
650 cho một loại số phức tạpgdb target_application
651 cho một trình vòng lặpgdb target_application
587 cho loạigdb target_application
585gdb target_application
654 cho loại sốgdb target_application
655gdb target_application
656 cho loại bộ nhớ cơ sởgdb target_application
657 cho loại phương thức lớpgdb target_application
658 cho loại mô-đungdb target_application
659 cho một loại không gian têngdb target_application
660 cho một loại từ điển được đặt hànggdb target_application
661 cho bộ tạo phạm vigdb target_application
662 cho loạigdb target_application
663gdb target_application
664 cho loại tham chiếu lát cắtgdb target_application
665 cho loạigdb target_application
666gdb target_application
667 cho loạigdb target_application
668gdb target_application
669 cho loạigdb target_application
670gdb target_application
087 cho loạigdb target_application
090gdb target_application
673 cho một đối tượnggdb target_application
674
Chúng ta sẽ đi sâu vào 3 loại này
- Booleans
- số nguyên
- máy phát điện
Booleans và Integers có nhiều điểm chung, vì vậy chúng tôi sẽ đề cập đến những điểm đó trước
Kiểu số nguyên Bool và dài
Loại
gdb target_application639 là cách triển khai đơn giản nhất trong số các loại tích hợp. Nó kế thừa từ
gdb target_application655 và có các hằng số được xác định trước,
gdb target_application677 và
gdb target_application678. Các hằng số này là các thể hiện bất biến, được tạo khi khởi tạo trình thông dịch Python
Bên trong
gdb target_application638, bạn có thể thấy hàm trợ giúp để tạo một phiên bản
gdb target_application639 từ một số
gdb target_application733
Hàm này sử dụng đánh giá C của một loại số để gán
gdb target_application677 hoặc
gdb target_application678 cho một kết quả và tăng bộ đếm tham chiếu
Các hàm số cho
gdb target_application683,
gdb target_application684 và
gdb target_application685 được triển khai, nhưng phép cộng, phép trừ và phép chia được hủy đăng ký khỏi kiểu cơ sở dài vì sẽ không có ý nghĩa gì khi chia hai giá trị boolean
Việc triển khai
gdb target_application683 cho giá trị
gdb target_application639 sẽ kiểm tra xem
gdb target_application548 và
gdb target_application553 có phải là booleans hay không, sau đó kiểm tra các tham chiếu của chúng tới
gdb target_application677, nếu không, được truyền dưới dạng số và thao tác
gdb target_application683 được chạy trên hai số
gdb target_application734
Loại
gdb target_application655 phức tạp hơn một chút vì yêu cầu bộ nhớ mở rộng. Trong quá trình chuyển đổi từ Python 2 sang Python 3, CPython đã bỏ hỗ trợ cho loại
gdb target_application608 và thay vào đó sử dụng loại
gdb target_application655 làm loại số nguyên chính. Loại
gdb target_application655 của Python khá đặc biệt ở chỗ nó có thể lưu trữ một số có độ dài thay đổi. Độ dài tối đa được đặt trong tệp nhị phân đã biên dịch
Cấu trúc dữ liệu của Python
gdb target_application655 bao gồm tiêu đề
gdb target_application001 và danh sách các chữ số. Danh sách các chữ số,
gdb target_application698 ban đầu được đặt thành một chữ số, nhưng sau đó được mở rộng thành độ dài dài hơn khi được khởi tạo
gdb target_application735
Bộ nhớ được phân bổ cho một
gdb target_application655 mới đến
gdb target_application7000. Hàm này có độ dài cố định và đảm bảo rằng nó nhỏ hơn
gdb target_application7001. Sau đó, nó phân bổ lại bộ nhớ cho
gdb target_application698 để phù hợp với độ dài
Để chuyển đổi loại C
gdb target_application655 thành loại Python
gdb target_application655,
gdb target_application655 được chuyển đổi thành danh sách các chữ số, bộ nhớ cho Python
gdb target_application655 được chỉ định, sau đó từng chữ số được đặt. Bởi vì
gdb target_application655 được khởi tạo với
gdb target_application698 đã có độ dài là 1, nếu số nhỏ hơn 10, thì giá trị được đặt mà không cần cấp phát bộ nhớ
gdb target_application736
Để chuyển đổi một dấu phẩy động hai dấu chấm thành một Python
gdb target_application655,
gdb target_application7010 sẽ thực hiện phép toán cho bạn
gdb target_application737
Phần còn lại của các chức năng triển khai trong
gdb target_application7011 có các tiện ích, chẳng hạn như chuyển đổi chuỗi Unicode thành số với
gdb target_application7012
Đánh giá về loại máy phát điện
Trình tạo Python là các hàm trả về câu lệnh
gdb target_application7013 và có thể được gọi liên tục để tạo thêm giá trị
Thông thường, chúng được sử dụng như một cách hiệu quả hơn về bộ nhớ để lặp qua các giá trị trong một khối dữ liệu lớn, như tệp, cơ sở dữ liệu hoặc qua mạng
Các đối tượng trình tạo được trả về thay cho giá trị khi sử dụng
gdb target_application7013 thay vì
gdb target_application356. Đối tượng trình tạo được tạo từ câu lệnh
gdb target_application7013 và được trả lại cho người gọi
Hãy tạo một trình tạo đơn giản với danh sách 4 giá trị không đổi
>>>
gdb target_application738
Nếu bạn khám phá nội dung của đối tượng trình tạo, bạn có thể thấy một số trường bắt đầu bằng
gdb target_application7017
>>>
gdb target_application739
Loại
gdb target_application7018 được xác định trong
gdb target_application7019 và có 3 hương vị
- đối tượng máy phát điện
- đối tượng quy trình
- Đối tượng trình tạo không đồng bộ
Cả 3 chia sẻ cùng một tập hợp con các trường được sử dụng trong trình tạo và có các hành vi tương tự nhau
Tập trung đầu tiên vào máy phát điện, bạn có thể thấy các trường
gdb target_application
7020 liên kết với mộtgdb target_application
7021 cho trình tạo, trước đó trong chương thực thi, chúng ta đã khám phá việc sử dụng cục bộ và toàn cục bên trong ngăn xếp giá trị của khung. Đây là cách trình tạo ghi nhớ giá trị cuối cùng của các biến cục bộ do khung liên tục giữa các lần gọigdb target_application
7022 được đặt thành 0 hoặc 1 nếu trình tạo hiện đang chạygdb target_application
7023 liên kết với mộtgdb target_application
220 bằng chức năng được biên dịch mang lại trình tạo để nó có thể được gọi lạigdb target_application
7025 liên kết đến danh sách các tham chiếu yếu đến các đối tượng bên trong hàm tạogdb target_application
7026 là tên của máy phát điệngdb target_application
7027 là tên đủ điều kiện của trình tạogdb target_application
7028 dưới dạng một bộ dữ liệu ngoại lệ nếu lệnh gọi trình tạo đưa ra một ngoại lệ
Các trình tạo coroutine và async có các trường giống nhau nhưng được thêm vào trước bằng
gdb target_application7029 và
gdb target_application7030 tương ứng
Nếu bạn gọi
gdb target_application7031 trên đối tượng trình tạo, giá trị tiếp theo sẽ được tạo ra cho đến khi cuối cùng một
gdb target_application7032 được nâng lên
>>>
gdb target_application740
Mỗi khi
gdb target_application7031 được gọi, đối tượng mã bên trong trường
gdb target_application7023 của trình tạo được thực thi dưới dạng một khung mới và giá trị trả về được đẩy vào ngăn xếp giá trị
Bạn cũng có thể thấy rằng
gdb target_application7023 là đối tượng mã được biên dịch cho hàm tạo bằng cách nhập mô-đun
gdb target_application274 và phân tách mã byte bên trong
>>>
gdb target_application741
Bất cứ khi nào
gdb target_application7031 được gọi trên một đối tượng trình tạo, thì
gdb target_application7038 được gọi với thể hiện của trình tạo, ngay lập tức gọi
gdb target_application7039 bên trong
gdb target_application7040
gdb target_application7039 là hàm chuyển đổi một đối tượng trình tạo thành kết quả mang lại tiếp theo. Bạn sẽ thấy nhiều điểm tương đồng với cách các khung được xây dựng trong
gdb target_application382 từ một đối tượng mã vì các chức năng này có nhiệm vụ tương tự nhau
Hàm
gdb target_application7039 được chia sẻ với các trình tạo, coroutines và trình tạo không đồng bộ và có các bước sau
Trạng thái luồng hiện tại được tìm nạp
Đối tượng khung từ đối tượng trình tạo được tìm nạp
Nếu trình tạo đang chạy khi
gdb target_application
7031 được gọi, hãy tăng mộtgdb target_application
7045Nếu khung bên trong trình tạo nằm ở trên cùng của ngăn xếp
- Trong trường hợp của một coroutine, nếu coroutine chưa được đánh dấu là đóng, một
gdb target_application
7046 sẽ xuất hiện - Nếu đây là trình tạo không đồng bộ, hãy tăng số lượng
gdb target_application
7047 - Đối với một trình tạo tiêu chuẩn, một
gdb target_application
7032 được nâng lên
- Trong trường hợp của một coroutine, nếu coroutine chưa được đánh dấu là đóng, một
Nếu lệnh cuối cùng trong khung [
gdb target_application
7049] vẫn là -1 vì nó mới được bắt đầu và đây là trình tạo coroutine hoặc async, thì không thể chuyển giá trị non-None làm đối số, do đó, một ngoại lệ sẽ được đưa raKhác, đây là lần đầu tiên nó được gọi và các đối số được cho phép. Giá trị của đối số được đẩy vào ngăn xếp giá trị của khung
Trường
gdb target_application
598 của khung là trình gọi mà các giá trị trả về được gửi đến, do đó, trường này được đặt thành khung hiện tại trong chuỗi. Điều này có nghĩa là giá trị trả về được gửi đến người gọi, không phải người tạo trình tạoTrình tạo được đánh dấu là đang chạy
Ngoại lệ cuối cùng trong thông tin ngoại lệ của trình tạo được sao chép từ ngoại lệ cuối cùng trong trạng thái luồng
Thông tin ngoại lệ trạng thái luồng được đặt thành địa chỉ thông tin ngoại lệ của trình tạo. Điều này có nghĩa là nếu người gọi nhập điểm dừng xung quanh việc thực thi trình tạo, thì dấu vết ngăn xếp sẽ đi qua trình tạo và mã vi phạm sẽ bị xóa
Khung bên trong trình tạo được thực thi trong vòng lặp thực thi chính của
gdb target_application
382 và giá trị được trả vềNgoại lệ cuối cùng của trạng thái luồng được đặt lại thành giá trị trước khi khung được gọi
Trình tạo được đánh dấu là không chạy
Sau đó, các trường hợp sau khớp với giá trị trả về và bất kỳ ngoại lệ nào được đưa ra bởi lệnh gọi đến trình tạo. Hãy nhớ rằng các trình tạo sẽ tăng
gdb target_application
7032 khi chúng cạn kiệt, theo cách thủ công hoặc bằng cách không mang lại giá trị. Các trình tạo coroutines và async không nên- Nếu không có kết quả nào được trả về từ khung, hãy tăng
gdb target_application
7032 cho trình tạo vàgdb target_application
7047 cho trình tạo không đồng bộ - Nếu một
gdb target_application
7032 đã được nâng lên một cách rõ ràng, nhưng đây là một trình tạo coroutine hoặc một trình tạo không đồng bộ, hãy tăng mộtgdb target_application
7046 vì điều này không được phép - Nếu một
gdb target_application
7047 đã được nâng lên một cách rõ ràng và đây là một trình tạo không đồng bộ, hãy tăng mộtgdb target_application
7046, vì điều này không được phép
- Nếu không có kết quả nào được trả về từ khung, hãy tăng
Cuối cùng, kết quả được trả lại cho người gọi của
gdb target_application
7031
gdb target_application742
Quay trở lại việc đánh giá các đối tượng mã bất cứ khi nào một hàm hoặc mô-đun được gọi, có một trường hợp đặc biệt đối với trình tạo, coroutines và trình tạo không đồng bộ trong
gdb target_application382. Hàm này kiểm tra các cờ
gdb target_application7061,
gdb target_application7062 và
gdb target_application7063 trên đối tượng mã
Khi một coroutine mới được tạo bằng
gdb target_application7064, một trình tạo không đồng bộ mới được tạo bằng
gdb target_application7065 hoặc một trình tạo bằng
gdb target_application7066. Các đối tượng này được trả về sớm thay vì trả về một khung đã đánh giá, đó là lý do tại sao bạn nhận được một đối tượng trình tạo sau khi gọi một hàm bằng câu lệnh suất
gdb target_application743
Các cờ trong đối tượng mã đã được trình biên dịch đưa vào sau khi duyệt qua AST và nhìn thấy các câu lệnh
gdb target_application7013 hoặc
gdb target_application7068 hoặc nhìn thấy trình trang trí
gdb target_application7069
gdb target_application7066 sẽ gọi
gdb target_application7071 với khung được tạo và sau đó tạo
gdb target_application7018 với các giá trị
gdb target_application7073 và đối tượng mã được biên dịch
gdb target_application744
Kết hợp tất cả những điều này lại với nhau, bạn có thể thấy cách biểu thức trình tạo là một cú pháp mạnh mẽ trong đó một từ khóa duy nhất,
gdb target_application7013 kích hoạt toàn bộ luồng để tạo một đối tượng duy nhất, sao chép một đối tượng mã đã biên dịch làm thuộc tính, đặt khung và lưu trữ danh sách các biến
Đối với người sử dụng biểu thức trình tạo, tất cả điều này có vẻ giống như ma thuật, nhưng dưới vỏ bọc thì nó không phức tạp lắm
Sự kết luận
Bây giờ bạn đã hiểu cách một số loại tích hợp sẵn, bạn có thể khám phá các loại khác
Khi khám phá các lớp Python, điều quan trọng cần nhớ là có các loại dựng sẵn, được viết bằng C và các lớp kế thừa từ các loại đó, được viết bằng Python hoặc C
Một số thư viện có các kiểu được viết bằng C thay vì kế thừa từ các kiểu dựng sẵn. Một ví dụ là
gdb target_application7075, một thư viện cho các mảng số. Loại
gdb target_application7076 được viết bằng C, hiệu quả cao và hoạt động hiệu quả
Phần tiếp theo chúng ta sẽ tìm hiểu các lớp và hàm được định nghĩa trong thư viện chuẩn
Phần 5. Thư viện chuẩn Python
Python đã luôn đi kèm với “pin đi kèm. ” Tuyên bố này có nghĩa là với bản phân phối CPython tiêu chuẩn, có các thư viện để làm việc với tệp, luồng, mạng, trang web, nhạc, bàn phím, màn hình, văn bản và toàn bộ tiện ích
Một số pin đi kèm với CPython giống pin AA hơn. Chúng hữu ích cho mọi thứ, như mô-đun
gdb target_application7077 và mô-đun
gdb target_application7078. Một số trong số chúng khó hiểu hơn một chút, chẳng hạn như pin đồng hồ nhỏ mà bạn không bao giờ biết khi nào nó có thể hữu ích
Có 2 loại module trong thư viện chuẩn của Python
- Những thứ được viết bằng Python thuần túy cung cấp tiện ích
- Những thứ được viết bằng C với trình bao bọc Python
Chúng ta sẽ khám phá cả hai loại
Mô-đun Python
Các mô-đun được viết bằng Python thuần túy đều nằm trong thư mục
gdb target_application7079 trong mã nguồn. Một số mô-đun lớn hơn có các mô-đun con trong các thư mục con, chẳng hạn như mô-đun
gdb target_application7080
Một mô-đun dễ xem sẽ là mô-đun
gdb target_application7081. Nó chỉ có vài trăm dòng mã Python. Có thể bạn chưa gặp nó trước đây. Mô-đun
gdb target_application7081 có một số chức năng tiện ích để chuyển đổi thang màu
Khi bạn cài đặt bản phân phối Python từ nguồn, các mô-đun thư viện tiêu chuẩn sẽ được sao chép từ thư mục
gdb target_application7083 vào thư mục phân phối. Thư mục này luôn là một phần trong đường dẫn của bạn khi bạn khởi động Python, vì vậy bạn có thể
gdb target_application7084 các mô-đun mà không phải lo lắng về vị trí của chúng
Ví dụ
>>>
gdb target_application745
Chúng ta có thể thấy mã nguồn của
gdb target_application7085 bên trong
gdb target_application7086
gdb target_application746
Không có gì đặc biệt về chức năng này, nó chỉ là Python tiêu chuẩn. Bạn sẽ tìm thấy những thứ tương tự với tất cả các mô-đun thư viện chuẩn Python thuần túy. Chúng chỉ được viết bằng Python đơn giản, bố cục tốt và dễ hiểu. Bạn thậm chí có thể phát hiện ra các cải tiến hoặc lỗi, vì vậy bạn có thể thay đổi chúng và đóng góp vào bản phân phối Python. Chúng tôi sẽ đề cập đến điều đó vào cuối bài viết này
Mô-đun Python và C
Phần còn lại của các mô-đun được viết bằng C hoặc kết hợp hoặc Python và C. Mã nguồn của những thứ này nằm trong
gdb target_application7079 cho thành phần Python và
gdb target_application7088 cho thành phần C. Có hai trường hợp ngoại lệ đối với quy tắc này, mô-đun
gdb target_application7078, có trong
gdb target_application7090 và mô-đun
gdb target_application7091, có trong
gdb target_application7092
Python sẽ
gdb target_application7093 khi trình thông dịch được khởi tạo, vì vậy tất cả các hàm như
gdb target_application7094,
gdb target_application7095,
gdb target_application7096, v.v. được tìm thấy trong
gdb target_application7092
Bởi vì mô-đun
gdb target_application7078 rất dành riêng cho trình thông dịch và phần bên trong của CPython, được tìm thấy trực tiếp bên trong
gdb target_application813. Nó cũng được đánh dấu là "chi tiết triển khai" của CPython và không tìm thấy trong các bản phân phối khác
Hàm
gdb target_application7094 tích hợp có lẽ là điều đầu tiên bạn học được trong Python. Vậy điều gì xảy ra khi bạn gõ
gdb target_application7101?
- Đối số
gdb target_application
7102 đã được trình biên dịch chuyển đổi từ hằng chuỗi thànhgdb target_application
7103 gdb target_application
7104 được thực thi với 1 đối số và NULLgdb target_application
502- Biến
gdb target_application
7106 được đặt thànhgdb target_application
7107, tay cầmgdb target_application
7108 của hệ thống - Mỗi đối số được gửi đến
gdb target_application
7106 - Ngắt dòng,
gdb target_application
7110 được gửi đếngdb target_application
7106
gdb target_application747
Nội dung của một số mô-đun được viết bằng C hiển thị các chức năng của hệ điều hành. Do mã nguồn CPython cần biên dịch sang macOS, Windows, Linux và các hệ điều hành dựa trên *nix khác nên có một số trường hợp đặc biệt
Mô-đun
gdb target_application7112 là một ví dụ điển hình. Cách Windows giữ và lưu trữ thời gian trong Hệ điều hành về cơ bản khác với Linux và macOS. Đây là một trong những lý do tại sao độ chính xác của các chức năng đồng hồ khác nhau giữa các hệ điều hành
Trong
gdb target_application7113, các hàm thời gian của hệ điều hành cho các hệ thống dựa trên Unix được nhập từ
gdb target_application7114
gdb target_application748
Sau này trong tệp,
gdb target_application7115 được định nghĩa là trình bao bọc cho
gdb target_application7116
gdb target_application749
gdb target_application7116 được triển khai theo nhiều cách khác nhau trong mã nguồn, nhưng chỉ một số phần nhất định được biên dịch thành tệp nhị phân cho mô-đun, tùy thuộc vào hệ điều hành. Hệ thống Windows sẽ gọi
gdb target_application7118 và hệ thống Unix sẽ gọi
gdb target_application7119
Các mô-đun khác có nhiều triển khai cho cùng một API là mô-đun luồng, mô-đun hệ thống tệp và mô-đun mạng. Do các Hệ điều hành hoạt động khác nhau, nên mã nguồn CPython thực hiện cùng một hành vi tốt nhất có thể và hiển thị nó bằng cách sử dụng API trừu tượng, nhất quán
Bộ kiểm tra hồi quy CPython
CPython có bộ thử nghiệm mạnh mẽ và mở rộng bao gồm trình thông dịch lõi, thư viện chuẩn, công cụ và phân phối cho cả Windows và Linux/macOS
Bộ thử nghiệm được đặt tại
gdb target_application7120 và được viết gần như hoàn toàn bằng Python
Bộ thử nghiệm đầy đủ là một gói Python, vì vậy có thể chạy bằng trình thông dịch Python mà bạn đã biên dịch. Thay đổi thư mục thành thư mục
gdb target_application7083 và chạy
gdb target_application7122, trong đó
gdb target_application7123 có nghĩa là sử dụng 2 CPU
Trên Windows, sử dụng tập lệnh
gdb target_application7124 bên trong thư mục PCBuild, đảm bảo rằng bạn đã xây dựng trước cấu hình Phát hành từ Visual Studio
gdb target_application750
Trên Linux
gdb target_application751
Trên macOS
gdb target_application752
Một số bài kiểm tra yêu cầu một số cờ nhất định; . Ví dụ: nhiều bài kiểm tra IDLE yêu cầu GUI
Để xem danh sách các bộ thử nghiệm trong cấu hình, hãy sử dụng cờ
gdb target_application7125
gdb target_application753
Bạn có thể chạy các thử nghiệm cụ thể bằng cách cung cấp bộ thử nghiệm làm đối số đầu tiên
gdb target_application754
Bạn cũng có thể xem danh sách chi tiết các bài kiểm tra đã được thực hiện với kết quả bằng cách sử dụng đối số
gdb target_application056
gdb target_application755
Hiểu cách sử dụng bộ kiểm tra và kiểm tra trạng thái của phiên bản bạn đã biên dịch là rất quan trọng nếu bạn muốn thay đổi CPython. Trước khi bắt đầu thực hiện các thay đổi, bạn nên chạy toàn bộ bộ thử nghiệm và đảm bảo mọi thứ đều ổn
Cài đặt phiên bản tùy chỉnh
Từ kho lưu trữ nguồn của bạn, nếu bạn hài lòng với những thay đổi của mình và muốn sử dụng chúng bên trong hệ thống của mình, bạn có thể cài đặt nó dưới dạng phiên bản tùy chỉnh
Đối với macOS và Linux, bạn có thể sử dụng lệnh
gdb target_application7127, lệnh này sẽ không tạo liên kết tượng trưng cho
gdb target_application7128 và cài đặt phiên bản độc lập
gdb target_application756
Đối với Windows, bạn phải thay đổi cấu hình bản dựng từ
gdb target_application7129 thành
gdb target_application7130, sau đó sao chép các tệp nhị phân được đóng gói vào một thư mục trên máy tính của bạn. Đây là một phần của đường dẫn hệ thống
Mã nguồn CPython. Sự kết luận
Xin chúc mừng, bạn đã làm được. Trà của bạn có bị nguội không? . Bạn đã kiếm được nó
Bây giờ bạn đã thấy mã nguồn CPython, các mô-đun, trình biên dịch và công cụ, bạn có thể muốn thực hiện một số thay đổi và đóng góp chúng trở lại hệ sinh thái Python
Hướng dẫn dành cho nhà phát triển chính thức chứa nhiều tài nguyên dành cho người mới bắt đầu. Bạn đã thực hiện bước đầu tiên để hiểu mã nguồn, biết cách thay đổi, biên dịch và kiểm tra các ứng dụng CPython
Nghĩ lại tất cả những điều bạn đã học về CPython qua bài viết này. Tất cả những mảnh ma thuật mà bạn đã học được những bí mật. Cuộc hành trình không dừng lại ở đây
Đây có thể là thời điểm tốt để tìm hiểu thêm về Python và C. Ai biết. bạn có thể ngày càng đóng góp nhiều hơn cho dự án CPython. Ngoài ra, hãy nhớ xem cuốn sách CPython Internals mới có sẵn tại đây trên Real Python
Tải xuống miễn phí. Nhận một chương mẫu từ CPython Internals. Hướng dẫn về Trình thông dịch Python 3 chỉ cho bạn cách mở khóa hoạt động bên trong của ngôn ngữ Python, biên dịch trình thông dịch Python từ mã nguồn và tham gia phát triển CPython
Đánh dấu là đã hoàn thành
🐍 Thủ thuật Python 💌
Nhận một Thủ thuật Python ngắn và hấp dẫn được gửi đến hộp thư đến của bạn vài ngày một lần. Không có thư rác bao giờ. Hủy đăng ký bất cứ lúc nào. Được quản lý bởi nhóm Real Python
Gửi cho tôi thủ thuật Python »
Về Anthony Shaw
Anthony là một Pythonista cuồng nhiệt và viết cho Real Python. Anthony là thành viên của Python Software Foundation và là thành viên của Open-Source Apache Foundation
» Thông tin thêm về AnthonyMỗi hướng dẫn tại Real Python được tạo bởi một nhóm các nhà phát triển để nó đáp ứng các tiêu chuẩn chất lượng cao của chúng tôi. Các thành viên trong nhóm đã làm việc trong hướng dẫn này là
Aldren
Jim
Joanna
Bậc thầy Kỹ năng Python trong thế giới thực Với quyền truy cập không giới hạn vào Python thực
Tham gia với chúng tôi và có quyền truy cập vào hàng nghìn hướng dẫn, khóa học video thực hành và cộng đồng các Pythonistas chuyên gia
Nâng cao kỹ năng Python của bạn »
Bậc thầy Kỹ năng Python trong thế giới thực
Với quyền truy cập không giới hạn vào Python thực
Tham gia với chúng tôi và có quyền truy cập vào hàng ngàn hướng dẫn, khóa học video thực hành và cộng đồng Pythonistas chuyên gia
Nâng cao kỹ năng Python của bạn »
Bạn nghĩ sao?
Đánh giá bài viết này
Tweet Chia sẻ Chia sẻ EmailBài học số 1 hoặc điều yêu thích mà bạn đã học được là gì?
Mẹo bình luận. Những nhận xét hữu ích nhất là những nhận xét được viết với mục đích học hỏi hoặc giúp đỡ các sinh viên khác. Nhận các mẹo để đặt câu hỏi hay và nhận câu trả lời cho các câu hỏi phổ biến trong cổng thông tin hỗ trợ của chúng tôi