Đối tượng mã python vào nguồn

Đâ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_application
148, 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_application
149 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_application
150 để kết xuất mã byte vào tệp. Thuận tiện là định dạng
gdb target_application
148 chỉ đơn giản là một
gdb target_application
152 được sắp xếp theo thứ tự với một tiêu đề nhỏ

Tập lệnh

gdb target_application
0 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_application
1 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ố 8

Giờ đây, GDB có thể được tự động kết xuất mọi

gdb target_application
152 đượ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_application
7

gdb target_application
0

Đối số đầu tiên của

gdb target_application
8 phải nằm trong sổ đăng ký
gdb target_application
9 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_application
1 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_application
4

Tiêu đề cho tệp

gdb target_application
2 đã 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_application
757 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_application
758 là từ khóa dành riêng và
gdb target_application
759 đượ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áo

Có 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_application
764 để kéo phiên bản mới nhất về bản sao đang hoạt động cục bộ

gdb target_application
5

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_application
765 mới được tải xuống, bạn sẽ tìm thấy các thư mục con sau

gdb target_application
7

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_application
8

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_application
766

gdb target_application
0

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_application
767, 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_application
768

gdb target_application
3

Điều này sẽ tạo ra một

gdb target_application
769 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_application
770 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_application
6

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_application
773 ngăn
gdb target_application
769 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_application
775,
gdb target_application
776,
gdb target_application
777,
gdb target_application
778,
gdb target_application
779,
gdb target_application
780 và
gdb target_application
781 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_application
782. Mỗi khi bạn thay đổi mã nguồn, bạn sẽ cần chạy lại
gdb target_application
772 với cùng các cờ. Tệp nhị phân
gdb target_application
782 là tệp nhị phân gỡ lỗi của CPython. Thực thi
gdb target_application
782 để xem REPL đang hoạt động

gdb target_application
2

Ghi chú. Vâng, đúng vậy, bản dựng macOS có phần mở rộng tệp cho

gdb target_application
786. Đ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_application
787 nên
gdb target_application
786 đã được thêm vào để tránh sự mơ hồ. Nếu sau này bạn chạy
gdb target_application
789 hoặc
gdb target_application
790, nó sẽ đổi tên tệp trở lại
gdb target_application
757

Loạ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_application
3

Đối với Debian, Ubuntu hoặc các hệ thống dựa trên

gdb target_application
796 khác

gdb target_application
5

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_application
6

Đối với Debian, Ubuntu hoặc các hệ thống dựa trên

gdb target_application
796 khác

gdb target_application
70

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_application
767, kích hoạt móc gỡ lỗi
gdb target_application
768

gdb target_application
71

Xem lại đầu ra để đảm bảo rằng hỗ trợ OpenSSL được đánh dấu là

gdb target_application
800. 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_application
769 đã tạo

gdb target_application
6

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_application
757. Đây là nhị phân gỡ lỗi của CPython. Thực thi
gdb target_application
803 để xem REPL đang hoạt động

gdb target_application
73

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_application
804 để 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_application
805, bằng cách nhấp vào Giải pháp và Dự án và chọn
gdb target_application
806

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_application
807 có tệp
gdb target_application
808 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_application
807 đã tải xuống và chạy
gdb target_application
810

gdb target_application
74

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_application
811

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_application
812->______2813->
gdb target_application
814 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_application
815, ví dụ:
gdb target_application
816 và
gdb target_application
817. 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_application
816 làm trình thông dịch bên trong
gdb target_application
819 và
gdb target_application
817 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áo

Trì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_application
821 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

  1. 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
  2. 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_application
824 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_application
75

Bên trong

gdb target_application
825, 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_application
826

Câu lệnh

gdb target_application
826 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_application
76

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_application
828

gdb target_application
77

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_application
78

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_application
829

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ại
  • gdb target_application
    831 để lặp lại ít nhất một lần
  • gdb target_application
    759 cho các bộ phận tùy chọn
  • gdb 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_application
826 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_application
826

gdb target_application
79

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_application
837 được chỉ định là

  1. Bắt đầu bằng từ
    gdb target_application
    826
  2. Tiếp theo là một
    gdb target_application
    839, là một
    gdb target_application
    840 và [tùy chọn], từ
    gdb target_application
    828, và một biểu thức
  3. 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
  4. Kết thúc bằng một
    gdb target_application
    842
  5. 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ệnh
  • gdb 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_application
847 được sử dụng.
gdb target_application
847 đọ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_application
847 đượ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_application
847, 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_application
852

gdb target_application
80

Thay đổi dòng đó để chấp nhận từ khóa

gdb target_application
853 hoặc
gdb target_application
854 làm từ khóa

gdb target_application
81

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_application
855 để chạy
gdb target_application
847 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_application
847. Tuy nhiên, bạn có thể sao chép ngã ba của tôi và chạy
gdb target_application
858 từ trong thư mục
gdb target_application
807

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_application
860 và
gdb target_application
861 mới đã được tạo

gdb target_application
82

Ghi chú.

gdb target_application
847 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_application
852, hãy sử dụng từ khóa thay thế
gdb target_application
864 mà bạn đã biên dịch thành ngữ pháp Python

gdb target_application
83

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_application
865 là tệp
gdb target_application
866, 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_application
866 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_application
84

Cũng như với tệp

gdb target_application
865, nếu bạn thay đổi tệp
gdb target_application
866, bạn cần chạy lại
gdb target_application
847

Để 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_application
874

gdb target_application
85

Đối với phần còn lại của hướng dẫn này,

gdb target_application
875 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_application
86

cho Linux

gdb target_application
87

Đối với macOS

gdb target_application
88

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_application
873. 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_application
877 để xuất tên mã thông báo chính xác

gdb target_application
89

Ở đầ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_application
873 đã ngụ ý một số mã thông báo không có trong tệp. Mã thông báo
gdb target_application
879 cho
gdb target_application
880 và một dòng trống ở cuối, cung cấp cho
gdb target_application
881 để đóng phần khai báo hàm và một
gdb target_application
882 để 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_application
873 được viết bằng Python thuần túy và nằm ở
gdb target_application
884 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_application
885. Sử dụng tập lệnh
gdb target_application
874 mà bạn đã tạo trước đó, hãy chạy tập lệnh đó như sau

gdb target_application
00

Trong kết quả, bạn có thể thấy rằng nó đánh dấu

gdb target_application
864 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_application
847 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_application
889, sẽ được trình bày trong chương sau

Loạ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_application
890. Đấ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_application
891 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_application
890 đượ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_application
893. 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_application
894. 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_application
895

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_application
890 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_application
897 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_application
897 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_application
890 bằng cách gọi
gdb target_application
000 từ
gdb target_application
001 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_application
002. 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_application
003

Lấy ví dụ về

gdb target_application
893. Nếu bạn
gdb target_application
005 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_application
005 gọi
gdb target_application
007 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_application
008 được gọi để mở rộng bộ nhớ được phân bổ trong danh sách.
gdb target_application
008 là trình bao bọc API cho
gdb target_application
010

Python cũng có một trình bao bọc đặc biệt cho lệnh gọi C

gdb target_application
011, đặ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_application
012]

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_application
01

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

gdb target_application
016 chưa có trong từ điển
gdb target_application
017 hoặc
gdb target_application
018 nên đối tượng mới này được tạo và giá trị được gán là hằng số
gdb target_application
019

Hiện tại có một tham chiếu đến

gdb target_application
016, vì vậy bộ đếm tham chiếu cho
gdb target_application
016 được tăng thêm 1

Bạn sẽ thấy các lệnh gọi hàm

gdb target_application
022 và
gdb target_application
023 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_application
024, 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_application
023 được gọi và bộ đếm trở thành 0, hàm
gdb target_application
026 được gọi. Đối với đối tượng đó,
gdb target_application
003 đượ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_application
028. Đây là cách sử dụng mô-đun
gdb target_application
028 ở chế độ gỡ lỗi

>>>

gdb target_application
02

Đ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_application
030

>>>

gdb target_application
03

Bạn cũng có thể nhận được số lượng ngưỡng hiện tại

>>>

gdb target_application
04

Cuối cùng, bạn có thể chạy thủ công thuật toán thu thập

>>>

gdb target_application
05

Điều này sẽ gọi

gdb target_application
031 bên trong tệp
gdb target_application
032 chứa việc triển khai thuật toán thu gom rác

Loạ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_application
757 đến phần mã của bạn được thực thi

Có năm cách nhị phân

gdb target_application
757 có thể được gọi

  1. Để chạy một lệnh duy nhất với
    gdb target_application
    035 và lệnh Python
  2. Để bắt đầu một mô-đun với
    gdb target_application
    036 và tên của một mô-đun
  3. Để chạy một tệp có tên tệp
  4. Để chạy đầu vào
    gdb target_application
    037 bằng shell pipe
  5. Để 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à

  1. gdb target_application
    038 là một điểm vào đơn giản
  2. gdb 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ớ
  3. 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ỗi

  • Cá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
    049

  • Macro 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_application
052 có tên là
gdb target_application
053

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_application
056. Ở 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_application
06

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_application
052 bên trong
gdb target_application
058 cho
gdb target_application
053

gdb target_application
07

Trong

gdb target_application
040, 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_application
061, 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_application
08

Đối với cài đặt dài dòng, bạn có thể thấy rằng giá trị của

gdb target_application
062 được sử dụng để đặt giá trị của
gdb target_application
063, nếu tìm thấy
gdb target_application
062. Nếu biến môi trường không tồn tại thì giá trị mặc định của
gdb target_application
065 sẽ được giữ nguyên

Sau đó, trong

gdb target_application
066 trong
gdb target_application
067 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_application
09

Giá trị này sau đó được sao chép vào biến toàn cục

gdb target_application
068 bằng hàm
gdb target_application
069

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_application
070. Các cờ
gdb target_application
071 đều có sẵn trong từ điển
gdb target_application
072

>>>

gdb target_application
30

Ngoài cấu hình thời gian chạy trong

gdb target_application
073, còn có cấu hình bản dựng nằm bên trong
gdb target_application
074 trong thư mục gốc. Tệp này được tạo động trong bước
gdb target_application
767 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_application
31

Loạ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_application
076 bên trong
gdb target_application
039. Tùy thuộc vào phiên bản
gdb target_application
078 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_application
035 và một chương trình Python bên trong dấu ngoặc kép

Ví dụ

gdb target_application
32

Đây là sơ đồ đầy đủ về cách điều này xảy ra

Đầu tiên, hàm

gdb target_application
081 được thực thi bên trong
gdb target_application
039 lấy lệnh được truyền trong
gdb target_application
035 làm đối số trong kiểu C
gdb target_application
084. Loại
gdb target_application
084 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_application
084 thành chuỗi Python, tệp
gdb target_application
087 có hàm trợ giúp
gdb target_application
088 trả về một
gdb target_application
001, loại
gdb target_application
090. Mã hóa thành UTF8 sau đó được thực hiện bởi
gdb target_application
091 trên đối tượng Python
gdb target_application
090 để chuyển đổi nó thành đối tượng Python
gdb target_application
093

Khi quá trình này hoàn tất, sau đó,

gdb target_application
081 sẽ chuyển đối tượng byte Python sang
gdb target_application
095 để thực thi, nhưng trước tiên hãy chuyển đổi lại loại
gdb target_application
093 thành loại
gdb target_application
090

gdb target_application
33

Việc chuyển đổi

gdb target_application
084 thành Unicode, byte và sau đó là một chuỗi tương đương như sau

gdb target_application
34

Hàm

gdb target_application
095 là một phần của
gdb target_application
300. 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_application
301 để đượ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_application
35

Khi

gdb target_application
095 đã tạo một mô-đun và một từ điển, nó sẽ gọi
gdb target_application
303, 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_application
304

gdb target_application
36

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_application
036 với tên của một mô-đun. Ví dụ điển hình là
gdb target_application
307 để 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_application
036 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_application
301. Điều đó cũng ngụ ý rằng bạn muốn tìm kiếm mô-đun có tên
gdb target_application
310

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_application
763 trên hệ thống tệp của mình

Bên trong

gdb target_application
039 có một chức năng được gọi khi dòng lệnh được chạy với cờ
gdb target_application
036. Tên của mô-đun được truyền dưới dạng đối số
gdb target_application
314

CPython sau đó sẽ nhập một mô-đun thư viện chuẩn,

gdb target_application
315 và thực thi nó bằng cách sử dụng
gdb target_application
316. Quá trình nhập được thực hiện bằng hàm C API
gdb target_application
317, được tìm thấy trong tệp
gdb target_application
318

gdb target_application
37

Trong hàm này, bạn cũng sẽ thấy 2 hàm C API khác.

gdb target_application
316 và
gdb target_application
320. Bởi vì
gdb target_application
317 trả về một
gdb target_application
322, 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_application
323. Trong API C, cuộc gọi này là
gdb target_application
320, được tìm thấy trong
gdb target_application
325. 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_application
326 trên bất kỳ đối tượng Python nào. Phương thức
gdb target_application
326 được triển khai bên trong
gdb target_application
325

gdb target_application
38

Mô-đun

gdb target_application
315 được viết bằng Python thuần túy và nằm trong
gdb target_application
330

Thực thi

gdb target_application
331 tương đương với việc chạy
gdb target_application
332. Mô-đun
gdb target_application
315 đượ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_application
315 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_application
315 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_application
757 là một tên tệp, chẳng hạn như
gdb target_application
341, thì CPython sẽ mở một bộ điều khiển tệp, tương tự như sử dụng
gdb target_application
342 trong Python và chuyển bộ điều khiển đó tới
gdb target_application
343 bên trong
gdb target_application
300

Có 3 con đường mà hàm này có thể đi

  1. Nếu đường dẫn tệp là tệp
    gdb target_application
    821, nó sẽ gọi
    gdb target_application
    346
  2. Nếu đường dẫn tệp là tệp script [______3347] thì nó sẽ chạy ____3348
  3. Nếu đường dẫn tệp là
    gdb target_application
    037 vì người dùng đã chạy
    gdb target_application
    350 thì hãy coi
    gdb target_application
    037 là phần xử lý tệp và chạy
    gdb target_application
    348

gdb target_application
39

Nhập qua Tệp Với
gdb target_application
348

Đối với

gdb target_application
037 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_application
348 nằm trong tệp
gdb target_application
356

Mục đích của

gdb target_application
348 tương tự như
gdb target_application
095 được sử dụng cho đầu vào
gdb target_application
035. CPython sẽ tải xử lý tệp vào
gdb target_application
360. 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_application
361 được sử dụng bởi
gdb target_application
035

gdb target_application
60

Giống hệt với

gdb target_application
095, sau khi
gdb target_application
348 đã tạo một mô-đun Python từ tệp, nó sẽ gửi mô-đun đó tới
gdb target_application
365 để được thực thi

gdb target_application
365 được tìm thấy trong
gdb target_application
300 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_application
821

gdb target_application
61

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_application
369 là một chức năng bao bọc đơn giản gọi
gdb target_application
370 trong tệp
gdb target_application
371. Hàm
gdb target_application
370 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_application
343 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_application
821. Nếu đường dẫn tệp kết thúc bằng
gdb target_application
821 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_application
821 chứa một đối tượng mã được ghi vào đĩa

Hàm

gdb target_application
346 bên trong
gdb target_application
300 sau đó sắp xếp đối tượng mã từ tệp
gdb target_application
821 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_application
62

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_application
369, gọi
gdb target_application
382 để 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_application
360

Gắn bó với

gdb target_application
300, hàm
gdb target_application
360 sẽ xử lý tệp, cờ trình biên dịch và phiên bản
gdb target_application
890 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_application
387

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_application
388

gdb target_application
63

Đối với

gdb target_application
387, chúng tôi chuyển sang
gdb target_application
390 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

  1. Khởi tạo trạng thái tokenizer
    gdb target_application
    391 bằng cách sử dụng
    gdb target_application
    392 trong
    gdb target_application
    393
  2. 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ụng
    gdb target_application
    395 trong
    gdb target_application
    390

gdb target_application
64

gdb target_application
391 [được định nghĩa trong
gdb target_application
398] 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_application
395 để phát triển cây cú pháp cụ thể

Bên trong

gdb target_application
395, nó sẽ sử dụng cấu trúc
gdb target_application
391 và thực hiện lệnh gọi tới
gdb target_application
602 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_application
602, được định nghĩa trong
gdb target_application
393 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_application
602 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_application
65

Trong trường hợp này,

gdb target_application
606 là mã thông báo, với giá trị được xác định trong
gdb target_application
607. Tất cả các mã thông báo là các giá trị
gdb target_application
608 không đổi và tệp
gdb target_application
607 đã được tạo trước đó khi chúng tôi chạy
gdb target_application
855

Loại

gdb target_application
394 được trả về bởi
gdb target_application
387 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_application
66

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_application
613, 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_application
614, 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_application
855, được lưu trữ trong
gdb target_application
607

>>>

gdb target_application
67

Để dễ hiểu hơn, bạn có thể lấy tất cả các số trong mô-đun

gdb target_application
617 và
gdb target_application
618, đặt chúng vào từ điển và thay thế đệ quy các giá trị trong đầu ra của
gdb target_application
619 bằng tên

gdb target_application
68

Bạn có thể chạy

gdb target_application
620 với một biểu thức đơn giản, chẳng hạn như
gdb target_application
621 để xem cách biểu diễn này dưới dạng cây phân tích cú pháp

>>>

gdb target_application
69

Ở đầ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áo

Câ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_application
624 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_application
889 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_application
889

gdb target_application
20

Sau đó, mở REPL bằng cách chạy

gdb target_application
757 tại dòng lệnh không có đối số

>>>

gdb target_application
21

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_application
628. 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_application
629 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_application
624 và tất cả đều kế thừa từ
gdb target_application
631

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_application
632

Nó có hai thuộc tính

  1. 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én
  2. gdb target_application
    634 là giá trị cần gán, trong trường hợp này là câu lệnh
    gdb target_application
    635,
    gdb target_application
    621

Nếu bạn nhấp vào câu lệnh

gdb target_application
635, 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út
    gdb target_application
    640 [
    gdb target_application
    831] để bổ sung
  • gdb 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_application
613 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_application
388. Đế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_application
645

Sau đó nhảy vào

gdb target_application
388 bên trong
gdb target_application
613, bạn có thể thấy nó nhận được cây
gdb target_application
645, tên tệp, cờ trình biên dịch và
gdb target_application
890

Kiểu trả về từ hàm này là

gdb target_application
650, được xác định trong
gdb target_application
651.
gdb target_application
650 là cấu trúc vùng chứa cho một trong 5 loại mô-đun trong Python

  1. gdb target_application
    653
  2. gdb target_application
    654
  3. gdb target_application
    655
  4. gdb target_application
    656
  5. gdb target_application
    657

Trong

gdb target_application
651, bạn có thể thấy rằng loại
gdb target_application
655 yêu cầu trường
gdb target_application
660, đây là loại
gdb target_application
661. Loại
gdb target_application
661 cũng được định nghĩa trong
gdb target_application
651

gdb target_application
22

Các loại AST đều được liệt kê trong

gdb target_application
664. 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_application
624

Các thông số và tên trong

gdb target_application
651 tương quan trực tiếp với những thông số được chỉ định trong
gdb target_application
664

gdb target_application
23

Tệp tiêu đề C và các cấu trúc ở đó để chương trình

gdb target_application
613 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_application
388 bạn có thể thấy rằng nó thực chất là một câu lệnh
gdb target_application
670 xung quanh kết quả từ
gdb target_application
671.
gdb target_application
672 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_application
388, 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_application
653,
gdb target_application
654,
gdb target_application
655,
gdb target_application
656

Kết quả của

gdb target_application
672 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_application
679, kết quả phải là một
gdb target_application
653. 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_application
681 và tạo các nút câu lệnh nằm trong
gdb target_application
682. 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_application
653 sau đó được trả về với
gdb target_application
890

Đối với

gdb target_application
685, kết quả phải là một
gdb target_application
655. Kết quả từ
gdb target_application
687, là con đầu tiên của
gdb target_application
681 được truyền cho
gdb target_application
689, trả về loại
gdb target_application
661.
gdb target_application
661 này được gửi đến
gdb target_application
692 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_application
24

Bên trong hàm

gdb target_application
682, có một câu lệnh
gdb target_application
670 khác cho từng loại câu lệnh có thể có [
gdb target_application
695,
gdb target_application
696, 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_application
697 là 2 mũ 4. Hàm này bắt đầu bằng cách lấy
gdb target_application
698, là số
gdb target_application
699 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_application
200] và trả về một
gdb target_application
635 [phép toán nhị phân] với toán tử là
gdb target_application
202 [lũy thừa], bàn tay trái của
gdb target_application
203 [2] và bàn tay phải

gdb target_application
25

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_application
889

>>>

gdb target_application
26

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_application
206 tương ứng để tạo ra nó. Các đối số được xác định trong
gdb target_application
664 và được hiển thị thông qua mô-đun
gdb target_application
624 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_application
209 tương ứng trong một lần duyệt theo chiều sâu

Loạ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

  1. 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
  2. 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_application
348 trong
gdb target_application
300. Bên trong chức năng này, chúng tôi đã chuyển đổi điều khiển
gdb target_application
212 thành một
gdb target_application
304, loại
gdb target_application
650. Nhiệm vụ này đã được hoàn thành bởi
gdb target_application
360, lần lượt gọi
gdb target_application
216,
gdb target_application
217 và sau đó là AST

gdb target_application
27

Mô-đun kết quả từ cuộc gọi đến được gửi tới

gdb target_application
365 vẫn trong
gdb target_application
300. Đây là một chức năng nhỏ nhận
gdb target_application
220 từ
gdb target_application
221 và gửi nó tới
gdb target_application
369. Bạn sẽ giải quyết
gdb target_application
369 trong phần tiếp theo

gdb target_application
28

Hàm

gdb target_application
221 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_application
890, 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_application
226 được định nghĩa trong
gdb target_application
227 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_application
890

gdb target_application
29

Bên trong

gdb target_application
221, có 11 bước chính diễn ra

  1. 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
  2. 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
  3. Đặ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
  4. Đặ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
  5. 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
  6. 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
  7. Kích hoạt bất kỳ tính năng
    gdb target_application
    232 nào trong trình biên dịch
  8. Đặt mức tối ưu hóa thành đối số được cung cấp hoặc mặc định
  9. Xây dựng bảng ký hiệu từ đối tượng mô-đun
  10. 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ã
  11. Giải phóng mọi bộ nhớ được cấp phát bởi trình biên dịch

gdb target_application
30

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

  1. 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
  2. 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_application
232 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_application
237

gdb target_application
31

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_application
232 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_application
232 thực hiện

Một ví dụ về cờ trình biên dịch sẽ là cờ

gdb target_application
240 để tối ưu hóa việc sử dụng các câu lệnh
gdb target_application
758. Cờ này vô hiệu hóa bất kỳ câu lệnh
gdb target_application
758 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_application
243

Bảng biểu tượng

Trong

gdb target_application
221 có một tham chiếu đến một
gdb target_application
245 và một cuộc gọi đến
gdb target_application
246 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_application
245 trong
gdb target_application
248 đượ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_application
249 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_application
32

Một số API bảng biểu tượng được hiển thị thông qua mô-đun

gdb target_application
245 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_application
251

Bạn có thể cung cấp một chuỗi có biểu thức Python và

gdb target_application
252 của
gdb target_application
253 hoặc một mô-đun, hàm hoặc lớp và
gdb target_application
254 của
gdb target_application
255 để 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_application
33

Mã C phía sau tất cả nằm trong

gdb target_application
256 và giao diện chính là hàm
gdb target_application
246

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_application
246 chuyển đổi giữa các loại có thể có của
gdb target_application
650 [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_application
650 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_application
34

Vì vậy, đối với một mô-đun,

gdb target_application
246 sẽ lặp qua từng câu lệnh trong mô-đun và gọi
gdb target_application
262.
gdb target_application
262 là một câu lệnh
gdb target_application
670 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_application
664]

Đố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

  1. Nếu độ sâu đệ quy vượt quá giới hạn, hãy tăng lỗi độ sâu đệ quy
  2. Tên của hàm sẽ được thêm làm biến cục bộ
  3. Các giá trị mặc định cho các đối số tuần tự sẽ được giải quyết
  4. Các giá trị mặc định cho các đối số từ khóa sẽ được giải quyết
  5. Mọi chú thích cho các đối số hoặc kiểu trả về đều được giải quyết
  6. Bất kỳ chức năng trang trí được giải quyết
  7. Khối mã chứa nội dung của hàm được truy cập trong
    gdb target_application
    266
  8. Các đối số được truy cập
  9. 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_application
35

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_application
221 đã 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_application
268. Nó trả về một phiên bản
gdb target_application
269

>>>

gdb target_application
36

Tương tự như với hàm

gdb target_application
270, một biểu thức đơn giản phải có chế độ là
gdb target_application
271 và một mô-đun, hàm hoặc lớp phải có chế độ là
gdb target_application
272

Mã được biên dịch có thể được tìm thấy trong thuộc tính

gdb target_application
273 của đối tượng mã

>>>

gdb target_application
37

Ngoài ra còn có một mô-đun

gdb target_application
274 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_application
275

Nếu bạn nhập

gdb target_application
274 và cung cấp cho hàm
gdb target_application
277 thuộc tính
gdb target_application
273 của đối tượng mã, nó sẽ tách nó ra và in hướng dẫn trên REPL

>>>

gdb target_application
38

gdb target_application
279,
gdb target_application
280,
gdb target_application
281 và
gdb target_application
282 đề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_application
283, 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_application
889. Đ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_application
39

Nếu bây giờ chúng ta chuyển sang

gdb target_application
285, 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_application
304 là một
gdb target_application
653. Mô-đun được biên dịch sang trạng thái trình biên dịch và sau đó
gdb target_application
288 được chạy để tạo một
gdb target_application
220

Đối tượng mã mới được trả lại cho

gdb target_application
221 và được gửi đi để thực thi

gdb target_application
50

Hàm

gdb target_application
291 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_application
245

gdb target_application
51

Loại câu lệnh được xác định thông qua lệnh gọi hàm

gdb target_application
293, 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_application
294 gọi một hàm trong
gdb target_application
227 cho từng loại câu lệnh

gdb target_application
52

Đối với một

gdb target_application
296 [thể loại cho một câu lệnh], trình biên dịch sau đó sẽ thả vào
gdb target_application
297 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_application
664

gdb target_application
53

Ví dụ, hãy tập trung vào câu lệnh

gdb target_application
299, trong Python là

gdb target_application
54

Nếu câu lệnh là loại ________ 5299, nó sẽ gọi ________ 6301. Có một hàm

gdb target_application
302 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_application
303 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_application
304 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_application
227 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_application
55

Vì vậy, một khối khung [loại

gdb target_application
306], 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ụng
    gdb 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_application
56

Câu lệnh

gdb target_application
299 ở đâ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_application
299 với cú pháp
gdb target_application
317

  1. 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
  2. Tạo một khối mã mới có tên là
    gdb target_application
    320
  3. Tạo một khối mã mới có tên là
    gdb target_application
    321
  4. Đẩ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ối
    gdb target_application
    318 và khối khối đầu ra là
    gdb target_application
    321
  5. 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
  6. Thêm hoạt động
    gdb target_application
    325 vào trạng thái trình biên dịch
  7. Chuyển sang khối
    gdb target_application
    318
  8. Gọi
    gdb target_application
    327 gọi
    gdb target_application
    328 để thêm hoạt động
    gdb target_application
    329 với đối số của khối
    gdb target_application
    320
  9. 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ối
    gdb target_application
    318
  10. Truy cập từng câu lệnh trong phần thân của vòng lặp for
  11. Gọi
    gdb target_application
    333 gọi
    gdb target_application
    328 để thêm hoạt động
    gdb 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
  12. Di chuyển đến khối
    gdb target_application
    320
  13. Đưa khối khung
    gdb target_application
    322 ra khỏi ngăn xếp
  14. 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
  15. Sử dụng khối
    gdb target_application
    321

Nhắc lại cấu trúc

gdb target_application
306. 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_application
57

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_application
333 và
gdb target_application
327 ở đâ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_application
343 và
gdb target_application
333 gọi
gdb target_application
345 và đặt đối số
gdb target_application
346 thành 0 và 1 tương ứng

Có một số macro khác, chẳng hạn như

gdb target_application
347 gọi
gdb target_application
348 để thêm một thao tác với đối số số nguyên hoặc
gdb target_application
349 gọi
gdb target_application
350 để thêm một thao tác với đối số
gdb target_application
001

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_application
227

gdb target_application
58

Hàm

gdb target_application
288 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ạo
    gdb target_application
    220

gdb target_application
59

Tìm kiếm theo chiều sâu được thực hiện bởi hàm

gdb target_application
357 trong
gdb target_application
227, theo sau các con trỏ
gdb target_application
311 trong mỗi khối, đánh dấu chúng là đã nhìn thấy bằng cách chuyển đổi
gdb target_application
363 và sau đó thêm chúng vào danh sách trình biên dịch mã
gdb target_application
364 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_application
357 cho bước nhảy đó

gdb target_application
60

Tạo đối tượng mã

Nhiệm vụ của

gdb target_application
358 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_application
220 bằng cách gọi
gdb target_application
368

Tên biến, hằng được đặt làm thuộc tính cho đối tượng mã

gdb target_application
61

Bạn cũng có thể nhận thấy rằng mã byte được gửi tới

gdb target_application
369 trước khi nó được gửi tới
gdb target_application
370. 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_application
371

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_application
62

Nó tối ưu hóa điều đó để

gdb target_application
63

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_application
64

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_application
273

Loại bỏ các quảng cáo

Chấp hành

Trong

gdb target_application
300, chúng tôi đã chia tay ngay trước cuộc gọi tới
gdb target_application
369

Cuộc gọi này nhận một đối tượng mã, được tìm nạp từ tệp

gdb target_application
821 đã đượ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_application
369 sẽ vượt qua toàn cầu, địa phương,
gdb target_application
890 và biên dịch
gdb target_application
220 thành
gdb target_application
370 trong
gdb target_application
382

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_application
370 là API công khai để đánh giá một đối tượng mã. Logic để đánh giá được phân chia giữa
gdb target_application
382 và
gdb target_application
383, cả hai đều nằm trong
gdb target_application
024

API công khai

gdb target_application
370 sẽ xây dựng khung thực thi từ đầu ngăn xếp bằng cách gọi
gdb target_application
382

Việc xây dựng khung thực thi đầu tiên có nhiều bước

  1. Đối số từ khóa và vị trí được giải quyết
  2. 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
  3. Các đối số được thêm dưới dạng biến cục bộ vào phạm vi
  4. 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_application
389 và có nhiều tài liệu tham khảo xuyên suốt
gdb target_application
024

Đâ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_application
370 và do đó
gdb target_application
382 có các đối số cho

  • gdb target_application
    393. một
    gdb target_application
    220
  • gdb target_application
    395. một
    gdb target_application
    396 với tên biến là khóa và giá trị của chúng
  • gdb target_application
    397. một
    gdb 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ột
    gdb 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óa
  • gdb 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úng
  • gdb 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ài
  • gdb target_application
    507. một từ điển với các giá trị mặc định cho các đối số từ khóa
  • gdb target_application
    508. một bộ có chuỗi để hợp nhất vào trường đối tượng mã
    gdb target_application
    509
  • gdb target_application
    510. tên cho câu lệnh đánh giá này dưới dạng một chuỗi
  • gdb 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_application
65

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_application
388 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_application
503 được đặt làm biến, như trong ví dụ này

gdb target_application
66

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_application
67

Biến

gdb target_application
514 sẽ tham chiếu đến một
gdb target_application
515 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_application
68

Ở cuối vòng lặp, bạn sẽ thấy một lệnh gọi tới

gdb target_application
516 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_application
69

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_application
388, một đối số chức năng được thêm vào trước bằng một số
gdb target_application
830 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_application
387 được đặt làm biến cục bộ

gdb target_application
700

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_application
514 đượ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_application
203 không phải là vị trí hoặc được đặt tên, vì vậy nó được thêm vào
gdb target_application
523

>>>

gdb target_application
701

Đố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_application
524 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_application
702

Tất cả các đối số ở bên trái của

gdb target_application
524 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_application
703

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_application
526

>>>

gdb target_application
704

Độ 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_application
527. Nếu ký hiệu
gdb target_application
524 được sử dụng trên đối số thứ 3, giá trị của
gdb target_application
527 sẽ là
gdb target_application
699.
gdb target_application
531 được gọi cho mỗi đối số còn lại để thêm nó vào từ điển
gdb target_application
397, 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_application
705

Ở cuối vòng lặp, bạn sẽ thấy lệnh gọi tới

gdb target_application
516 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_application
706

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_application
387 nếu bộ dữ liệu này không tồn tại, sẽ xảy ra lỗi

gdb target_application
707

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_application
388 nếu từ điển này không tồn tại, sẽ xảy ra lỗi

gdb target_application
708

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_application
709

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_application
710

Cuối cùng,

gdb target_application
536 được gọi với khung mới

gdb target_application
711

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_application
382. 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_application
536 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_application
539. Đánh giá khung có thể cắm được trong Python 3. 7 với PEP 523

gdb target_application
383 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_application
383. 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_application
024, 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_application
543 trên Linux và macOS

gdb target_application
712

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_application
544 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_application
713

Đ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_application
274

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_application
001 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_application
547, trong đó
gdb target_application
548 là một con trỏ tới một
gdb target_application
001

Ví dụ: nếu bạn đã tạo một

gdb target_application
550 với giá trị 10 và đẩy nó vào ngăn xếp giá trị

gdb target_application
714

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_application
551 để lấy giá trị cao nhất từ ​​ngăn xếp

gdb target_application
715

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_application
716

Chúng sẽ kết thúc theo thứ tự mà chúng được thêm vào, vì vậy

gdb target_application
548 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_application
553 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_application
717

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_application
556 hoặc bằng cách sử dụng opcode
gdb target_application
557

gdb target_application
718

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_application
558 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_application
559 bên trong
gdb target_application
227. 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_application
005 có sẵn trên đối tượng danh sách

gdb target_application
719

Trong đó

gdb target_application
562 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_application
563, để tải đối tượng
gdb target_application
562 lên đầu ngăn xếp giá trị từ danh sách
gdb target_application
397 trong khung và
gdb target_application
566 để thêm đối tượng

Lần đầu tiên khám phá

gdb target_application
563, có 5 bước

  1. 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ữ trong
    gdb target_application
    570, là bản sao của thuộc tính PyFrame
    gdb target_application
    571. Đối số hoạt động là một số, trỏ đến chỉ mục trong con trỏ mảng
    gdb 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ến

  2. Nế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

  3. 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 1

  4. Con trỏ tới

    gdb target_application
    562 được đẩy lên đầu ngăn xếp giá trị

  5. 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ột
    gdb target_application
    577 được gọi tới
    gdb target_application
    578, quay trở lại đầu vòng lặp cho lệnh tiếp theo

gdb target_application
720

Bây giờ con trỏ tới

gdb target_application
562 ở trên cùng của ngăn xếp giá trị. Lệnh tiếp theo
gdb target_application
566 đượ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_application
566 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_application
721

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_application
584

Sau đó, danh sách API C cho Python được gọi cho

gdb target_application
585 và
gdb target_application
555. Mã cho điều này nằm bên trong
gdb target_application
587, mà chúng ta sẽ xem xét trong chương tiếp theo

Một cuộc gọi đến

gdb target_application
588 được thực hiện, dự đoán rằng hoạt động tiếp theo sẽ là
gdb target_application
335. Macro
gdb target_application
588 có các câu lệnh
gdb target_application
577 do trình biên dịch tạo cho mỗi câu lệnh
gdb target_application
592 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_application
722

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_application
593 thường được theo sau bởi
gdb target_application
594 hoặc
gdb target_application
595

“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

  1. 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
  2. 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_application
596,
gdb target_application
597, 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_application
598 đượ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_application
723

Gọi cái này trên dòng lệnh sẽ cung cấp cho bạn

gdb target_application
724

Trong

gdb target_application
599, hàm
gdb target_application
600 được sử dụng để in dấu vết ngược lại

gdb target_application
725

Ở đâ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_application
601 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_application
600 hoặc
gdb target_application
603 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_application
598 được đưa lên đầu

gdb target_application
601 là API Python để lấy thuộc tính
gdb target_application
606 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_application
607

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_application
726

Hoặc, bạn có thể sử dụng dấu ngoặc vuông

gdb target_application
727

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_application
607, 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_application
607. 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_application
322, cấu trúc C-API cho một
gdb target_application
607

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_application
001 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_application
325, như hàm
gdb target_application
614, mà hàm
gdb target_application
615 tích hợp sẵn. Bạn cũng sẽ tìm thấy
gdb target_application
616 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_application
728

Mã này được triển khai trong

gdb target_application
617, bên trong
gdb target_application
325. Loại đối tượng mục tiêu,
gdb target_application
555 sẽ được suy ra thông qua lệnh gọi tới
gdb target_application
620 và nếu trường
gdb target_application
621 được đặt, thì con trỏ hàm được gọi. Nếu trường
gdb target_application
621 không được đặt, tôi. e. đối tượng không khai báo phương thức
gdb target_application
623 tùy chỉnh, thì hành vi mặc định được chạy, đó là trả về
gdb target_application
624 với tên loại và ID

gdb target_application
729

Trường ob_type cho một

gdb target_application
322 nhất định sẽ trỏ đến cấu trúc dữ liệu
gdb target_application
626, được định nghĩa trong
gdb target_application
627. 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_application
621 làm ví dụ

gdb target_application
730

Trong đó

gdb target_application
629 là một
gdb target_application
630 cho
gdb target_application
631, một hàm lấy 1 con trỏ tới
gdb target_application
001 [
gdb target_application
633]

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_application
731

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_application
732

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_application
325, việc triển khai cơ sở của loại
gdb target_application
607 đượ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ứ

  1. 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
  2. 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_application
626 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ợp
  • gdb target_application
    638 cho loại
    gdb target_application
    639
  • gdb target_application
    640 cho loại
    gdb target_application
    641
  • gdb target_application
    642 cho loại
    gdb target_application
    093
  • gdb target_application
    644 cho loại
    gdb target_application
    645
  • gdb target_application
    646 cho loại
    gdb target_application
    647 trừu tượng, được sử dụng trong lập trình meta
  • gdb target_application
    648 được sử dụng cho loại đối tượng
    gdb target_application
    649 tích hợp
  • gdb target_application
    650 cho một loại số phức tạp
  • gdb target_application
    651 cho một trình vòng lặp
  • gdb target_application
    587 cho loại
    gdb target_application
    585
  • gdb target_application
    654 cho loại số
    gdb target_application
    655
  • gdb target_application
    656 cho loại bộ nhớ cơ sở
  • gdb target_application
    657 cho loại phương thức lớp
  • gdb target_application
    658 cho loại mô-đun
  • gdb target_application
    659 cho một loại không gian tên
  • gdb target_application
    660 cho một loại từ điển được đặt hàng
  • gdb target_application
    661 cho bộ tạo phạm vi
  • gdb target_application
    662 cho loại
    gdb target_application
    663
  • gdb target_application
    664 cho loại tham chiếu lát cắt
  • gdb target_application
    665 cho loại
    gdb target_application
    666
  • gdb target_application
    667 cho loại
    gdb target_application
    668
  • gdb target_application
    669 cho loại
    gdb target_application
    670
  • gdb target_application
    087 cho loại
    gdb target_application
    090
  • gdb target_application
    673 cho một đối tượng
    gdb target_application
    674

Chúng ta sẽ đi sâu vào 3 loại này

  1. Booleans
  2. số nguyên
  3. 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_application
639 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_application
655 và có các hằng số được xác định trước,
gdb target_application
677 và
gdb target_application
678. 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_application
638, bạn có thể thấy hàm trợ giúp để tạo một phiên bản
gdb target_application
639 từ một số

gdb target_application
733

Hàm này sử dụng đánh giá C của một loại số để gán

gdb target_application
677 hoặc
gdb target_application
678 cho một kết quả và tăng bộ đếm tham chiếu

Các hàm số cho

gdb target_application
683,
gdb target_application
684 và
gdb target_application
685 đượ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_application
683 cho giá trị
gdb target_application
639 sẽ kiểm tra xem
gdb target_application
548 và
gdb target_application
553 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_application
677, nếu không, được truyền dưới dạng số và thao tác
gdb target_application
683 được chạy trên hai số

gdb target_application
734

Loại

gdb target_application
655 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_application
608 và thay vào đó sử dụng loại
gdb target_application
655 làm loại số nguyên chính. Loại
gdb target_application
655 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_application
655 bao gồm tiêu đề
gdb target_application
001 và danh sách các chữ số. Danh sách các chữ số,
gdb target_application
698 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_application
735

Bộ nhớ được phân bổ cho một

gdb target_application
655 mới đến
gdb target_application
7000. Hàm này có độ dài cố định và đảm bảo rằng nó nhỏ hơn
gdb target_application
7001. Sau đó, nó phân bổ lại bộ nhớ cho
gdb target_application
698 để phù hợp với độ dài

Để chuyển đổi loại C

gdb target_application
655 thành loại Python
gdb target_application
655,
gdb target_application
655 được chuyển đổi thành danh sách các chữ số, bộ nhớ cho Python
gdb target_application
655 được chỉ định, sau đó từng chữ số được đặt. Bởi vì
gdb target_application
655 được khởi tạo với
gdb target_application
698 đã 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_application
736

Để chuyển đổi một dấu phẩy động hai dấu chấm thành một Python

gdb target_application
655,
gdb target_application
7010 sẽ thực hiện phép toán cho bạn

gdb target_application
737

Phần còn lại của các chức năng triển khai trong

gdb target_application
7011 có các tiện ích, chẳng hạn như chuyển đổi chuỗi Unicode thành số với
gdb target_application
7012

Đá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_application
7013 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_application
7013 thay vì
gdb target_application
356. Đối tượng trình tạo được tạo từ câu lệnh
gdb target_application
7013 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_application
738

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_application
7017

>>>

gdb target_application
739

Loại

gdb target_application
7018 được xác định trong
gdb target_application
7019 và có 3 hương vị

  1. đối tượng máy phát điện
  2. đối tượng quy trình
  3. Đố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ột
    gdb 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ọi
  • gdb target_application
    7022 được đặt thành 0 hoặc 1 nếu trình tạo hiện đang chạy
  • gdb target_application
    7023 liên kết với một
    gdb 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ại
  • gdb 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ạo
  • gdb target_application
    7026 là tên của máy phát điện
  • gdb target_application
    7027 là tên đủ điều kiện của trình tạo
  • gdb 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_application
7029 và
gdb target_application
7030 tương ứng

Nếu bạn gọi

gdb target_application
7031 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_application
7032 được nâng lên

>>>

gdb target_application
740

Mỗi khi

gdb target_application
7031 được gọi, đối tượng mã bên trong trường
gdb target_application
7023 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_application
7023 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_application
274 và phân tách mã byte bên trong

>>>

gdb target_application
741

Bất cứ khi nào

gdb target_application
7031 được gọi trên một đối tượng trình tạo, thì
gdb target_application
7038 được gọi với thể hiện của trình tạo, ngay lập tức gọi
gdb target_application
7039 bên trong
gdb target_application
7040

gdb target_application
7039 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_application
382 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_application
7039 đượ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

  1. Trạng thái luồng hiện tại được tìm nạp

  2. Đối tượng khung từ đối tượng trình tạo được tìm nạp

  3. Nếu trình tạo đang chạy khi

    gdb target_application
    7031 được gọi, hãy tăng một
    gdb target_application
    7045

  4. Nế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
  5. 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 ra

  6. Khá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

  7. 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ạo

  8. Trình tạo được đánh dấu là đang chạy

  9. 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

  10. 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

  11. 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ề

  12. 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

  13. Trình tạo được đánh dấu là không chạy

  14. 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ột
      gdb 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ột
      gdb target_application
      7046, vì điều này không được phép
  15. Cuối cùng, kết quả được trả lại cho người gọi của

    gdb target_application
    7031

gdb target_application
742

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_application
382. Hàm này kiểm tra các cờ
gdb target_application
7061,
gdb target_application
7062 và
gdb target_application
7063 trên đối tượng mã

Khi một coroutine mới được tạo bằng

gdb target_application
7064, một trình tạo không đồng bộ mới được tạo bằng
gdb target_application
7065 hoặc một trình tạo bằng
gdb target_application
7066. 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_application
743

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_application
7013 hoặc
gdb target_application
7068 hoặc nhìn thấy trình trang trí
gdb target_application
7069

gdb target_application
7066 sẽ gọi
gdb target_application
7071 với khung được tạo và sau đó tạo
gdb target_application
7018 với các giá trị
gdb target_application
7073 và đối tượng mã được biên dịch

gdb target_application
744

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_application
7013 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_application
7075, một thư viện cho các mảng số. Loại
gdb target_application
7076 đượ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_application
7077 và mô-đun
gdb target_application
7078. 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

  1. Những thứ được viết bằng Python thuần túy cung cấp tiện ích
  2. 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_application
7079 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_application
7080

Một mô-đun dễ xem sẽ là mô-đun

gdb target_application
7081. 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_application
7081 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_application
7083 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_application
7084 các mô-đun mà không phải lo lắng về vị trí của chúng

Ví dụ

>>>

gdb target_application
745

Chúng ta có thể thấy mã nguồn của

gdb target_application
7085 bên trong
gdb target_application
7086

gdb target_application
746

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_application
7079 cho thành phần Python và
gdb target_application
7088 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_application
7078, có trong
gdb target_application
7090 và mô-đun
gdb target_application
7091, có trong
gdb target_application
7092

Python sẽ

gdb target_application
7093 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_application
7094,
gdb target_application
7095,
gdb target_application
7096, v.v. được tìm thấy trong
gdb target_application
7092

Bởi vì mô-đun

gdb target_application
7078 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_application
813. 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_application
7094 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_application
7101?

  1. Đối số
    gdb target_application
    7102 đã được trình biên dịch chuyển đổi từ hằng chuỗi thành
    gdb target_application
    7103
  2. gdb target_application
    7104 được thực thi với 1 đối số và NULL
    gdb target_application
    502
  3. Biến
    gdb target_application
    7106 được đặt thành
    gdb target_application
    7107, tay cầm
    gdb target_application
    7108 của hệ thống
  4. Mỗi đối số được gửi đến
    gdb target_application
    7106
  5. Ngắt dòng,
    gdb target_application
    7110 được gửi đến
    gdb target_application
    7106

gdb target_application
747

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_application
7112 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_application
7113, 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_application
7114

gdb target_application
748

Sau này trong tệp,

gdb target_application
7115 được định nghĩa là trình bao bọc cho
gdb target_application
7116

gdb target_application
749

gdb target_application
7116 đượ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_application
7118 và hệ thống Unix sẽ gọi
gdb target_application
7119

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_application
7120 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_application
7083 và chạy
gdb target_application
7122, trong đó
gdb target_application
7123 có nghĩa là sử dụng 2 CPU

Trên Windows, sử dụng tập lệnh

gdb target_application
7124 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_application
750

Trên Linux

gdb target_application
751

Trên macOS

gdb target_application
752

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_application
7125

gdb target_application
753

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_application
754

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_application
056

gdb target_application
755

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_application
7127, lệnh này sẽ không tạo liên kết tượng trưng cho
gdb target_application
7128 và cài đặt phiên bản độc lập

gdb target_application
756

Đối với Windows, bạn phải thay đổi cấu hình bản dựng từ

gdb target_application
7129 thành
gdb target_application
7130, 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ề Anthony

Mỗ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ẻ Email

Bà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

Có thể được sử dụng để xem mã nguồn trong đối tượng Python không?

getsource[] được sử dụng để lấy mã nguồn của các đối tượng Python.

Mã đối tượng Python là gì?

Đối tượng mã là chi tiết cấp thấp của việc triển khai CPython . Mỗi cái đại diện cho một đoạn mã thực thi chưa được liên kết thành một hàm. gõ PyCodeObject. Cấu trúc C của các đối tượng được sử dụng để mô tả các đối tượng mã.

Mã nguồn Python ở đâu?

Nguồn cho python 2. 7 có thể được tìm thấy tại http. //hg. con trăn. org/cpython . Các phiên bản khác của python đã có nguồn được nhập vào Launchpad. Bạn có thể thấy chúng ở đây. Nhấp vào một cái bạn muốn xem và sau đó bạn có thể nhấp vào "Duyệt mã".

Bạn có thể tháo rời mã Python không?

Trong Python, mô-đun dis cho phép tách mã Python thành các lệnh riêng lẻ do trình thông dịch Python [thường là cPython] thực thi cho mỗi dòng . Truyền một mô-đun, chức năng hoặc đoạn mã khác cho dis.

Chủ Đề