AST có được tích hợp vào Python không?

Yêu cầu. Tất cả các ví dụ đều tương thích với ít nhất Python v3. 6, ngoại trừ việc sử dụng

>>> code = 'one_plus_two = 1+2 # type: int'
>>> tree = ast.parse[code, type_comments=True]
>>> print[ast.dump[tree, indent=4]]
3 với thuộc tính
>>> code = 'one_plus_two = 1+2 # type: int'
>>> tree = ast.parse[code, type_comments=True]
>>> print[ast.dump[tree, indent=4]]
4 đã được thêm vào trong Python v3. 9

Cây cú pháp trừu tượng [AST] là gì?

Cây cú pháp trừu tượng [AST] là cấu trúc dữ liệu được sử dụng để suy luận về ngữ pháp của ngôn ngữ lập trình trong ngữ cảnh của các hướng dẫn được cung cấp trong mã nguồn

Chẳng hạn, trình biên dịch sử dụng AST khi chuyển đổi mã nguồn thành mã nhị phân

  1. Đưa ra một số mã nguồn văn bản, trước tiên trình biên dịch mã hóa văn bản để xác định các từ khóa, biến, chữ, v.v. của ngôn ngữ lập trình. Mỗi mã thông báo đại diện cho một "nguyên tử" của một hướng dẫn

  2. Sau đó, các mã thông báo được sắp xếp lại thành một AST, một cây trong đó các nút là “nguyên tử” của hướng dẫn và sắp xếp các mối quan hệ giữa các nguyên tử dựa trên ngữ pháp ngôn ngữ lập trình. Chẳng hạn, AST làm rõ sự hiện diện của lệnh gọi hàm, các đối số đầu vào có liên quan, các hướng dẫn soạn thảo hàm, v.v.

  3. Sau đó, trình biên dịch có thể áp dụng nhiều tối ưu hóa cho AST và cuối cùng chuyển đổi nó thành mã nhị phân

Bất chấp vai trò của chúng đối với trình biên dịch, AST vẫn hữu ích cho nhiều trường hợp sử dụng hơn. Hãy thảo luận về điều này chi tiết hơn

Mô-đun
Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
7 Python và cách sử dụng nó

Mô-đun

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
7 trong thư viện chuẩn Python có thể được sử dụng để tạo, truy cập và sửa đổi AST liên quan đến mã nguồn Python. Nó đã được giới thiệu vào năm 1990 và kể từ đó nó đã phát triển cùng với ngữ pháp Python

Ngay cả khi nó là một phần của thư viện tiêu chuẩn trong một thời gian dài, việc sử dụng nó trực tiếp không phổ biến. Thay vào đó, bạn có thể đã sử dụng nó một cách gián tiếp vì các công cụ phổ biến sử dụng nó một cách bí mật

  • kiểm tra mã.

    >>> code = 'one_plus_two = 1+2 # type: int'
    >>> tree = ast.parse[code, type_comments=True]
    >>> print[ast.dump[tree, indent=4]]
    
    7 là một công cụ kiểm tra đột biến được sử dụng để thay đổi mã đang được kiểm tra để mở rộng bộ kiểm tra theo cách tự động. Trong thực tế, đột biến là một sửa đổi nhân tạo của AST được tạo từ mã đang được thử nghiệm. Để xem cách PyBites sử dụng
    >>> code = 'one_plus_two = 1+2 # type: int'
    >>> tree = ast.parse[code, type_comments=True]
    >>> print[ast.dump[tree, indent=4]]
    
    7, hãy xem bài viết này

  • mã số bảo hiểm.

    >>> code = 'one_plus_two = 1+2 # type: int'
    >>> tree = ast.parse[code, type_comments=True]
    >>> print[ast.dump[tree, indent=4]]
    
    9 là một bộ phân tích mã tĩnh nghiên cứu AST để xác định phần mã không được sử dụng

  • lỗ hổng mã.

    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]],
                type_comment='int']],
        type_ignores=[]]
    
    0 sử dụng biểu diễn AST để xác định các lỗ hổng bảo mật

  • tự động hoàn thành mã.

    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]],
                type_comment='int']],
        type_ignores=[]]
    
    1 là một IDE và công cụ tự động hoàn thành trình soạn thảo văn bản dựa trên chức năng của mô-đun
    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    7 để đánh giá các biểu thức một cách an toàn

  • định dạng mã.

    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]],
                type_comment='int']],
        type_ignores=[]]
    
    3 và
    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]],
                type_comment='int']],
        type_ignores=[]]
    
    4 là hai công cụ phổ biến để thực thi định dạng lại mã và cả hai đều sử dụng biểu diễn AST của mã nguồn để áp dụng các quy tắc định dạng của chúng

Sử dụng mô-đun
Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
7 để điều tra các bài tập về PyBites Bite

Vẫn không thuyết phục về sự liên quan của một AST? . hãy xem xét một trường hợp sử dụng thực tế hơn và gần gũi hơn với Nền tảng PyBites

Nền tảng PyBites hiện đang cung cấp hơn 300 bài tập Bite và con số này không ngừng tăng lên. Do mục đích [bán] ẩn của nền tảng là đưa ra một loạt các thử thách bao gồm các mô-đun và chức năng Python khác nhau, việc xác định nội dung của các bài tập đã có sẽ bắt đầu trở nên khó khăn hơn và thay vào đó, nội dung nào còn lại để khám phá

Đây là nơi chúng ta có thể tận dụng mô-đun

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
7. Cụ thể, chúng tôi có thể xử lý mã nguồn của lời giải của các bài tập [do tác giả của các thử thách cung cấp] và khôi phục một số thống kê về nội dung của chúng. Chẳng hạn, các mô-đun phổ biến và các hàm dựng sẵn được sử dụng

Đây là một số kết quả. Để theo dõi, hãy xem sổ ghi chép Jupyter này

Mức độ phổ biến của nội trang

Biểu đồ ở trên hiển thị các lệnh gọi nội trang Python được sắp xếp theo mức độ phổ biến của chúng. Nói cách khác, sử dụng mô-đun

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
7, người ta có thể phát hiện khi một lệnh gọi hàm được thực hiện và liệu nó có liên quan đến mô-đun
Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
9 hay không. Ba màu được sử dụng để phân biệt trực quan giữa các loại ngoại lệ, việc tạo các loại cơ sở [
Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]],
            type_comment='int']],
    type_ignores=[]]
9,
>>> code = 'one_plus_two = 1+2 # type: ignore'
>>> tree = ast.parse[code, type_comments=True]
>>> print[ast.dump[tree, indent=4]]
0,
>>> code = 'one_plus_two = 1+2 # type: ignore'
>>> tree = ast.parse[code, type_comments=True]
>>> print[ast.dump[tree, indent=4]]
1,
>>> code = 'one_plus_two = 1+2 # type: ignore'
>>> tree = ast.parse[code, type_comments=True]
>>> print[ast.dump[tree, indent=4]]
2 và
>>> code = 'one_plus_two = 1+2 # type: ignore'
>>> tree = ast.parse[code, type_comments=True]
>>> print[ast.dump[tree, indent=4]]
3] hoặc các chức năng khác. Biểu đồ là số đếm tần số chuẩn hóa, i. e. , tần suất xuất hiện của từng phần tử được cộng dồn trong tất cả các bài tập và chia cho tổng tất cả các phần tử xuất hiện trong tất cả các bài tập

Một vài quan sát

  • Phân phối có đuôi nặng, với

    >>> code = 'one_plus_two = 1+2 # type: ignore'
    >>> tree = ast.parse[code, type_comments=True]
    >>> print[ast.dump[tree, indent=4]]
    
    4 đại diện cho 13. 4% của tất cả các cuộc gọi dựng sẵn, trong khi
    >>> code = 'one_plus_two = 1+2 # type: ignore'
    >>> tree = ast.parse[code, type_comments=True]
    >>> print[ast.dump[tree, indent=4]]
    
    5 chỉ được sử dụng một lần

  • Tất cả năm loại cơ sở đều được sử dụng, nhưng

    >>> code = 'one_plus_two = 1+2 # type: ignore'
    >>> tree = ast.parse[code, type_comments=True]
    >>> print[ast.dump[tree, indent=4]]
    
    6 chỉ được sử dụng trong 1 thử thách

  • Chỉ có 5 trường hợp ngoại lệ tiêu chuẩn được sử dụng, với

    >>> code = 'one_plus_two = 1+2 # type: ignore'
    >>> tree = ast.parse[code, type_comments=True]
    >>> print[ast.dump[tree, indent=4]]
    
    7 là trường hợp phổ biến nhất

  • Hầu hết các hàm dựng sẵn đều đã được sử dụng trong các bài tập, nhưng khi xem xét các lời gọi lập trình hàm, bạn có thể nhận thấy rằng _____17_______8 xuất hiện trong khi _____17_______9 thì không [thực ra thông lệ phổ biến là thích dùng hơn]

phổ biến mô-đun

Biểu đồ trên hiển thị xếp hạng cho các mô-đun. Để đơn giản, chúng tôi giới hạn chỉ báo cáo về các mô-đun gốc. Nếu các mô-đun con được sử dụng, tần số của chúng được cộng dồn vào tần số của các mô-đun gốc tương ứng

Như trước đây, biểu đồ có nhiều đuôi, một minh chứng rằng các bài tập PyBites Bite cố gắng “bao quát một chút mọi thứ”

Chúng ta có thể quan sát sự hiện diện của các mô-đun không chuẩn, chẳng hạn như

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[
        TypeIgnore[lineno=1, tag='']]]
0 và
Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[
        TypeIgnore[lineno=1, tag='']]]
1, cũng như các mô-đun đặc biệt hơn như
Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[
        TypeIgnore[lineno=1, tag='']]]
2 và
Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[
        TypeIgnore[lineno=1, tag='']]]
3 được tạo ra cho mục đích của chính những thách thức đó

Người ta có thể dễ dàng mở rộng phân tích để hiểu các chức năng được sử dụng trong từng mô-đun/mô-đun con, cũng như đi sâu vào phân tích cụ thể hơn. Điều liên quan cần làm nổi bật là các kết quả được báo cáo ở đây được tạo với khoảng 50 dòng mã Python và sử dụng mô-đun

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
7. Xử lý hơn 300 tệp mã nguồn bằng các công cụ như
Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[
        TypeIgnore[lineno=1, tag='']]]
5,
Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[
        TypeIgnore[lineno=1, tag='']]]
6 hoặc bất kỳ công cụ nào khác sẽ khó hơn đáng kể

Hy vọng rằng các ví dụ này đã cho bạn ý tưởng sơ bộ về những gì bạn có thể đạt được với AST. Bước tiếp theo là hiểu cách tạo cấu trúc dữ liệu như vậy và điều tra thành phần của chúng

Phân tích hướng dẫn bài tập bằng cách sử dụng mô-đun
Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
7

Để bắt đầu làm quen với mô-đun

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
7, hãy xem điều gì sẽ xảy ra khi chúng ta phân tích một lệnh đơn lẻ.
Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[
        TypeIgnore[lineno=1, tag='']]]
9

>>> import ast
>>> code = "one_plus_two = 1+2"
>>> tree = ast.parse[code]
>>> ast.dump[tree, indent=4]

Điều này sẽ xuất ra

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]

Lúc đầu có thể không rõ ràng, nhưng đầu ra được tạo bởi

>>> code = 'one_plus_two = 1+2 # type: int'
>>> tree = ast.parse[code, type_comments=True]
>>> print[ast.dump[tree, indent=4]]
3 thực sự là một cái cây

  • Các từ bắt đầu bằng chữ in hoa là các nút của cây

  • Các thuộc tính của các nút là các cạnh của cây hoặc siêu dữ liệu

Hãy làm lại đầu ra thành sơ đồ với các quy ước sau

  • Một hình chữ nhật cho mỗi nút, đánh dấu đậm loại nút liên quan

  • Thuộc tính nút thu thập siêu dữ liệu được báo cáo bằng màu xanh lam

  • Các thuộc tính nút khác được chú thích với loại của chúng

  • Các nút được kết nối dựa trên thuộc tính của chúng

Với hình dung này trong tay, chúng ta có thể quan sát một vài điều

Gốc của cây là một nút

>>> import ast
>>> code = "one_plus_two = 1+2"
>>> tree = ast.parse[code]

>>> for node in ast.walk[tree]:
        print[node.__class__.__name__]

Module
Assign
Name
BinOp
Store
Constant
Add
Constant

>>> for name, value in ast.iter_fields[tree]:
        print[name, value]

body []
type_ignores []

>>> for node in ast.iter_child_nodes[tree]:
        print[node.__class__.__name__]

Assign
1. Trên thực tế, ngay cả khi ví dụ của chúng tôi là một chương trình dòng đơn, nó vẫn là một mô-đun Python thực sự. Nút chứa hai thuộc tính
>>> import ast
>>> code = "one_plus_two = 1+2"
>>> tree = ast.parse[code]

>>> for node in ast.walk[tree]:
        print[node.__class__.__name__]

Module
Assign
Name
BinOp
Store
Constant
Add
Constant

>>> for name, value in ast.iter_fields[tree]:
        print[name, value]

body []
type_ignores []

>>> for node in ast.iter_child_nodes[tree]:
        print[node.__class__.__name__]

Assign
2 và
>>> import ast
>>> code = "one_plus_two = 1+2"
>>> tree = ast.parse[code]

>>> for node in ast.walk[tree]:
        print[node.__class__.__name__]

Module
Assign
Name
BinOp
Store
Constant
Add
Constant

>>> for name, value in ast.iter_fields[tree]:
        print[name, value]

body []
type_ignores []

>>> for node in ast.iter_child_nodes[tree]:
        print[node.__class__.__name__]

Assign
3. Hãy tạm gác
>>> import ast
>>> code = "one_plus_two = 1+2"
>>> tree = ast.parse[code]

>>> for node in ast.walk[tree]:
        print[node.__class__.__name__]

Module
Assign
Name
BinOp
Store
Constant
Add
Constant

>>> for name, value in ast.iter_fields[tree]:
        print[name, value]

body []
type_ignores []

>>> for node in ast.iter_child_nodes[tree]:
        print[node.__class__.__name__]

Assign
3 sang một bên và tập trung vào
>>> import ast
>>> code = "one_plus_two = 1+2"
>>> tree = ast.parse[code]

>>> for node in ast.walk[tree]:
        print[node.__class__.__name__]

Module
Assign
Name
BinOp
Store
Constant
Add
Constant

>>> for name, value in ast.iter_fields[tree]:
        print[name, value]

body []
type_ignores []

>>> for node in ast.iter_child_nodes[tree]:
        print[node.__class__.__name__]

Assign
2

Vì một mô-đun Python chứa một loạt các hướng dẫn, nên thuộc tính

>>> import ast
>>> code = "one_plus_two = 1+2"
>>> tree = ast.parse[code]

>>> for node in ast.walk[tree]:
        print[node.__class__.__name__]

Module
Assign
Name
BinOp
Store
Constant
Add
Constant

>>> for name, value in ast.iter_fields[tree]:
        print[name, value]

body []
type_ignores []

>>> for node in ast.iter_child_nodes[tree]:
        print[node.__class__.__name__]

Assign
6 là một danh sách các nút, một nút cho mỗi lệnh trong chương trình. Ví dụ của chúng tôi bao gồm một hoạt động chuyển nhượng duy nhất, do đó
>>> import ast
>>> code = "one_plus_two = 1+2"
>>> tree = ast.parse[code]

>>> for node in ast.walk[tree]:
        print[node.__class__.__name__]

Module
Assign
Name
BinOp
Store
Constant
Add
Constant

>>> for name, value in ast.iter_fields[tree]:
        print[name, value]

body []
type_ignores []

>>> for node in ast.iter_child_nodes[tree]:
        print[node.__class__.__name__]

Assign
6 chỉ chứa một nút
>>> import ast
>>> code = "one_plus_two = 1+2"
>>> tree = ast.parse[code]

>>> for node in ast.walk[tree]:
        print[node.__class__.__name__]

Module
Assign
Name
BinOp
Store
Constant
Add
Constant

>>> for name, value in ast.iter_fields[tree]:
        print[name, value]

body []
type_ignores []

>>> for node in ast.iter_child_nodes[tree]:
        print[node.__class__.__name__]

Assign
8

Một thao tác gán có một bên phải chỉ định thao tác sẽ thực hiện và một bên trái chỉ định đích của thao tác. Hai bên được liên kết với các thuộc tính

>>> import ast
>>> code = "one_plus_two = 1+2"
>>> tree = ast.parse[code]

>>> for node in ast.walk[tree]:
        print[node.__class__.__name__]

Module
Assign
Name
BinOp
Store
Constant
Add
Constant

>>> for name, value in ast.iter_fields[tree]:
        print[name, value]

body []
type_ignores []

>>> for node in ast.iter_child_nodes[tree]:
        print[node.__class__.__name__]

Assign
9 và
class BinOpVisitor[ast.NodeVisitor]:

    def visit_BinOp[self, node]:
        print[f"found BinOp at line: {node.lineno}"]
        self.generic_visit[node]
0 của nút
>>> import ast
>>> code = "one_plus_two = 1+2"
>>> tree = ast.parse[code]

>>> for node in ast.walk[tree]:
        print[node.__class__.__name__]

Module
Assign
Name
BinOp
Store
Constant
Add
Constant

>>> for name, value in ast.iter_fields[tree]:
        print[name, value]

body []
type_ignores []

>>> for node in ast.iter_child_nodes[tree]:
        print[node.__class__.__name__]

Assign
8

Xem xét phía bên tay phải, thuộc tính

>>> import ast
>>> code = "one_plus_two = 1+2"
>>> tree = ast.parse[code]

>>> for node in ast.walk[tree]:
        print[node.__class__.__name__]

Module
Assign
Name
BinOp
Store
Constant
Add
Constant

>>> for name, value in ast.iter_fields[tree]:
        print[name, value]

body []
type_ignores []

>>> for node in ast.iter_child_nodes[tree]:
        print[node.__class__.__name__]

Assign
9 là nút
class BinOpVisitor[ast.NodeVisitor]:

    def visit_BinOp[self, node]:
        print[f"found BinOp at line: {node.lineno}"]
        self.generic_visit[node]
3, do lệnh là phép toán nhị phân giữa hai toán hạng, được chỉ định đầy đủ với ba thuộc tính

  • class BinOpVisitor[ast.NodeVisitor]:
    
        def visit_BinOp[self, node]:
            print[f"found BinOp at line: {node.lineno}"]
            self.generic_visit[node]
    
    4 là nút
    class BinOpVisitor[ast.NodeVisitor]:
    
        def visit_BinOp[self, node]:
            print[f"found BinOp at line: {node.lineno}"]
            self.generic_visit[node]
    
    5 do chúng tôi đang thực hiện phép cộng

  • class BinOpVisitor[ast.NodeVisitor]:
    
        def visit_BinOp[self, node]:
            print[f"found BinOp at line: {node.lineno}"]
            self.generic_visit[node]
    
    6 và
    class BinOpVisitor[ast.NodeVisitor]:
    
        def visit_BinOp[self, node]:
            print[f"found BinOp at line: {node.lineno}"]
            self.generic_visit[node]
    
    7 là các toán hạng cộng và bao gồm các nút
    class BinOpVisitor[ast.NodeVisitor]:
    
        def visit_BinOp[self, node]:
            print[f"found BinOp at line: {node.lineno}"]
            self.generic_visit[node]
    
    8, mỗi nút giữ giá trị thô trong thuộc tính
    class BinOpVisitor[ast.NodeVisitor]:
    
        def visit_BinOp[self, node]:
            print[f"found BinOp at line: {node.lineno}"]
            self.generic_visit[node]
    
    9

Xét về phía bên trái, vì Python hỗ trợ nhiều phép gán và giải nén bộ dữ liệu, thuộc tính

class BinOpVisitor[ast.NodeVisitor]:

    def visit_BinOp[self, node]:
        print[f"found BinOp at line: {node.lineno}"]
        self.generic_visit[node]
0 là một danh sách thu thập các đích khác nhau của thao tác. Trong trường hợp của chúng tôi, phép gán dành cho một biến duy nhất, do đó, một nút
>>> vis = BinOpVisitor[]
>>> vis.visit[tree]
1 duy nhất được sử dụng. Đổi lại, nút
>>> vis = BinOpVisitor[]
>>> vis.visit[tree]
1 có 2 thuộc tính

  • >>> vis = BinOpVisitor[]
    >>> vis.visit[tree]
    
    3 lưu tên của biến được sử dụng trong chương trình [
    >>> vis = BinOpVisitor[]
    >>> vis.visit[tree]
    
    4]

  • >>> vis = BinOpVisitor[]
    >>> vis.visit[tree]
    
    5 chỉ định cách sử dụng tham chiếu biến trong chương trình. Đây chỉ có thể là một trong các loại
    >>> vis = BinOpVisitor[]
    >>> vis.visit[tree]
    
    6,
    >>> vis = BinOpVisitor[]
    >>> vis.visit[tree]
    
    7 hoặc
    >>> vis = BinOpVisitor[]
    >>> vis.visit[tree]
    
    8, nhưng chúng luôn là các nút trống

Thuộc tính
>>> code = 'one_plus_two = 1+2 # type: int'
>>> tree = ast.parse[code, type_comments=True]
>>> print[ast.dump[tree, indent=4]]
1 và loại bình luận

Thuộc tính

>>> code = 'one_plus_two = 1+2 # type: int'
>>> tree = ast.parse[code, type_comments=True]
>>> print[ast.dump[tree, indent=4]]
1 trong phần lớn các trường hợp sẽ là một danh sách trống. Đây là lý do tại sao trong bản phác thảo được tô màu xanh lam. Để hiểu tại sao lại như vậy và mục đích thực sự của thuộc tính là gì, chúng ta cần thực hiện một sự lạc đề

Trăn 3. 0 đã giới thiệu các chú thích và vài năm sau, chúng đã được mở rộng thành các gợi ý loại. Nếu bạn không quen thuộc với những khái niệm đó, hãy xem hướng dẫn Real Python này và

Những thay đổi đó không được chuyển trở lại Python 2, mà thay vào đó sử dụng các nhận xét loại dưới dạng chú thích. Để biết thêm thông tin, hãy xem hoặc hướng dẫn Real Python này

Thuộc tính

>>> code = 'one_plus_two = 1+2 # type: int'
>>> tree = ast.parse[code, type_comments=True]
>>> print[ast.dump[tree, indent=4]]
1 đề cập đến một nhận xét loại đặc biệt
import ast

class BinOpVisitor[ast.NodeVisitor]:

    def visit_BinOp[self, node]:
        print[f"found BinOp at line: {node.lineno}"]
        self.generic_visit[node]


code = """
left_op = 1
right_op = 2
sum_two_things = left_op + right_op
other_sum = sum_two_things - 1

print[sum_two_things]
print[other_sum]
"""

tree = ast.parse[code]

print["=== full AST ==="]
print[ast.dump[tree, indent=4]]

print[]
print["=== visit ==="]
vis = BinOpVisitor[]
vis.visit[tree]
2 được sử dụng để chỉ ra trình kiểm tra loại [chẳng hạn như mypy] để loại bỏ lỗi nếu tìm thấy lỗi. Vì những lý do cũ, mô-đun
Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
7 vẫn đang báo cáo về những nhận xét đó, nhưng chỉ khi được yêu cầu làm như vậy

Hãy xem một ví dụ

>>> code = 'one_plus_two = 1+2 # type: int'
>>> tree = ast.parse[code, type_comments=True]
>>> print[ast.dump[tree, indent=4]]

Điều này sẽ xuất ra

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]],
            type_comment='int']],
    type_ignores=[]]

Lưu ý rằng sự khác biệt duy nhất đối với phân tích chi tiết về AST đã thảo luận trước đó là sự hiện diện của thuộc tính

import ast

class BinOpVisitor[ast.NodeVisitor]:

    def visit_BinOp[self, node]:
        print[f"found BinOp at line: {node.lineno}"]
        self.generic_visit[node]


code = """
left_op = 1
right_op = 2
sum_two_things = left_op + right_op
other_sum = sum_two_things - 1

print[sum_two_things]
print[other_sum]
"""

tree = ast.parse[code]

print["=== full AST ==="]
print[ast.dump[tree, indent=4]]

print[]
print["=== visit ==="]
vis = BinOpVisitor[]
vis.visit[tree]
4. Thuộc tính phản ánh siêu dữ liệu được cung cấp bởi nhận xét loại
import ast

class BinOpVisitor[ast.NodeVisitor]:

    def visit_BinOp[self, node]:
        print[f"found BinOp at line: {node.lineno}"]
        self.generic_visit[node]


code = """
left_op = 1
right_op = 2
sum_two_things = left_op + right_op
other_sum = sum_two_things - 1

print[sum_two_things]
print[other_sum]
"""

tree = ast.parse[code]

print["=== full AST ==="]
print[ast.dump[tree, indent=4]]

print[]
print["=== visit ==="]
vis = BinOpVisitor[]
vis.visit[tree]
5 và được thêm vào nút cây AST
>>> import ast
>>> code = "one_plus_two = 1+2"
>>> tree = ast.parse[code]

>>> for node in ast.walk[tree]:
        print[node.__class__.__name__]

Module
Assign
Name
BinOp
Store
Constant
Add
Constant

>>> for name, value in ast.iter_fields[tree]:
        print[name, value]

body []
type_ignores []

>>> for node in ast.iter_child_nodes[tree]:
        print[node.__class__.__name__]

Assign
8 vì chúng tôi đã chỉ định
import ast

class BinOpVisitor[ast.NodeVisitor]:

    def visit_BinOp[self, node]:
        print[f"found BinOp at line: {node.lineno}"]
        self.generic_visit[node]


code = """
left_op = 1
right_op = 2
sum_two_things = left_op + right_op
other_sum = sum_two_things - 1

print[sum_two_things]
print[other_sum]
"""

tree = ast.parse[code]

print["=== full AST ==="]
print[ast.dump[tree, indent=4]]

print[]
print["=== visit ==="]
vis = BinOpVisitor[]
vis.visit[tree]
7 khi kích hoạt phân tích cú pháp

Tuy nhiên,

import ast

class BinOpVisitor[ast.NodeVisitor]:

    def visit_BinOp[self, node]:
        print[f"found BinOp at line: {node.lineno}"]
        self.generic_visit[node]


code = """
left_op = 1
right_op = 2
sum_two_things = left_op + right_op
other_sum = sum_two_things - 1

print[sum_two_things]
print[other_sum]
"""

tree = ast.parse[code]

print["=== full AST ==="]
print[ast.dump[tree, indent=4]]

print[]
print["=== visit ==="]
vis = BinOpVisitor[]
vis.visit[tree]
2 được đối xử khác biệt. Những nhận xét loại đó được lưu trữ vào thuộc tính
>>> code = 'one_plus_two = 1+2 # type: int'
>>> tree = ast.parse[code, type_comments=True]
>>> print[ast.dump[tree, indent=4]]
1 dưới dạng đối tượng
Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
00 thay vì được thu thập dưới dạng siêu dữ liệu trong các nút bên trong của cây

>>> code = 'one_plus_two = 1+2 # type: ignore'
>>> tree = ast.parse[code, type_comments=True]
>>> print[ast.dump[tree, indent=4]]

Điều này sẽ xuất ra

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[
        TypeIgnore[lineno=1, tag='']]]

API mô-đun
Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
7

Mô-đun

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
7 chủ yếu là một tập hợp lớn các lớp, mỗi lớp cho mỗi khía cạnh khác nhau của ngữ pháp Python. Nhìn chung, có khoảng 100 lớp, từ nghĩa đen, đến cấu trúc phức tạp hơn, chẳng hạn như hiểu danh sách

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
03 là lớp cơ sở cho tất cả các lớp khác trong mô-đun và nó định nghĩa các thuộc tính cơ sở sau cho tất cả các nút AST

  • Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    04,
    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    05,
    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    06 và
    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    07 được sử dụng để theo dõi vị trí chính xác của hướng dẫn liên quan trong mã nguồn

  • Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    08 chứa danh sách các tên thuộc tính [bạn có thể nghĩ rằng đó là danh sách các tên “con”]

Khi xử lý một AST, phần khó nhất là hiểu ngữ nghĩa của các nút và thuộc tính. Thực tế có rất nhiều biến thể và ốp góc nên rất dễ bị nhầm lẫn

Một cách hay để bắt đầu làm quen với AST là sử dụng bảng điều khiển tương tác chẳng hạn như

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
09 tương tự như những gì chúng ta đã làm trong các ví dụ trước. Nếu bạn đã quen với IDE, thì cả PyCharm và Visual Studio Code đều cung cấp plugin để trực quan hóa AST [lưu ý rằng PyCharm sử dụng phiên bản AST của chính nó được gọi là Giao diện cấu trúc chương trình – PSI]

Bất kể lựa chọn ưa thích của bạn là gì, tài liệu là nguồn tài nguyên cơ bản cần có trong tầm tay. Tuy nhiên, một vài nhận xét

  • Vì ngôn ngữ Python đang trong quá trình phát triển không ngừng, hãy đảm bảo sử dụng phiên bản mới nhất của tài liệu Python

  • Tài liệu chính thức cũng gợi ý tham khảo Green Tree Snake, tài liệu này thực sự làm rất tốt việc bổ sung cho tài liệu chính thức về những phần mà nếu không thì có vẻ “khô khan” về chi tiết

Bên cạnh các lớp, mô-đun

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
7 định nghĩa cách thực hiện việc thăm cây và cách thực hiện các phép biến đổi

Tham quan một AST

Bạn có thể truy cập AST theo hai cách. sử dụng các chức năng của trình trợ giúp hoặc thông qua một lớp

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
11

Hãy bắt đầu xem xét các chức năng của trình trợ giúp

  • Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    12 truy cập nút đã chỉ định và đệ quy tất cả các phần tử con của nó, nhưng theo thứ tự không được chỉ định

  • Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    13 và
    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    14 tương tự như
    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    15 và
    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    16 của cấu trúc dữ liệu
    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    17, nhưng chỉ áp dụng cho một nút cụ thể và chúng không mang tính đệ quy

Dưới đây là một số ví dụ

>>> import ast
>>> code = "one_plus_two = 1+2"
>>> tree = ast.parse[code]

>>> for node in ast.walk[tree]:
        print[node.__class__.__name__]

Module
Assign
Name
BinOp
Store
Constant
Add
Constant

>>> for name, value in ast.iter_fields[tree]:
        print[name, value]

body []
type_ignores []

>>> for node in ast.iter_child_nodes[tree]:
        print[node.__class__.__name__]

Assign

Thay vào đó, khi sử dụng

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
11, người ta có thể đăng ký các cuộc gọi lại cụ thể để kích hoạt khi truy cập các loại nút cụ thể

class BinOpVisitor[ast.NodeVisitor]:

    def visit_BinOp[self, node]:
        print[f"found BinOp at line: {node.lineno}"]
        self.generic_visit[node]

trong ví dụ này

  • Chúng ta định nghĩa một lớp

    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    19 mở rộng lớp
    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    11

  • Chúng tôi đăng ký một cuộc gọi lại để được kích hoạt khi

    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    21 nút được truy cập. Tên gọi lại luôn là
    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    22 trong đó
    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    23 là một trong những tên loại nút được xác định trước [trong trường hợp của chúng tôi là ____49_______3]

  • Khi cuộc gọi lại được gọi, nó sẽ nhận được tham chiếu của nút được phân tích. Trong ví dụ này, chúng tôi sử dụng thông tin nút để in số dòng của lệnh mà nó liên quan đến

  • Cuối cùng, chúng tôi gọi

    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    25 để tuyên truyền lượt truy cập vào nút con của nút đầu vào

Loại ma thuật đen nào xảy ra đằng sau hiện trường để kích hoạt các cuộc gọi lại? . Hàm

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
11 cũng định nghĩa hàm
Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
27 luôn được gọi trước. nếu loại nút đầu vào khớp với một trong các cuộc gọi lại, thì cuộc gọi lại đó được gọi, nếu không thì
Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
28 được gọi để thăm các nút con. Trong ví dụ của chúng tôi, chúng tôi không ghi đè lên
Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
27, do đó chúng tôi có thể kích hoạt một lượt truy cập vào cây chỉ bằng cách gọi phương thức

>>> vis = BinOpVisitor[]
>>> vis.visit[tree]

Đây là ví dụ hoàn chỉnh

import ast

class BinOpVisitor[ast.NodeVisitor]:

    def visit_BinOp[self, node]:
        print[f"found BinOp at line: {node.lineno}"]
        self.generic_visit[node]


code = """
left_op = 1
right_op = 2
sum_two_things = left_op + right_op
other_sum = sum_two_things - 1

print[sum_two_things]
print[other_sum]
"""

tree = ast.parse[code]

print["=== full AST ==="]
print[ast.dump[tree, indent=4]]

print[]
print["=== visit ==="]
vis = BinOpVisitor[]
vis.visit[tree]

Chạy chương trình ta thu được kết quả như sau

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
0

Sửa đổi một AST

Một

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
30 có thể được sử dụng làm lớp cơ sở cho một máy biến áp, tương tự như logic được sử dụng cho lớp khách truy cập. Lần này, thay vì chỉ truy cập các nút, các cuộc gọi lại được sử dụng để sửa đổi, thay thế, thêm các nút mới

Đây là một ví dụ

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
1

trong ví dụ này

  • Chúng tôi đã đăng ký gọi lại để được kích hoạt khi bàn giao một nút

    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    31

  • Cuộc gọi lại tạo một số ngẫu nhiên trong khoảng [-10, 10], tạo một nút

    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    32 mới với giá trị được tạo và báo cáo một thông báo trên đầu ra tiêu chuẩn

  • Cuối cùng, nó trả về tham chiếu của nút mới

Tham chiếu được trả về bởi các cuộc gọi lại đại diện cho nút sẽ sử dụng trong AST. Trong ví dụ này, chúng tôi đang thay thế nút ban đầu. Thay vào đó, khi trả về

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
33, nút đã truy cập sẽ bị xóa khỏi cây

Để kích hoạt chuyển đổi, chúng tôi sử dụng thao tác tương tự được sử dụng cho lượt truy cập. Lần này, lượt truy cập trả về tham chiếu của cây đã sửa đổi

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
2

Đây là ví dụ đầy đủ

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
3

Mã nguồn trong

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
34 giống với mã được sử dụng để thực hiện một lượt truy cập đơn giản. Tương tự như vậy, quá trình tạo cây liên quan

Sau đó, chúng tôi sửa một hạt giống cho trình tạo số ngẫu nhiên thông qua

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
35, để có đầu ra nhất quán khi chạy chương trình nhiều lần

Chúng tôi tạo một đối tượng

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
36 và chúng tôi truy cập nó để thu được
Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
37, đây là phiên bản đã biến đổi của cây ban đầu

Để xác minh các phép biến đổi, chúng tôi có thể in AST và “chạy nó” bằng cách chuyển đổi thành mã thực thi. Để làm như vậy, chúng ta sử dụng hàm trợ giúp

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
38

  • Chúng tôi bắt đầu in nội dung của cây bằng cách sử dụng

    >>> code = 'one_plus_two = 1+2 # type: int'
    >>> tree = ast.parse[code, type_comments=True]
    >>> print[ast.dump[tree, indent=4]]
    
    3 như đã thấy trong các ví dụ trước

  • Sau đó, chúng tôi áp dụng

    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    40 cho cây. Mỗi nút trong AST thực sự được dự kiến ​​sẽ có
    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    04 được lấp đầy, nhưng thay vì lấp đầy nó khi thực hiện các phép biến đổi, hàm trợ giúp
    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    40 cho phép trì hoãn việc sửa lỗi này cho đến khi quá trình biên dịch được yêu cầu

  • Cuối cùng, hàm dựng sẵn

    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    43 được sử dụng để chuyển đổi AST thành một đối tượng mã, đến lượt nó được thực thi bằng cách gọi hàm dựng sẵn
    Module[
        body=[
            Assign[
                targets=[
                    Name[id='one_plus_two', ctx=Store[]]],
                value=BinOp[
                    left=Constant[value=1],
                    op=Add[],
                    right=Constant[value=2]]]],
        type_ignores=[]]
    
    44

Đây là đầu ra liên quan đến

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
45

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
4

Đầu ra cho

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
46

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
5

Đầu ra bây giờ là "ngẫu nhiên", như mong đợi của phép biến đổi. Tuy nhiên, phép biến đổi đã ghi đè lên cây ban đầu, vì

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
37 và
Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
48 là cùng một đối tượng

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
6

Tuy nhiên, để tránh điều này, người ta chỉ cần sử dụng lệnh để sao chép toàn bộ cây trước khi kích hoạt chuyển đổi hoặc ghi đè phương thức

Module[
    body=[
        Assign[
            targets=[
                Name[id='one_plus_two', ctx=Store[]]],
            value=BinOp[
                left=Constant[value=1],
                op=Add[],
                right=Constant[value=2]]]],
    type_ignores=[]]
27 và xác định logic đặc biệt cho trường hợp sử dụng hiện tại

AST có phải là một phần của Python không?

Mô-đun ast giúp các ứng dụng Python xử lý cây ngữ pháp cú pháp trừu tượng của Python . Bản thân cú pháp trừu tượng có thể thay đổi với mỗi bản phát hành Python; . Một cây cú pháp trừu tượng có thể được tạo bằng cách chuyển ast.

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

Ví dụ - .
nhập khẩu ast
biểu thức = '6 + 8'
mã = ast. phân tích cú pháp [biểu thức, chế độ = 'eval']
in [eval [biên dịch [mã, '', chế độ = 'eval']]]
in [ast. kết xuất [mã]]

Ngôn ngữ lập trình AST là gì?

Cây cú pháp trừu tượng, hay AST, là biểu diễn cây mã nguồn của chương trình máy tính truyền đạt cấu trúc của mã nguồn. Each node in the tree represents a construct occurring in the source code.

Cây cú pháp trừu tượng Python là gì?

Cây cú pháp trừu tượng [AST] là cấu trúc dữ liệu được sử dụng để suy luận về ngữ pháp của ngôn ngữ lập trình trong ngữ cảnh của các hướng dẫn được cung cấp trong mã nguồn.

Chủ Đề