Hướng dẫn how do i map bytecodes back to line numbers in python? - làm cách nào để ánh xạ các mã byte trở lại số dòng trong python?

Tác giả: Mark Shannon BDFL-DELEGATE: Pablo Galindo Tình trạng: FinalType: Tiêu chuẩn theo dõi: 15-JUL-2020Python-Version: 3.10Post-History: 17-JUL-2020202020:Mark Shannon BDFL-Delegate:Pablo Galindo Status:FinalType:Standards TrackCreated:15-Jul-2020Python-Version:3.10Post-History:17-Jul-2020
Mục lục
  • trừu tượng
  • Động lực
  • Cơ sở lý luận
  • Sự chỉ rõ
    • Truy tìm
    • Những gì được coi là mã cho mục đích truy tìm
    • Ví dụ trình tự sự kiện
    • Thuộc tính F_Lineno
    • Phương thức CO_LINES () mới của các đối tượng mã
      • Phạm vi chiều rộng bằng không
    • Thuộc tính co_linetable
    • Thuộc tính Co_lnotab
  • Khả năng tương thích ngược
    • Ví dụ về mã mà chuỗi các sự kiện theo dõi sẽ thay đổi
      • Tuyên bố
        "line" 1
        "line" 2
        "line" 4
        
        1 trong một tuyên bố
        "line" 1
        "line" 2
        "line" 4
        
        2.
      • Nhiều câu lệnh
        "line" 1
        "line" 2
        "line" 4
        
        1.
    • C API
    • Không có quá trình gỡ lỗi và trình biên dịch
  • Ý nghĩa hiệu suất
  • Thực hiện tham khảo
  • Bản quyền
  • Người giới thiệu

trừu tượng

Python nên đảm bảo rằng khi truy tìm được bật, các sự kiện theo dõi dòng trực tuyến được tạo ra cho tất cả các dòng mã được thực thi và chỉ cho các dòng mã được thực thi.

Thuộc tính

"line" 1
"line" 2
"line" 4
4 của các đối tượng khung phải luôn luôn chứa số dòng dự kiến. Trong quá trình thực hiện khung, số dòng dự kiến ​​là số dòng mã nguồn hiện đang được thực thi. Sau khi một khung hình hoàn thành, bằng cách trả lại hoặc bằng cách tăng một ngoại lệ, số dòng dự kiến ​​là số dòng của dòng nguồn cuối cùng được thực thi.

Một tác dụng phụ của việc đảm bảo số dòng chính xác, là một số byte sẽ cần được đánh dấu là nhân tạo và không có số dòng có ý nghĩa. Để hỗ trợ các công cụ, một thuộc tính

"line" 1
"line" 2
"line" 4
5 mới sẽ được thêm vào mô tả ánh xạ từ mã byte đến nguồn.

Động lực

Cơ sở lý luận

Sự chỉ rõ

Truy tìm

Cơ sở lý luận

Sự chỉ rõ

Truy tìm

Những gì được coi là mã cho mục đích truy tìm

Ví dụ trình tự sự kiện

Sự chỉ rõ

Truy tìm

Truy tìm

Những gì được coi là mã cho mục đích truy tìm

Ví dụ trình tự sự kiện

Thuộc tính F_Lineno

  • Phương thức CO_LINES () mới của các đối tượng mã
  • Phạm vi chiều rộng bằng không

Thuộc tính co_linetable

Những gì được coi là mã cho mục đích truy tìm

Ví dụ trình tự sự kiện

Thuộc tính F_Lineno

Phương thức CO_LINES () mới của các đối tượng mã

Phạm vi chiều rộng bằng không

  • Thuộc tính co_linetable
  • Thuộc tính Co_lnotab
  • Khả năng tương thích ngược
  • Ví dụ về mã mà chuỗi các sự kiện theo dõi sẽ thay đổi
  • Tuyên bố
    "line" 1
    "line" 2
    "line" 4
    
    1 trong một tuyên bố
    "line" 1
    "line" 2
    "line" 4
    
    2.

Nhiều câu lệnh

"line" 1
"line" 2
"line" 4
1.

Ví dụ trình tự sự kiện

Thuộc tính F_Lineno

Phương thức CO_LINES () mới của các đối tượng mã

Phạm vi chiều rộng bằng không

Phương thức CO_LINES () mới của các đối tượng mã

1.     try:
2.        pass
3.     finally:
4.        pass

Phạm vi chiều rộng bằng không

"line" 1
"line" 2
"line" 4

Phương thức CO_LINES () mới của các đối tượng mã

1.      for (
2.          x) in [1]:
3.          pass
4.      return

Tạo các sự kiện sau:

"line" 2       # evaluate [1]
"line" 1       # for
"line" 2       # store to x
"line" 3       # pass
"line" 1       # for
"line" 4       # return
"return" 1

Thuộc tính F_Lineno

  • Khi một đối tượng khung được tạo, thuộc tính
    "line" 1
    "line" 2
    "line" 4
    
    4 sẽ được đặt thành dòng tại đó hàm hoặc lớp được xác định; Đó là dòng mà từ khóa
    "line" 2       # evaluate [1]
    "line" 1       # for
    "line" 2       # store to x
    "line" 3       # pass
    "line" 1       # for
    "line" 4       # return
    "return" 1
    
    3 hoặc
    "line" 2       # evaluate [1]
    "line" 1       # for
    "line" 2       # store to x
    "line" 3       # pass
    "line" 1       # for
    "line" 4       # return
    "return" 1
    
    4 xuất hiện. Đối với các mô -đun, nó sẽ được đặt thành 0.
  • Thuộc tính
    "line" 1
    "line" 2
    "line" 4
    
    4 sẽ được cập nhật để phù hợp với số dòng sắp được thực thi, ngay cả khi truy tìm bị tắt và không có sự kiện nào được tạo.

Phương thức CO_LINES () mới của các đối tượng mã

Phương thức

1.      for (
2.          x) in [1]:
3.          pass
4.      return
0 sẽ trả về một trình lặp lại mang lại các bộ dữ liệu của các giá trị, mỗi phần biểu thị số dòng của một phạm vi byte. Mỗi tuple sẽ bao gồm ba giá trị:

  • "line" 2       # evaluate [1]
    "line" 1       # for
    "line" 2       # store to x
    "line" 3       # pass
    "line" 1       # for
    "line" 4       # return
    "return" 1
    
    7 - phần bù (bao gồm) của bắt đầu phạm vi mã byte
  • "line" 2       # evaluate [1]
    "line" 1       # for
    "line" 2       # store to x
    "line" 3       # pass
    "line" 1       # for
    "line" 4       # return
    "return" 1
    
    8 - phần bù (độc quyền) của phần cuối của phạm vi mã byte
  • "line" 2       # evaluate [1]
    "line" 1       # for
    "line" 2       # store to x
    "line" 3       # pass
    "line" 1       # for
    "line" 4       # return
    "return" 1
    
    9 - Số dòng hoặc
    0.  def spam(a):
    1.      if a:
    2.          eggs()
    3.      else:
    4.          pass
    
    0 nếu các byte trong phạm vi đã cho không có số dòng.

Trình tự được tạo sẽ có các thuộc tính sau:

  • Phạm vi đầu tiên trong chuỗi có
    "line" 2       # evaluate [1]
    "line" 1       # for
    "line" 2       # store to x
    "line" 3       # pass
    "line" 1       # for
    "line" 4       # return
    "return" 1
    
    7 của
    0.  def spam(a):
    1.      if a:
    2.          eggs()
    3.      else:
    4.          pass
    
    2
  • Phạm vi
    0.  def spam(a):
    1.      if a:
    2.          eggs()
    3.      else:
    4.          pass
    
    3 sẽ không giảm và liên tiếp. Đó là, đối với bất kỳ cặp bộ dữ liệu nào,
    "line" 2       # evaluate [1]
    "line" 1       # for
    "line" 2       # store to x
    "line" 3       # pass
    "line" 1       # for
    "line" 4       # return
    "return" 1
    
    7 của phần thứ hai sẽ bằng với
    "line" 2       # evaluate [1]
    "line" 1       # for
    "line" 2       # store to x
    "line" 3       # pass
    "line" 1       # for
    "line" 4       # return
    "return" 1
    
    8 của lần thứ nhất.
  • Không có phạm vi nào sẽ ngược, đó là
    0.  def spam(a):
    1.      if a:
    2.          eggs()
    3.      else:
    4.          pass
    
    6 cho tất cả các bộ ba.
  • Phạm vi cuối cùng trong chuỗi có
    "line" 2       # evaluate [1]
    "line" 1       # for
    "line" 2       # store to x
    "line" 3       # pass
    "line" 1       # for
    "line" 4       # return
    "return" 1
    
    8 bằng kích thước của mã byte.
  • "line" 2       # evaluate [1]
    "line" 1       # for
    "line" 2       # store to x
    "line" 3       # pass
    "line" 1       # for
    "line" 4       # return
    "return" 1
    
    9 sẽ là một số nguyên dương hoặc
    0.  def spam(a):
    1.      if a:
    2.          eggs()
    3.      else:
    4.          pass
    
    0

Phạm vi chiều rộng bằng không

Phạm vi chiều rộng bằng không, đó là phạm vi được phép

"line" 1
"line" 2
"line" 4
"return" 4
0. Phạm vi chiều rộng bằng không được sử dụng cho các dòng có trong mã nguồn, nhưng đã được loại bỏ bởi trình biên dịch byte.

Thuộc tính co_linetable

Thuộc tính CO_LINETABLE sẽ giữ thông tin số dòng. Định dạng mờ đục, không xác định và có thể được thay đổi mà không cần thông báo trước. Thuộc tính chỉ công khai để hỗ trợ tạo các đối tượng mã mới.

Thuộc tính Co_lnotab

Trong lịch sử, thuộc tính

"line" 1
"line" 2
"line" 4
8 đã giữ một ánh xạ từ phần bù mã byte đến số dòng, nhưng không hỗ trợ bytecodes mà không có số dòng. Đối với khả năng tương thích ngược, đối tượng byte
"line" 1
"line" 2
"line" 4
8 sẽ được tạo một cách uể oải khi cần thiết. Đối với các phạm vi byte mà không có số dòng, số dòng của phạm vi mã byte trước đó sẽ được sử dụng.

Các công cụ phân tích bảng

"line" 1
"line" 2
"line" 4
8 nên chuyển sang sử dụng phương thức
1.      for (
2.          x) in [1]:
3.          pass
4.      return
0 mới ngay khi thực tế.

Khả năng tương thích ngược

Thuộc tính

"line" 1
"line" 2
"line" 4
8 sẽ được dùng hết trong 3.10 và bị loại bỏ trong 3.12.

Bất kỳ công cụ nào phân tích thuộc tính

"line" 1
"line" 2
"line" 4
8 của các đối tượng mã sẽ cần phải chuyển sang sử dụng
1.      for (
2.          x) in [1]:
3.          pass
4.      return
0 trước khi 3.12 được phát hành. Các công cụ sử dụng
"line" 1
"line" 2
"line" 4
6 sẽ không bị ảnh hưởng, ngoại trừ trong trường hợp các sự kiện của dòng dòng họ nhận được chính xác hơn.

Ví dụ về mã mà chuỗi các sự kiện theo dõi sẽ thay đổi

Trong các ví dụ sau, các sự kiện được liệt kê là các cặp tên,

"line" 1
"line" 2
"line" 4
4.

Tuyên bố
"line" 1
"line" 2
"line" 4
1 trong một tuyên bố
"line" 1
"line" 2
"line" 4
2.

0.  def spam(a):
1.      if a:
2.          eggs()
3.      else:
4.          pass

Nếu

"line" 1
"line" 2
"return" 2
2 là
"line" 1
"line" 2
"return" 2
3, thì chuỗi các sự kiện được tạo bởi Python 3.9 là:

"line" 1
"line" 2
"line" 4
"return" 4

Từ 3.10, chuỗi sẽ là:

"line" 1
"line" 2
"return" 2

Nhiều câu lệnh
"line" 1
"line" 2
"line" 4
1.

0.  def bar():
1.      pass
2.      pass
3.      pass

Trình tự các sự kiện được tạo bởi Python 3.9 là:

Từ 3.10, chuỗi sẽ là:

"line" 1
"line" 2
"line" 3
"return" 3

Nhiều câu lệnh "line" 1 "line" 2 "line" 4 1.

Trình tự các sự kiện được tạo bởi Python 3.9 là:

C API

Truy cập vào thuộc tính "line" 1 "line" 2 "line" 4 4 của các đối tượng khung thông qua các hàm A API không thay đổi. "line" 1 "line" 2 "line" 4 4 có thể được đọc bởi "line" 1 "line" 2 "return" 2 7. "line" 1 "line" 2 "line" 4 4 chỉ có thể được đặt thông qua "line" 1 "line" 2 "return" 2 9 và các chức năng tương tự.

Truy cập

"line" 1
"line" 2
"line" 4
4 trực tiếp thông qua cấu trúc dữ liệu cơ bản bị cấm.

Không có quá trình gỡ lỗi và trình biên dịch

typedef struct addressrange {
    int ar_start;
    int ar_end;
    int ar_line;
    struct _opaque opaque;
} PyCodeAddressRange;

void PyLineTable_InitAddressRange(char *linetable, Py_ssize_t length, int firstlineno, PyCodeAddressRange *range);
int PyLineTable_NextAddressRange(PyCodeAddressRange *range);
int PyLineTable_PreviousAddressRange(PyCodeAddressRange *range);

Ngoài các công cụ xử lý, chẳng hạn như PY-SPY [1], không thể sử dụng C-API và phải phân tích chữ số dòng. Mặc dù định dạng bảng số dòng có thể thay đổi mà không cần cảnh báo, nhưng nó sẽ không thay đổi trong quá trình phát hành trừ khi thực sự cần thiết cho sửa lỗi.

Để giảm công việc cần thiết để thực hiện các công cụ này, các chức năng C cấu trúc và tiện ích sau đây được cung cấp. Lưu ý rằng các chức năng này không phải là một phần của C-API, vì vậy sẽ cần được liên kết với bất kỳ mã nào cần sử dụng chúng.

0.  def bar():
1.      pass
2.      pass
3.      pass
1 Khởi tạo cấu trúc
0.  def bar():
1.      pass
2.      pass
3.      pass
2 từ bảng số dòng và số dòng đầu tiên.

0.  def bar():
1.      pass
2.      pass
3.      pass
3 tiến lên phạm vi vào mục tiếp theo, trả lại không khác nếu hợp lệ.

0.  def bar():
1.      pass
2.      pass
3.      pass
4 rút lui phạm vi vào mục trước đó, trả lại không khác nếu hợp lệ.

Ghi chú

Ghi chú

Cấu trúc

0.  def bar():
1.      pass
2.      pass
3.      pass
2 đã thay đổi từ phiên bản gốc của PEP này, nơi các trường bổ sung được xác định, nhưng có khả năng thay đổi.

Ví dụ: mã sau in ra tất cả các phạm vi địa chỉ:

"line" 1
"line" 2
"line" 4
0

Ý nghĩa hiệu suất

Nói chung, không nên có thay đổi trong hiệu suất. Khi truy tìm, các chương trình sẽ chạy nhanh hơn một chút vì định dạng bảng mới có thể được thiết kế với tốc độ tính toán số dòng trong tâm trí. Mã với các chuỗi dài của các câu lệnh

"line" 1
"line" 2
"line" 4
1 có thể sẽ trở nên chậm hơn một chút.

Thực hiện tham khảo

https://github.com/markshannon/cpython/tree/new-linetable-format-version-2

Bản quyền

Tài liệu này được đặt trong phạm vi công cộng hoặc theo giấy phép CC0-1.0-Universal, tùy theo điều kiện nào cho phép hơn.

Người giới thiệu

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

Tháo rời mã Python của bạn, chúng tôi có thể tháo rời mã của chúng tôi bằng mô -đun DIS của Python. Đây là những gì tháo rời một hàm đơn giản trông giống như: chúng tôi đã nhập mô -đun DIS và sau đó gọi phương thức dis () để tháo rời My_very_special_function. Hãy nhớ không bao gồm niềng răng tròn.We can disassemble our code using Python's dis module. This is what disassembling a simple function looks like: We imported the dis module and then called the dis() method to disassemble my_very_special_function . Remember not to include round braces.

Python Bytecode có thể bị phân hủy không?

Bằng cách lấy mã byte Python được phân phối với phiên bản Python đó và phân hủy chúng. Trong số những người bị phân hủy thành công, sau đó chúng ta có thể đảm bảo các chương trình kết quả được chính xác về mặt cú pháp bằng cách chạy trình thông dịch Python cho phiên bản mã byte đó.. Among those that successfully decompile, we can then make sure the resulting programs are syntactically correct by running the Python interpreter for that bytecode version.

Làm cách nào để sử dụng mã byte trong Python?

Có thể thực thi mã byte python từ một tập lệnh ?..
Kiểm tra các tập lệnh Python cho mã độc.....
Tạo mã tự động và bộ đệm nó để sử dụng lại (không nhất thiết phải trên đĩa, có thể sử dụng một cơ sở dữ liệu chẳng hạn) ..
Khả năng gửi mã byte được biên dịch sẵn cho một quy trình, kiểm soát một ứng dụng nhúng python cho ví dụ ..

Mã Byte Python là gì?

Python, giống như nhiều ngôn ngữ được giải thích, thực sự biên dịch mã nguồn cho một tập hợp các hướng dẫn cho một máy ảo và trình thông dịch Python là một triển khai của máy ảo đó.Định dạng trung gian này được gọi là "mã byte."