Khi bạn đang viết python trong trình soạn thảo, bạn sẽ sử dụng lệnh nào để gửi nó tới trình thông dịch?

Allison là kỹ sư tại Dropbox, nơi cô giúp duy trì một trong những mạng máy khách Python lớn nhất thế giới. Trước Dropbox, cô ấy là người điều hành tại Recurse Center, nơi ẩn dật của các nhà văn dành cho các lập trình viên ở New York. Cô ấy đã nói chuyện tại PyCon Bắc Mỹ về nội bộ Python và yêu thích những con bọ kỳ lạ. Cô viết blog tại akaptur. com

[Chương này cũng có sẵn bằng tiếng Trung giản thể]

Giới thiệu

Byterun là một trình thông dịch Python được triển khai trong Python. Thông qua công việc của tôi trên Byterun, tôi đã rất ngạc nhiên và vui mừng khi phát hiện ra rằng cấu trúc cơ bản của trình thông dịch Python dễ dàng phù hợp với giới hạn kích thước 500 dòng. Chương này sẽ đi qua cấu trúc của trình thông dịch và cung cấp cho bạn đủ ngữ cảnh để khám phá thêm về nó. Mục tiêu không phải là giải thích mọi thứ cần biết về trình thông dịch—giống như rất nhiều lĩnh vực thú vị khác của lập trình và khoa học máy tính, bạn có thể dành nhiều năm để phát triển sự hiểu biết sâu sắc về chủ đề này

Byterun được viết bởi Ned Batchelder và tôi, dựa trên tác phẩm của Paul Swartz. Cấu trúc của nó tương tự như triển khai chính của Python, CPython, vì vậy việc hiểu Byterun sẽ giúp bạn hiểu về trình thông dịch nói chung và trình thông dịch CPython nói riêng. [Nếu bạn không biết mình đang dùng Python nào thì có thể là CPython. ] Mặc dù có độ dài ngắn nhưng Byterun có khả năng chạy hầu hết các chương trình Python đơn giản

Trước khi bắt đầu, hãy thu hẹp ý nghĩa của "trình thông dịch Python". Từ "interpreter" có thể được sử dụng theo nhiều cách khác nhau khi thảo luận về Python. Đôi khi, trình thông dịch đề cập đến REPL của Python, lời nhắc tương tác mà bạn nhận được bằng cách nhập

class Interpreter:
    def __init__[self]:
        self.stack = []

    def LOAD_VALUE[self, number]:
        self.stack.append[number]

    def PRINT_ANSWER[self]:
        answer = self.stack.pop[]
        print[answer]

    def ADD_TWO_VALUES[self]:
        first_num = self.stack.pop[]
        second_num = self.stack.pop[]
        total = first_num + second_num
        self.stack.append[total]
9 tại dòng lệnh. Đôi khi, mọi người ít nhiều sử dụng "trình thông dịch Python" thay thế cho "Python" để nói về việc thực thi mã Python từ đầu đến cuối. Trong chương này, "interpreter" có nghĩa hẹp hơn. đó là bước cuối cùng trong quá trình thực thi chương trình Python

Trước khi trình thông dịch tiếp quản, Python thực hiện ba bước khác. từ vựng, phân tích cú pháp và biên dịch. Cùng với nhau, các bước này biến đổi mã nguồn của lập trình viên từ các dòng văn bản thành các đối tượng mã có cấu trúc chứa các hướng dẫn mà trình thông dịch có thể hiểu được. Công việc của người phiên dịch là lấy các đối tượng mã này và làm theo hướng dẫn

Bạn có thể ngạc nhiên khi biết rằng biên dịch hoàn toàn là một bước trong quá trình thực thi mã Python. Python thường được gọi là ngôn ngữ "thông dịch" như Ruby hoặc Perl, trái ngược với ngôn ngữ "biên dịch" như C hoặc Rust. Tuy nhiên, thuật ngữ này không chính xác như nó có vẻ. Hầu hết các ngôn ngữ được giải thích, bao gồm cả Python, đều liên quan đến bước biên dịch. Lý do Python được gọi là "thông dịch" là vì bước biên dịch hoạt động tương đối ít hơn [và trình thông dịch tương đối nhiều hơn] so với ngôn ngữ được biên dịch. Như chúng ta sẽ thấy ở phần sau của chương này, trình biên dịch Python có ít thông tin hơn về hành vi của chương trình so với trình biên dịch C.

Trình thông dịch Python Python

Byterun là một trình thông dịch Python được viết bằng Python. Điều này có thể khiến bạn thấy kỳ quặc, nhưng nó không kỳ quặc hơn việc viết một trình biên dịch C bằng C. [Thật vậy, trình biên dịch C được sử dụng rộng rãi gcc được viết bằng C. ] Bạn có thể viết một trình thông dịch Python bằng hầu hết mọi ngôn ngữ

Viết trình thông dịch Python bằng Python có cả ưu điểm và nhược điểm. Nhược điểm lớn nhất là tốc độ. thực thi mã qua Byterun chậm hơn nhiều so với thực thi mã trong CPython, nơi trình thông dịch được viết bằng C và được tối ưu hóa cẩn thận. Tuy nhiên, Byterun ban đầu được thiết kế như một bài tập học tập, vì vậy tốc độ không quan trọng đối với chúng tôi. Ưu điểm lớn nhất khi sử dụng Python là chúng ta có thể dễ dàng triển khai chỉ trình thông dịch chứ không phải phần còn lại của thời gian chạy Python, đặc biệt là hệ thống đối tượng. Ví dụ: Byterun có thể quay lại Python "thực" khi cần tạo một lớp. Một ưu điểm khác là Byterun rất dễ hiểu, một phần vì nó được viết bằng ngôn ngữ cấp cao [Python. ] mà nhiều người thấy dễ đọc. [Chúng tôi cũng loại trừ việc tối ưu hóa trình thông dịch trong Byterun—một lần nữa ưu tiên sự rõ ràng và đơn giản hơn là tốc độ. ]

Xây dựng một phiên dịch viên

Trước khi bắt đầu xem mã của Byterun, chúng ta cần một số bối cảnh cấp cao hơn về cấu trúc của trình thông dịch. Trình thông dịch Python hoạt động như thế nào?

Trình thông dịch Python là một máy ảo, nghĩa là nó là phần mềm mô phỏng một máy tính vật lý. Máy ảo cụ thể này là một máy ngăn xếp. nó điều khiển một số ngăn xếp để thực hiện các hoạt động của nó [ngược lại với một máy đăng ký ghi và đọc từ các vị trí bộ nhớ cụ thể]

Trình thông dịch Python là trình thông dịch bytecode. đầu vào của nó là tập lệnh được gọi là bytecode. Khi bạn viết Python, từ vựng, trình phân tích cú pháp và trình biên dịch sẽ tạo các đối tượng mã để trình thông dịch hoạt động trên đó. Mỗi đối tượng mã chứa một bộ hướng dẫn sẽ được thực thi—đó là mã byte—cộng với thông tin khác mà trình thông dịch sẽ cần. Bytecode là một đại diện trung gian của mã Python. nó thể hiện mã nguồn mà bạn đã viết theo cách mà trình thông dịch có thể hiểu được. Nó tương tự như cách hợp ngữ đóng vai trò là biểu diễn trung gian giữa mã C và một phần cứng

Phiên dịch viên tí hon

Để làm cho điều này trở nên cụ thể, hãy bắt đầu với một trình thông dịch rất tối thiểu. Trình thông dịch này chỉ có thể thêm số và chỉ hiểu ba hướng dẫn. Tất cả mã mà nó có thể thực thi bao gồm ba lệnh này trong các kết hợp khác nhau. Ba hướng dẫn này là

  •     def run_code[self, what_to_execute]:
            instructions = what_to_execute["instructions"]
            numbers = what_to_execute["numbers"]
            for each_step in instructions:
                instruction, argument = each_step
                if instruction == "LOAD_VALUE":
                    number = numbers[argument]
                    self.LOAD_VALUE[number]
                elif instruction == "ADD_TWO_VALUES":
                    self.ADD_TWO_VALUES[]
                elif instruction == "PRINT_ANSWER":
                    self.PRINT_ANSWER[]
    0
  •     def run_code[self, what_to_execute]:
            instructions = what_to_execute["instructions"]
            numbers = what_to_execute["numbers"]
            for each_step in instructions:
                instruction, argument = each_step
                if instruction == "LOAD_VALUE":
                    number = numbers[argument]
                    self.LOAD_VALUE[number]
                elif instruction == "ADD_TWO_VALUES":
                    self.ADD_TWO_VALUES[]
                elif instruction == "PRINT_ANSWER":
                    self.PRINT_ANSWER[]
    1
  •     def run_code[self, what_to_execute]:
            instructions = what_to_execute["instructions"]
            numbers = what_to_execute["numbers"]
            for each_step in instructions:
                instruction, argument = each_step
                if instruction == "LOAD_VALUE":
                    number = numbers[argument]
                    self.LOAD_VALUE[number]
                elif instruction == "ADD_TWO_VALUES":
                    self.ADD_TWO_VALUES[]
                elif instruction == "PRINT_ANSWER":
                    self.PRINT_ANSWER[]
    2

Vì chúng ta không quan tâm đến từ vựng, trình phân tích cú pháp và trình biên dịch trong chương này nên các tập lệnh được tạo ra như thế nào không quan trọng. Bạn có thể tưởng tượng việc viết

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
3 và có một trình biên dịch phát ra sự kết hợp của ba hướng dẫn này. Hoặc, nếu bạn có trình biên dịch phù hợp, bạn có thể viết cú pháp Lisp được chuyển thành cùng một tổ hợp hướng dẫn. Thông dịch viên không quan tâm. Tất cả những gì quan trọng là thông dịch viên của chúng tôi được sắp xếp hợp lý các hướng dẫn

Giả sử rằng

7 + 5

sản xuất tập lệnh này

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }

Trình thông dịch Python là một máy ngăn xếp, vì vậy nó phải thao tác với các ngăn xếp để cộng hai số [. ] Trình thông dịch sẽ bắt đầu bằng cách thực hiện lệnh đầu tiên,

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
0 và đẩy số đầu tiên vào ngăn xếp. Tiếp theo, nó sẽ đẩy số thứ hai vào ngăn xếp. Đối với hướng dẫn thứ ba,
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
1, nó sẽ bật ra cả hai số, cộng chúng lại với nhau và đẩy kết quả vào ngăn xếp. Cuối cùng, nó sẽ bật câu trả lời ra khỏi ngăn xếp và in nó

Hình 12. 1 - Máy xếp chồng

Lệnh

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
0 yêu cầu trình thông dịch đẩy một số vào ngăn xếp, nhưng chỉ riêng lệnh này không chỉ định số nào. Mỗi hướng dẫn cần thêm một phần thông tin, cho trình thông dịch biết nơi tìm số để tải. Vì vậy, tập lệnh của chúng tôi có hai phần. bản thân các hướng dẫn, cộng với một danh sách các hằng số mà các hướng dẫn sẽ cần. [Trong Python, cái mà chúng ta gọi là "hướng dẫn" là mã byte và đối tượng "điều cần thực thi" bên dưới là đối tượng mã. ]

Tại sao không chỉ đặt các con số trực tiếp trong hướng dẫn? . Chúng tôi sẽ không muốn có các chuỗi được nhồi nhét theo hướng dẫn, vì chúng có thể lớn tùy ý. Thiết kế này cũng có nghĩa là chúng tôi chỉ có thể có một bản sao của mỗi đối tượng mà chúng tôi cần, vì vậy, ví dụ để thêm

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
7,
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
8 có thể chỉ là
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
9

Bạn có thể thắc mắc tại sao lại cần các hướng dẫn khác ngoài

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
1. Thật vậy, đối với trường hợp cộng hai số đơn giản, ví dụ này hơi giả tạo. Tuy nhiên, hướng dẫn này là một khối xây dựng cho các chương trình phức tạp hơn. Ví dụ: chỉ với các hướng dẫn chúng tôi đã xác định cho đến nay, chúng tôi đã có thể cộng ba giá trị lại với nhau—hoặc bất kỳ số lượng giá trị nào—được cung cấp đúng tập hợp các hướng dẫn này. Ngăn xếp cung cấp một cách rõ ràng để theo dõi trạng thái của trình thông dịch và nó sẽ hỗ trợ độ phức tạp cao hơn khi chúng tôi tiếp tục

Bây giờ hãy bắt đầu viết trình thông dịch. Đối tượng trình thông dịch có một ngăn xếp mà chúng ta sẽ biểu diễn bằng một danh sách. Đối tượng cũng có một phương thức mô tả cách thực hiện từng lệnh. Ví dụ, đối với

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
0, trình thông dịch sẽ đẩy giá trị lên ngăn xếp

class Interpreter:
    def __init__[self]:
        self.stack = []

    def LOAD_VALUE[self, number]:
        self.stack.append[number]

    def PRINT_ANSWER[self]:
        answer = self.stack.pop[]
        print[answer]

    def ADD_TWO_VALUES[self]:
        first_num = self.stack.pop[]
        second_num = self.stack.pop[]
        total = first_num + second_num
        self.stack.append[total]

Ba chức năng này thực hiện ba hướng dẫn mà trình thông dịch của chúng tôi hiểu được. Thông dịch viên cần thêm một mảnh. một cách để buộc mọi thứ lại với nhau và thực sự thực hiện nó. Phương pháp này,

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
62, lấy từ điển
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
63 được định nghĩa ở trên làm đối số. Nó lặp qua từng lệnh, xử lý các đối số cho lệnh đó nếu có, sau đó gọi phương thức tương ứng trên đối tượng trình thông dịch

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]

Để kiểm tra, chúng ta có thể tạo một thể hiện của đối tượng và sau đó gọi phương thức

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
62 với tập lệnh cộng 7 + 5 được xác định ở trên

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
6

Chắc chắn, nó in câu trả lời. 12

Mặc dù trình thông dịch này khá hạn chế, nhưng quá trình này gần như chính xác như cách trình thông dịch Python thực thêm số. Có một số điều cần lưu ý ngay cả trong ví dụ nhỏ này

Trước hết, một số hướng dẫn cần đối số. Trong mã byte Python thực, khoảng một nửa hướng dẫn có đối số. Các đối số được đóng gói cùng với các hướng dẫn, giống như trong ví dụ của chúng tôi. Lưu ý rằng các đối số cho các hướng dẫn khác với các đối số cho các phương thức được gọi

Thứ hai, lưu ý rằng hướng dẫn cho

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
1 không yêu cầu bất kỳ đối số nào. Thay vào đó, các giá trị được cộng lại với nhau đã được bật ra khỏi ngăn xếp của trình thông dịch. Đây là tính năng xác định của trình thông dịch dựa trên ngăn xếp

Hãy nhớ rằng các tập lệnh hợp lệ đã cho, không có bất kỳ thay đổi nào đối với trình thông dịch của chúng ta, chúng ta có thể thêm nhiều hơn hai số cùng một lúc. Hãy xem xét các hướng dẫn thiết lập dưới đây. Bạn mong đợi điều gì sẽ xảy ra?

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
2

Tại thời điểm này, chúng ta có thể bắt đầu thấy cấu trúc này có thể mở rộng như thế nào. chúng ta có thể thêm các phương thức trên đối tượng trình thông dịch mô tả nhiều thao tác hơn [miễn là chúng ta có trình biên dịch để cung cấp cho chúng ta các tập lệnh được định dạng tốt]

Biến

Tiếp theo, hãy thêm các biến vào trình thông dịch của chúng ta. Các biến yêu cầu một hướng dẫn để lưu trữ giá trị của một biến,

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
66; . Hiện tại, chúng tôi sẽ bỏ qua không gian tên và phạm vi, vì vậy chúng tôi có thể lưu trữ ánh xạ biến trên chính đối tượng trình thông dịch. Cuối cùng, chúng ta sẽ phải đảm bảo rằng
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
63 có danh sách tên biến, ngoài danh sách hằng số của nó

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
6

Triển khai mới của chúng tôi bên dưới. Để theo dõi tên nào bị ràng buộc với giá trị nào, chúng tôi sẽ thêm từ điển

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
69 vào phương thức
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
20. Chúng tôi cũng sẽ thêm
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
66 và
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
67. Các phương thức này trước tiên tra cứu tên biến được đề cập và sau đó sử dụng từ điển để lưu trữ hoặc truy xuất giá trị của nó

Các đối số cho một hướng dẫn bây giờ có thể có nghĩa là hai điều khác nhau. Chúng có thể là một chỉ mục trong danh sách "số" hoặc chúng có thể là một chỉ mục trong danh sách "tên". Trình thông dịch biết nó nên là gì bằng cách kiểm tra lệnh nào nó đang thực thi. Chúng ta sẽ tách logic này—và ánh xạ các hướng dẫn tới ý nghĩa của các đối số của chúng—thành một phương thức riêng biệt

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
1

Ngay cả khi chỉ có năm hướng dẫn, phương pháp

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
62 bắt đầu trở nên tẻ nhạt. Nếu chúng tôi giữ cấu trúc này, chúng tôi sẽ cần một nhánh của câu lệnh
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
24 cho mỗi hướng dẫn. Ở đây, chúng ta có thể sử dụng tra cứu phương thức động của Python. Chúng ta sẽ luôn định nghĩa một phương thức có tên là
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
25 để thực thi lệnh có tên là
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
25, vì vậy chúng ta có thể sử dụng hàm
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
27 của Python để tra cứu phương thức một cách nhanh chóng thay vì sử dụng câu lệnh lớn
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
24. Phương pháp
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
62 sau đó trông như thế này

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
9

Mã byte Python thực

Tại thời điểm này, chúng tôi sẽ từ bỏ bộ hướng dẫn đồ chơi của mình và chuyển sang mã byte Python thực. Cấu trúc của mã byte tương tự như bộ hướng dẫn chi tiết của trình thông dịch đồ chơi của chúng tôi, ngoại trừ việc nó sử dụng một byte thay vì tên dài để xác định từng lệnh. Để hiểu cấu trúc này, chúng ta sẽ xem qua bytecode của một hàm ngắn. Hãy xem xét ví dụ dưới đây

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
0

Python hiển thị một lượng lớn nội dung bên trong của nó trong thời gian chạy và chúng tôi có thể truy cập chúng ngay từ REPL. Đối với đối tượng chức năng

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
60,
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
61 là đối tượng mã được liên kết với nó và
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
62 là mã byte. Hầu như không bao giờ có lý do chính đáng để sử dụng trực tiếp các thuộc tính này khi bạn đang viết mã Python, nhưng chúng cho phép chúng ta xử lý tất cả các loại trò nghịch ngợm—và xem xét nội dung bên trong để hiểu chúng

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
0

Khi chúng tôi chỉ in mã byte, nó có vẻ khó hiểu—tất cả những gì chúng tôi có thể biết là đó là một chuỗi byte. May mắn thay, có một công cụ mạnh mẽ mà chúng ta có thể sử dụng để hiểu nó. mô-đun

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
63 trong thư viện chuẩn Python

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
63 là trình phân tách bytecode. Trình dịch mã lấy mã cấp thấp được viết cho máy, chẳng hạn như mã hợp ngữ hoặc mã byte và in mã đó theo cách mà con người có thể đọc được. Khi chúng tôi chạy
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
65, nó sẽ đưa ra lời giải thích về mã byte mà nó đã truyền

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
1

Tất cả điều này có nghĩa là gì? . Số trong cột đầu tiên [

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
67] hiển thị số dòng trong mã nguồn Python của chúng tôi. Cột thứ hai là một chỉ mục trong mã byte, cho chúng tôi biết rằng lệnh
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
66 xuất hiện ở vị trí 0. Cột thứ ba là chính hướng dẫn, được ánh xạ tới tên mà con người có thể đọc được. Cột thứ tư, khi có mặt, là đối số cho hướng dẫn đó. Cột thứ năm, nếu có, là một gợi ý về ý nghĩa của đối số

Hãy xem xét một vài byte đầu tiên của mã byte này. [100, 1, 0, 125, 0, 0]. Sáu byte này đại diện cho hai hướng dẫn với các đối số của chúng. Chúng ta có thể sử dụng

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
69, ánh xạ từ byte sang chuỗi dễ hiểu, để tìm ra lệnh 100 và 125 ánh xạ tới

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
2

Byte thứ hai và thứ ba—1, 0—là đối số của

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
66, trong khi byte thứ năm và thứ sáu—0, 0—là đối số của
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
11. Giống như trong ví dụ về đồ chơi của chúng ta,
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
66 cần biết nơi tìm hằng số để tải và
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
11 cần tìm tên để lưu trữ. [______266 của Python giống với
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
0 của phiên dịch viên đồ chơi của chúng tôi và
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
16 giống với
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
67. ] Vì vậy, sáu byte này đại diện cho dòng mã đầu tiên,
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
18. [Tại sao lại sử dụng hai byte cho mỗi đối số? Nếu Python chỉ sử dụng một byte để định vị các hằng và tên thay vì hai, thì bạn chỉ có thể có 256 tên/hằng được liên kết với một đối tượng mã duy nhất. Sử dụng hai byte, bạn có thể có tới 256 bình phương hoặc 65.536. ]

Điều kiện và vòng lặp

Cho đến nay, trình thông dịch đã thực thi mã đơn giản bằng cách thực hiện từng hướng dẫn một. Đây là một vấn đề; . Để cho phép chúng tôi viết các vòng lặp và các câu lệnh if trong mã của chúng tôi, trình thông dịch phải có khả năng nhảy xung quanh trong tập lệnh. Theo một nghĩa nào đó, Python xử lý các vòng lặp và điều kiện bằng các câu lệnh

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
19 trong mã byte. Nhìn lại việc tháo rời chức năng
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
60

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
1

Điều kiện

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
91 trên dòng 3 của mã được biên dịch thành bốn hướng dẫn.
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
16,
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
66,
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
94 và
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
95.
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
96 tạo mã để tải
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
97, tải 5 và so sánh hai giá trị. Hướng dẫn
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
95 chịu trách nhiệm thực hiện
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
24. Hướng dẫn này sẽ bật giá trị cao nhất ra khỏi ngăn xếp của trình thông dịch. Nếu giá trị là true, thì không có gì xảy ra. [Giá trị có thể là "trung thực"—không nhất thiết phải là đối tượng
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
00 theo nghĩa đen. ] Nếu giá trị là sai, thì trình thông dịch sẽ chuyển sang hướng dẫn khác

Lệnh tiếp đất được gọi là mục tiêu nhảy và nó được cung cấp làm đối số cho lệnh

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
01. Ở đây, mục tiêu nhảy là 22. Hướng dẫn tại chỉ mục 22 là
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
66 trên dòng 6. [
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
63 đánh dấu mục tiêu nhảy với
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
04. ] Nếu kết quả của
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
96 là Sai thì trình thông dịch nhảy thẳng đến dòng 6 [
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
06], bỏ qua dòng 4 [
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
07]. Do đó, trình thông dịch sử dụng các lệnh nhảy để bỏ qua có chọn lọc các phần của tập lệnh

Các vòng lặp Python cũng dựa vào việc nhảy. Trong mã byte bên dưới, lưu ý rằng dòng

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
08 tạo mã byte gần như giống hệt với
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
09. Trong cả hai trường hợp, phép so sánh được tính toán và sau đó
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
95 kiểm soát lệnh nào được thực hiện tiếp theo. Ở cuối dòng 4—cuối phần thân của vòng lặp—hướng dẫn
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
01 luôn gửi trình thông dịch trở lại hướng dẫn 9 ở đầu vòng lặp. Khi x < 5 trở thành sai, thì
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
95 nhảy trình thông dịch qua cuối vòng lặp, đến hướng dẫn 34

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
4

Khám phá mã byte

Tôi khuyến khích bạn thử chạy

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
65 trên các hàm bạn viết. Một số câu hỏi để khám phá

  • Sự khác biệt giữa vòng lặp for và vòng lặp while đối với trình thông dịch Python là gì?
  • Làm cách nào bạn có thể viết các hàm khác nhau để tạo mã byte giống hệt nhau?
  • Làm thế nào để
    what_to_execute = {
        "instructions": [["LOAD_VALUE", 0],  # the first number
                         ["LOAD_VALUE", 1],  # the second number
                         ["ADD_TWO_VALUES", None],
                         ["PRINT_ANSWER", None]],
        "numbers": [7, 5] }
    04 làm việc?

khung

Cho đến nay, chúng ta đã biết rằng máy ảo Python là một máy xếp chồng. Nó bước và nhảy qua các hướng dẫn, bật và tắt các giá trị trong ngăn xếp. Tuy nhiên, vẫn còn một số lỗ hổng trong mô hình tinh thần của chúng ta. Trong các ví dụ trên, lệnh cuối cùng là

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
05, tương ứng với câu lệnh
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
06 trong mã. Nhưng hướng dẫn trở về đâu?

Để trả lời câu hỏi này, chúng ta phải thêm một lớp phức tạp. khung. Khung là tập hợp thông tin và ngữ cảnh cho một đoạn mã. Các khung được tạo và hủy nhanh chóng khi mã Python của bạn thực thi. Có một khung tương ứng với mỗi lần gọi hàm—vì vậy trong khi mỗi khung có một đối tượng mã được liên kết với nó, thì một đối tượng mã có thể có nhiều khung. Nếu bạn có một hàm gọi chính nó theo cách đệ quy mười lần, thì bạn sẽ có mười một khung—một khung cho mỗi mức đệ quy và một khung cho mô-đun mà bạn đã bắt đầu từ đó. Nói chung, có một khung cho từng phạm vi trong chương trình Python. Ví dụ: mỗi mô-đun, mỗi lệnh gọi hàm và mỗi định nghĩa lớp có một khung

Các khung nằm trong ngăn xếp cuộc gọi, một ngăn xếp hoàn toàn khác với ngăn xếp mà chúng ta đã thảo luận cho đến nay. [Ngăn xếp lệnh gọi là ngăn xếp mà bạn đã quen thuộc nhất rồi—bạn đã thấy nó được in ra trong truy nguyên các ngoại lệ. Mỗi dòng trong truy nguyên bắt đầu bằng chương trình "Tệp '. py', dòng 10" tương ứng với một khung trên ngăn xếp cuộc gọi. ] Ngăn xếp mà chúng tôi đang kiểm tra—ngăn xếp mà trình thông dịch đang thao tác trong khi thực thi mã byte—chúng tôi sẽ gọi ngăn xếp dữ liệu. Ngoài ra còn có ngăn xếp thứ ba, được gọi là ngăn xếp khối. Các khối được sử dụng cho một số loại luồng điều khiển, đặc biệt là xử lý vòng lặp và ngoại lệ. Mỗi khung trên ngăn xếp cuộc gọi có ngăn xếp dữ liệu và ngăn xếp khối riêng

Hãy làm cho điều này cụ thể với một ví dụ. Giả sử trình thông dịch Python hiện đang thực thi dòng được đánh dấu 3 bên dưới. Thông dịch viên đang gọi tới số _______ 607, số này đang gọi số _______ 608. Sơ đồ hiển thị sơ đồ ngăn xếp cuộc gọi của khung, ngăn xếp khối và ngăn xếp dữ liệu. [Mã này được viết giống như phiên REPL, vì vậy trước tiên chúng tôi đã xác định các chức năng cần thiết. ] Tại thời điểm chúng tôi quan tâm, trình thông dịch đang thực thi

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
09, ở dưới cùng, sau đó tiếp cận với phần thân của
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
07 và sau đó lên tới
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
08

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
5

Hình 12. 2 - Ngăn xếp cuộc gọi

Tại thời điểm này, trình thông dịch đang ở giữa lời gọi hàm tới

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
08. Có ba khung trên ngăn xếp cuộc gọi. một cho cấp độ mô-đun, một cho chức năng
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
07 và một cho
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
08 [. ] Khi
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
08 quay trở lại, khung được liên kết với nó sẽ được bật ra khỏi ngăn xếp cuộc gọi và bị loại bỏ

Lệnh bytecode

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
05 yêu cầu trình thông dịch chuyển một giá trị giữa các khung. Đầu tiên, nó sẽ bật giá trị trên cùng ra khỏi ngăn xếp dữ liệu của khung trên cùng trên ngăn xếp cuộc gọi. Sau đó, nó bật toàn bộ khung ra khỏi ngăn xếp cuộc gọi và ném nó đi. Cuối cùng, giá trị được đẩy lên ngăn xếp dữ liệu trên khung tiếp theo xuống

Khi tôi và Ned Batchelder làm việc trên Byterun, trong một thời gian dài, chúng tôi đã gặp một lỗi nghiêm trọng trong quá trình triển khai. Thay vì có một ngăn xếp dữ liệu trên mỗi khung, chúng tôi chỉ có một ngăn xếp dữ liệu trên toàn bộ máy ảo. Chúng tôi đã có hàng tá thử nghiệm được tạo thành từ các đoạn mã Python nhỏ mà chúng tôi đã chạy qua Byterun và thông qua trình thông dịch Python thực để đảm bảo điều tương tự xảy ra ở cả hai trình thông dịch. Gần như tất cả các bài kiểm tra này đều vượt qua. Điều duy nhất chúng tôi không thể làm việc là máy phát điện. Cuối cùng, đọc kỹ mã CPython hơn, chúng tôi nhận ra sai lầm. Di chuyển ngăn xếp dữ liệu vào từng khung đã khắc phục sự cố

Nhìn lại lỗi này, tôi đã rất ngạc nhiên về việc Python phụ thuộc rất ít vào mỗi khung có ngăn xếp dữ liệu khác nhau. Gần như tất cả các hoạt động trong trình thông dịch Python đều dọn sạch ngăn xếp dữ liệu một cách cẩn thận, vì vậy việc các khung chia sẻ cùng một ngăn xếp không thành vấn đề. Trong ví dụ trên, khi

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
08 thực thi xong, nó sẽ để trống ngăn xếp dữ liệu. Ngay cả khi
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
07 chia sẻ cùng một ngăn xếp, các giá trị sẽ thấp hơn. Tuy nhiên, với các trình tạo, một tính năng chính là khả năng tạm dừng một khung, quay lại một số khung khác, sau đó quay lại khung trình tạo sau đó và đặt nó ở trạng thái chính xác như khi bạn rời khỏi nó.

Byterun

Bây giờ chúng ta có đủ ngữ cảnh về trình thông dịch Python để bắt đầu kiểm tra Byterun

Có bốn loại đối tượng trong Byterun

  • Một lớp
    what_to_execute = {
        "instructions": [["LOAD_VALUE", 0],  # the first number
                         ["LOAD_VALUE", 1],  # the second number
                         ["ADD_TWO_VALUES", None],
                         ["PRINT_ANSWER", None]],
        "numbers": [7, 5] }
    19, quản lý cấu trúc cấp cao nhất, đặc biệt là ngăn xếp cuộc gọi của các khung và chứa ánh xạ các lệnh tới các thao tác. Đây là phiên bản phức tạp hơn của đối tượng
    what_to_execute = {
        "instructions": [["LOAD_VALUE", 0],  # the first number
                         ["LOAD_VALUE", 1],  # the second number
                         ["ADD_TWO_VALUES", None],
                         ["PRINT_ANSWER", None]],
        "numbers": [7, 5] }
    20 ở trên
  • Một lớp
    what_to_execute = {
        "instructions": [["LOAD_VALUE", 0],  # the first number
                         ["LOAD_VALUE", 1],  # the second number
                         ["ADD_TWO_VALUES", None],
                         ["PRINT_ANSWER", None]],
        "numbers": [7, 5] }
    21. Mỗi phiên bản
    what_to_execute = {
        "instructions": [["LOAD_VALUE", 0],  # the first number
                         ["LOAD_VALUE", 1],  # the second number
                         ["ADD_TWO_VALUES", None],
                         ["PRINT_ANSWER", None]],
        "numbers": [7, 5] }
    21 có một đối tượng mã và quản lý một vài bit trạng thái cần thiết khác, đặc biệt là không gian tên toàn cục và cục bộ, tham chiếu đến khung gọi và lệnh mã byte cuối cùng được thực thi
  • Một lớp
    what_to_execute = {
        "instructions": [["LOAD_VALUE", 0],  # the first number
                         ["LOAD_VALUE", 1],  # the second number
                         ["ADD_TWO_VALUES", None],
                         ["PRINT_ANSWER", None]],
        "numbers": [7, 5] }
    23, sẽ được sử dụng thay cho các hàm Python thực. Nhớ lại rằng việc gọi một hàm sẽ tạo một khung mới trong trình thông dịch. Chúng tôi triển khai Chức năng để chúng tôi kiểm soát việc tạo các Khung mới
  • Một lớp
    what_to_execute = {
        "instructions": [["LOAD_VALUE", 0],  # the first number
                         ["LOAD_VALUE", 1],  # the second number
                         ["ADD_TWO_VALUES", None],
                         ["PRINT_ANSWER", None]],
        "numbers": [7, 5] }
    24, chỉ bao bọc ba thuộc tính của các khối. [Chi tiết về các khối không phải là trọng tâm của trình thông dịch Python, vì vậy chúng tôi sẽ không dành nhiều thời gian cho chúng, nhưng chúng được bao gồm ở đây để Byterun có thể chạy mã Python thực. ]

Lớp học
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
19

Chỉ một phiên bản của

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
19 sẽ được tạo mỗi khi chương trình được chạy, bởi vì chúng tôi chỉ có một trình thông dịch Python.
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
19 lưu trữ ngăn xếp cuộc gọi, trạng thái ngoại lệ và trả về các giá trị trong khi chúng được chuyển giữa các khung. Điểm vào để thực thi mã là phương thức
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
62, lấy một đối tượng mã đã biên dịch làm đối số. Nó bắt đầu bằng cách thiết lập và chạy một khung. Khung này có thể tạo ra các khung khác; . Khi khung hình đầu tiên cuối cùng trở lại, quá trình thực thi kết thúc

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
6

Lớp học
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
21

Tiếp theo chúng ta sẽ viết đối tượng

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
21. Khung là tập hợp các thuộc tính không có phương thức. Như đã đề cập ở trên, các thuộc tính bao gồm đối tượng mã được tạo bởi trình biên dịch; . [Chúng ta phải thực hiện thêm một chút công việc để truy cập không gian tên dựng sẵn vì Python xử lý không gian tên này khác nhau trong các mô-đun khác nhau; chi tiết này không quan trọng đối với máy ảo. ]

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
7

Tiếp theo, chúng tôi sẽ thêm thao tác khung vào máy ảo. Có ba chức năng trợ giúp cho các khung. một để tạo các khung mới [chịu trách nhiệm sắp xếp các không gian tên cho khung mới] và một để đẩy và bật khung lên và tắt ngăn xếp khung. Hàm thứ tư,

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
31, thực hiện công việc chính là thực thi một khung. Chúng ta sẽ quay lại vấn đề này sớm thôi

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
8

Lớp học
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
23

Việc triển khai đối tượng

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
23 hơi khó hiểu và hầu hết các chi tiết không quan trọng để hiểu trình thông dịch. Điều quan trọng cần lưu ý là việc gọi một hàm—gọi phương thức
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
34—tạo một đối tượng
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
21 mới và bắt đầu chạy nó

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
9

Tiếp theo, quay lại đối tượng

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
19, chúng ta sẽ thêm một số phương thức trợ giúp để thao tác ngăn xếp dữ liệu. Các mã byte điều khiển ngăn xếp luôn hoạt động trên ngăn xếp dữ liệu của khung hiện tại. Điều này sẽ làm cho việc triển khai của chúng tôi về
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
37,
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
16 và tất cả các hướng dẫn khác liên quan đến ngăn xếp dễ đọc hơn

class Interpreter:
    def __init__[self]:
        self.stack = []

    def LOAD_VALUE[self, number]:
        self.stack.append[number]

    def PRINT_ANSWER[self]:
        answer = self.stack.pop[]
        print[answer]

    def ADD_TWO_VALUES[self]:
        first_num = self.stack.pop[]
        second_num = self.stack.pop[]
        total = first_num + second_num
        self.stack.append[total]
0

Trước khi bắt đầu chạy một khung, chúng ta cần thêm hai phương thức

Đầu tiên,

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
39, lấy mã byte, kiểm tra xem nó có đối số không và phân tích cú pháp đối số nếu có. Phương thức này cũng cập nhật thuộc tính của khung
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
40, tham chiếu đến lệnh cuối cùng được thực hiện. Một lệnh dài một byte nếu nó không có đối số và ba byte nếu nó có đối số; . Ý nghĩa của đối số đối với mỗi lệnh phụ thuộc vào lệnh đó là lệnh nào. Ví dụ, như đã đề cập ở trên, đối với
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
95, đối số của lệnh là đích nhảy. Đối với
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
42, nó là số phần tử trong danh sách. Đối với
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
66, nó là một chỉ mục trong danh sách các hằng số

Một số hướng dẫn sử dụng các số đơn giản làm đối số của chúng. Đối với những người khác, máy ảo phải thực hiện một công việc nhỏ để khám phá ý nghĩa của các đối số. Mô-đun

    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
63 trong thư viện tiêu chuẩn hiển thị một trang phục giải thích các đối số có ý nghĩa gì, điều này làm cho mã của chúng tôi gọn hơn. Ví dụ: danh sách
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
45 cho chúng ta biết rằng các đối số của
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
67,
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
47,
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
48 và chín hướng dẫn khác có cùng ý nghĩa. đối với các hướng dẫn này, đối số đại diện cho một chỉ mục trong danh sách tên trên đối tượng mã

class Interpreter:
    def __init__[self]:
        self.stack = []

    def LOAD_VALUE[self, number]:
        self.stack.append[number]

    def PRINT_ANSWER[self]:
        answer = self.stack.pop[]
        print[answer]

    def ADD_TWO_VALUES[self]:
        first_num = self.stack.pop[]
        second_num = self.stack.pop[]
        total = first_num + second_num
        self.stack.append[total]
1

Phương thức tiếp theo là

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
49, tìm kiếm các hoạt động cho một lệnh nhất định và thực hiện chúng. Trong trình thông dịch CPython, việc gửi đi này được thực hiện với một câu lệnh chuyển đổi khổng lồ kéo dài 1.500 dòng. May mắn thay, vì chúng tôi đang viết Python, chúng tôi có thể gọn hơn. Chúng tôi sẽ xác định một phương thức cho từng tên byte và sau đó sử dụng
    def run_code[self, what_to_execute]:
        instructions = what_to_execute["instructions"]
        numbers = what_to_execute["numbers"]
        for each_step in instructions:
            instruction, argument = each_step
            if instruction == "LOAD_VALUE":
                number = numbers[argument]
                self.LOAD_VALUE[number]
            elif instruction == "ADD_TWO_VALUES":
                self.ADD_TWO_VALUES[]
            elif instruction == "PRINT_ANSWER":
                self.PRINT_ANSWER[]
27 để tra cứu nó. Giống như trong trình thông dịch đồ chơi ở trên, nếu hướng dẫn của chúng tôi được đặt tên là
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
51, thì phương thức tương ứng sẽ được đặt tên là
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
52. Hiện tại, chúng tôi sẽ để nội dung của các phương thức này dưới dạng hộp đen. Mỗi phương thức mã byte sẽ trả về
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
53 hoặc một chuỗi, được gọi là
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
54, đây là một phần trạng thái bổ sung mà trình thông dịch cần trong một số trường hợp. Các giá trị trả về này của các phương thức lệnh riêng lẻ chỉ được sử dụng làm chỉ báo nội bộ của trạng thái trình thông dịch—đừng nhầm lẫn các giá trị này với các giá trị trả về từ các khung thực thi

class Interpreter:
    def __init__[self]:
        self.stack = []

    def LOAD_VALUE[self, number]:
        self.stack.append[number]

    def PRINT_ANSWER[self]:
        answer = self.stack.pop[]
        print[answer]

    def ADD_TWO_VALUES[self]:
        first_num = self.stack.pop[]
        second_num = self.stack.pop[]
        total = first_num + second_num
        self.stack.append[total]
2

Lớp học
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
24

Trước khi triển khai các phương thức cho từng lệnh bytecode, chúng ta sẽ thảo luận ngắn gọn về các khối. Một khối được sử dụng cho một số loại điều khiển luồng nhất định, cụ thể là xử lý ngoại lệ và vòng lặp. Khối chịu trách nhiệm đảm bảo rằng ngăn xếp dữ liệu ở trạng thái thích hợp khi hoạt động kết thúc. Ví dụ, trong một vòng lặp, một đối tượng lặp đặc biệt vẫn còn trên ngăn xếp trong khi vòng lặp đang chạy, nhưng sẽ bật ra khi nó kết thúc. Trình thông dịch phải theo dõi xem vòng lặp đang tiếp tục hay đã kết thúc

Để theo dõi phần thông tin bổ sung này, trình thông dịch đặt cờ để chỉ trạng thái của nó. Chúng tôi triển khai cờ này dưới dạng một biến có tên là

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
54, có thể là
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
53 hoặc một trong các chuỗi
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
58,
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
59,
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
60 hoặc
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
61. Điều này cho biết loại thao tác nào đối với ngăn xếp khối và ngăn xếp dữ liệu sẽ xảy ra. Để quay lại ví dụ về bộ lặp, nếu đỉnh của ngăn xếp khối là khối
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
62 và mã
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
54 là
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
64, thì đối tượng bộ lặp sẽ vẫn nằm trên ngăn xếp dữ liệu, nhưng nếu mã
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
54 là
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
66, thì nó sẽ bị loại bỏ

Các chi tiết chính xác của thao tác khối khá khó sử dụng và chúng tôi sẽ không dành nhiều thời gian hơn cho việc này, nhưng những độc giả quan tâm được khuyến khích xem xét cẩn thận

class Interpreter:
    def __init__[self]:
        self.stack = []

    def LOAD_VALUE[self, number]:
        self.stack.append[number]

    def PRINT_ANSWER[self]:
        answer = self.stack.pop[]
        print[answer]

    def ADD_TWO_VALUES[self]:
        first_num = self.stack.pop[]
        second_num = self.stack.pop[]
        total = first_num + second_num
        self.stack.append[total]
3

Hướng dẫn

Tất cả những gì còn lại là thực hiện hàng chục phương pháp để được hướng dẫn. Các hướng dẫn thực tế là phần ít thú vị nhất của trình thông dịch, vì vậy chúng tôi chỉ hiển thị một số ít ở đây, nhưng phần triển khai đầy đủ có sẵn trên GitHub. [Có đủ hướng dẫn ở đây để thực thi tất cả các mẫu mã mà chúng tôi đã phân tách ở trên. ]

class Interpreter:
    def __init__[self]:
        self.stack = []

    def LOAD_VALUE[self, number]:
        self.stack.append[number]

    def PRINT_ANSWER[self]:
        answer = self.stack.pop[]
        print[answer]

    def ADD_TWO_VALUES[self]:
        first_num = self.stack.pop[]
        second_num = self.stack.pop[]
        total = first_num + second_num
        self.stack.append[total]
4

Nhập động. Những gì trình biên dịch không biết

Một điều mà bạn có thể đã nghe nói rằng Python là một ngôn ngữ "động"—đặc biệt là nó được "gõ động". Công việc chúng tôi đã thực hiện cho đến thời điểm này làm sáng tỏ mô tả này

Một trong những điều "động" có nghĩa là trong bối cảnh này là rất nhiều công việc được thực hiện trong thời gian chạy. Trước đó chúng ta đã thấy rằng trình biên dịch Python không có nhiều thông tin về chức năng thực sự của đoạn mã này. Ví dụ: hãy xem xét chức năng ngắn

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
67 bên dưới.
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
67 nhận hai đối số và trả về modulo đầu tiên thứ hai. Trong bytecode ta thấy biến
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
69 và
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
70 được nạp vào thì bytecode
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
71 tự thực hiện thao tác modulo

class Interpreter:
    def __init__[self]:
        self.stack = []

    def LOAD_VALUE[self, number]:
        self.stack.append[number]

    def PRINT_ANSWER[self]:
        answer = self.stack.pop[]
        print[answer]

    def ADD_TWO_VALUES[self]:
        first_num = self.stack.pop[]
        second_num = self.stack.pop[]
        total = first_num + second_num
        self.stack.append[total]
5

Tính 19

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
72 5 ra 4—không có gì ngạc nhiên. Điều gì xảy ra nếu chúng ta gọi nó với các đối số khác nhau?

class Interpreter:
    def __init__[self]:
        self.stack = []

    def LOAD_VALUE[self, number]:
        self.stack.append[number]

    def PRINT_ANSWER[self]:
        answer = self.stack.pop[]
        print[answer]

    def ADD_TWO_VALUES[self]:
        first_num = self.stack.pop[]
        second_num = self.stack.pop[]
        total = first_num + second_num
        self.stack.append[total]
6

Điều gì vừa xảy ra?

class Interpreter:
    def __init__[self]:
        self.stack = []

    def LOAD_VALUE[self, number]:
        self.stack.append[number]

    def PRINT_ANSWER[self]:
        answer = self.stack.pop[]
        print[answer]

    def ADD_TWO_VALUES[self]:
        first_num = self.stack.pop[]
        second_num = self.stack.pop[]
        total = first_num + second_num
        self.stack.append[total]
7

Sử dụng ký hiệu

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
72 để định dạng một chuỗi để in có nghĩa là gọi lệnh
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
71. Lệnh này điều chỉnh hai giá trị trên cùng của ngăn xếp cùng nhau khi lệnh thực thi—bất kể chúng là chuỗi, số nguyên hay thể hiện của lớp do bạn tự xác định. Mã byte được tạo khi hàm được biên dịch [thực tế là khi nó được xác định] và cùng một mã byte được sử dụng với các loại đối số khác nhau

Trình biên dịch Python biết tương đối ít về hiệu ứng mà mã byte sẽ có. Tùy thuộc vào trình thông dịch để xác định loại đối tượng mà

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
71 đang hoạt động và thực hiện đúng cho loại đó. Đây là lý do tại sao Python được mô tả là kiểu động. bạn không biết các loại đối số của hàm này cho đến khi bạn thực sự chạy nó. Ngược lại, trong một ngôn ngữ được nhập tĩnh, lập trình viên cho trình biên dịch biết trước loại đối số sẽ là gì [hoặc trình biên dịch sẽ tự tìm ra chúng]

Sự thiếu hiểu biết của trình biên dịch là một trong những thách thức đối với việc tối ưu hóa Python hoặc phân tích nó một cách tĩnh—chỉ nhìn vào mã byte mà không thực sự chạy mã, bạn không biết mỗi lệnh sẽ làm gì. Trên thực tế, bạn có thể định nghĩa một lớp triển khai phương thức

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
76 và Python sẽ gọi phương thức đó nếu bạn sử dụng
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
72 trên các đối tượng của mình. Vì vậy,
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
71 có thể chạy bất kỳ mã nào

Chỉ cần nhìn vào đoạn mã sau, phép tính đầu tiên của

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
79 có vẻ lãng phí

class Interpreter:
    def __init__[self]:
        self.stack = []

    def LOAD_VALUE[self, number]:
        self.stack.append[number]

    def PRINT_ANSWER[self]:
        answer = self.stack.pop[]
        print[answer]

    def ADD_TWO_VALUES[self]:
        first_num = self.stack.pop[]
        second_num = self.stack.pop[]
        total = first_num + second_num
        self.stack.append[total]
8

Thật không may, một phân tích tĩnh của mã này—loại mà bạn có thể thực hiện mà không cần chạy nó—không thể chắc chắn rằng

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
79 đầu tiên thực sự không có tác dụng gì. Gọi
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
76 bằng
what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
72 có thể ghi vào một tệp hoặc tương tác với một phần khác trong chương trình của bạn hoặc thực hiện bất kỳ điều gì khác có thể thực hiện được trong Python. Thật khó để tối ưu hóa một chức năng khi bạn không biết nó làm gì. Trong bài báo tuyệt vời của Russell Power và Alex Rubinsteyn "Chúng ta có thể giải thích Python nhanh như thế nào?", họ lưu ý, "Trong trường hợp không có thông tin loại, mỗi lệnh phải được coi là ________ 683. "

Phần kết luận

Byterun là trình thông dịch Python nhỏ gọn dễ hiểu hơn CPython. Byterun sao chép các chi tiết cấu trúc chính của CPython. một trình thông dịch dựa trên ngăn xếp hoạt động trên các tập lệnh được gọi là bytecode. Nó bước hoặc nhảy qua các hướng dẫn này, đẩy tới và bật ra khỏi ngăn xếp dữ liệu. Trình thông dịch tạo, hủy và nhảy giữa các khung khi nó gọi và trả về từ các hàm và trình tạo. Byterun cũng chia sẻ những hạn chế của trình thông dịch thực sự. vì Python sử dụng kiểu gõ động, trình thông dịch phải làm việc chăm chỉ trong thời gian chạy để xác định hành vi đúng của chương trình

Tôi khuyến khích bạn tháo rời các chương trình của riêng mình và chạy chúng bằng Byterun. Bạn sẽ nhanh chóng gặp phải các hướng dẫn mà phiên bản Byterun ngắn hơn này không triển khai. Việc triển khai đầy đủ có thể được tìm thấy tại https. //github. com/nedbat/byterun—hoặc, bằng cách đọc kỹ

what_to_execute = {
    "instructions": [["LOAD_VALUE", 0],  # the first number
                     ["LOAD_VALUE", 1],  # the second number
                     ["ADD_TWO_VALUES", None],
                     ["PRINT_ANSWER", None]],
    "numbers": [7, 5] }
84 của trình thông dịch CPython thực sự, bạn có thể tự triển khai nó

Sự nhìn nhận

Cảm ơn Ned Batchelder vì đã khởi xướng dự án này và hướng dẫn những đóng góp của tôi, Michael Arntzenius vì đã giúp gỡ lỗi mã và chỉnh sửa văn xuôi, Leta Montopoli vì những chỉnh sửa của cô ấy và toàn bộ cộng đồng Recurse Center vì sự hỗ trợ và quan tâm của họ. Bất kỳ sai sót là của riêng tôi

Trình thông dịch nào được sử dụng khi bạn chạy lệnh a py?

Lệnh py . Tương tự như lệnh py của Windows, bạn có thể in ra phiên bản bằng tùy chọn -V. Để chạy tập lệnh của chúng tôi, bạn có thể sử dụng lệnh trình thông dịch Python và trỏ nó vào tập lệnh. Python interpreter using the command python. Similar to the Windows py command, you can print out the version using the -V option. To run our script, you can use the Python interpreter command and point it to the script.

Chế độ thông dịch viên trong Python là gì?

các tệp py được chạy trong trình thông dịch Python. Chế độ tương tác là trình bao dòng lệnh cung cấp phản hồi ngay lập tức cho từng câu lệnh, trong khi chạy các câu lệnh đã nạp trước đó trong bộ nhớ hoạt động. Khi các dòng mới được đưa vào trình thông dịch, chương trình đã nạp được đánh giá cả một phần và toàn bộ

Làm cách nào để diễn giải mã Python?

Python là ngôn ngữ thông dịch, có nghĩa là mã nguồn của chương trình Python được chuyển đổi thành mã byte, sau đó được thực thi bởi máy ảo Python. Python is different from major compiled languages, such as C and C + +, as Python code is not required to be built and linked like code for these languages.

Chủ Đề