Tại sao Python không cần trình biên dịch?


29

Chỉ cần tự hỏi (bây giờ tôi đã bắt đầu với C ++ cần trình biên dịch) tại sao Python không cần trình biên dịch?

Tôi chỉ cần nhập mã, lưu nó dưới dạng thực thi và chạy nó. Trong C ++, tôi phải tạo các bản dựng và tất cả những thứ thú vị khác.


4
Python chỉ là một ngôn ngữ có nhiều triển khai. Iron Python được biên dịch theo cùng một cách C # và C ++ được biên dịch, và có thể có các triển khai khác giống như vậy.
Công việc

1
C # và C ++ không được biên dịch theo cùng một cách - mặc dù bạn có thể lập luận rằng cuối cùng cả hai đều là hướng dẫn máy, nhưng nếu bạn làm vậy thì bạn có thể nói BASIC cũng được biên dịch theo cùng một cách.
gbjbaanb

7
@gbjbaanb nhưng sau đó một lần nữa tiếng Anh không được biên dịch và phân tích ngữ nghĩa của một câu có thể mang lại hai kết quả hợp lệ như nhau và ở trên có thể được đọc là "trăn sắt được biên dịch giống như C # và C ++ được biên dịch"
Rune FS

Bạn đang sử dụng nền tảng / phần mềm nào để viết mã Python? Nếu bạn viết một tệp .py, nó không phải là tệp thực thi. Nó vẫn là một tập tin mã nguồn. Từ dòng lệnh bạn đang sử dụng pythonlệnh để diễn giải tệp .py hoặc nếu bạn sử dụng IDLE hoặc Eclipse, IDE sẽ làm điều đó cho bạn.
Rick Henderson

Câu trả lời:


68

Python có một trình biên dịch! Bạn không nhận thấy nó vì nó chạy tự động. Mặc dù vậy, bạn có thể nói rằng nó ở đó: nhìn vào các tệp .pyc(hoặc .pyonếu bạn đã bật trình tối ưu hóa) được tạo cho các mô-đun mà bạn import.

Ngoài ra, nó không biên dịch thành mã của máy gốc. Thay vào đó, nó biên dịch thành mã byte được sử dụng bởi một máy ảo. Máy ảo là một chương trình được biên dịch. Điều này rất giống với cách Java hoạt động; Thực tế, tương tự như vậy, có một biến thể Python ( Jython ) biên dịch thành mã byte của Máy ảo Java! Ngoài ra còn có IronPython , trình biên dịch sang CLR của Microsoft (được sử dụng bởi .NET). (Trình biên dịch mã byte Python bình thường đôi khi được gọi là CPython để phân tán nó khỏi các lựa chọn thay thế này.)

C ++ cần phơi bày quá trình biên dịch của nó vì bản thân ngôn ngữ chưa hoàn chỉnh; nó không chỉ định mọi thứ mà trình liên kết cần biết để xây dựng chương trình của bạn và cũng không thể chỉ định các tùy chọn biên dịch một cách hợp lý (một số trình biên dịch cho phép bạn sử dụng #pragma, nhưng đó không phải là tiêu chuẩn). Vì vậy, bạn phải thực hiện phần còn lại của công việc với makefiles và có thể là auto hell (autoconf / automake / libtool). Đây thực sự chỉ là một sự tiếp quản từ cách C đã làm nó. Và C đã làm theo cách đó bởi vì nó làm cho trình biên dịch trở nên đơn giản, đó là một lý do chính khiến nó trở nên phổ biến (bất kỳ ai cũng có thể tạo ra một trình biên dịch C đơn giản trong thập niên 80).


Một số điều có thể ảnh hưởng đến hoạt động của trình biên dịch hoặc trình liên kết nhưng không được chỉ định trong cú pháp của C hoặc C ++:

  • giải quyết phụ thuộc
  • yêu cầu thư viện bên ngoài (bao gồm cả thứ tự phụ thuộc)
  • mức độ tối ưu hóa
  • cài đặt cảnh báo
  • phiên bản đặc tả ngôn ngữ
  • ánh xạ liên kết (phần nào đi đâu trong chương trình cuối cùng)
  • kiến trúc mục tiêu

Một số trong số này có thể được phát hiện, nhưng chúng không thể được chỉ định; ví dụ: tôi có thể phát hiện C ++ nào đang được sử dụng __cplusplus, nhưng tôi không thể chỉ định rằng C ++ 98 là mã được sử dụng cho mã của tôi trong chính mã; Tôi phải chuyển nó dưới dạng cờ cho trình biên dịch trong Makefile hoặc tạo một cài đặt trong hộp thoại.

Mặc dù bạn có thể nghĩ rằng hệ thống "độ phân giải phụ thuộc" tồn tại trong trình biên dịch, tự động tạo các bản ghi phụ thuộc, các bản ghi này chỉ cho biết tệp tiêu đề nào mà tệp nguồn đã cho sử dụng. Chúng không thể chỉ ra những mô-đun mã nguồn bổ sung nào được yêu cầu để liên kết vào một chương trình thực thi, bởi vì không có cách tiêu chuẩn nào trong C hoặc C ++ để chỉ ra rằng một tệp tiêu đề đã cho là định nghĩa giao diện cho một mô-đun mã nguồn khác chứ không phải chỉ là một bó các dòng bạn muốn hiển thị ở nhiều nơi để bạn không lặp lại chính mình. Có những truyền thống trong các quy ước đặt tên tệp, nhưng chúng không được biết đến hoặc được thực thi bởi trình biên dịch và trình liên kết.

Một vài trong số này có thể được thiết lập bằng cách sử dụng #pragma, nhưng điều này là không chuẩn, và tôi đã nói về tiêu chuẩn. Tất cả những điều này có thể được chỉ định bởi một tiêu chuẩn, nhưng không có lợi cho khả năng tương thích ngược. Sự khôn ngoan phổ biến là makefiles và IDE không bị hỏng, vì vậy đừng sửa chúng.

Python xử lý tất cả điều này trong ngôn ngữ. Ví dụ, importchỉ định một phụ thuộc mô-đun rõ ràng, ngụ ý cây phụ thuộc và các mô-đun không được chia thành các tệp tiêu đề và nguồn (tức là giao diện và triển khai).


3
Việc triển khai C của Python là CPython , Cython là một cái gì đó khác biệt.
Greg Hewgill

4
Các lý do khác khiến C biên dịch thành mã máy là vì nó được dự định ít hơn một trình biên dịch được tôn vinh, bởi vì các trình thông dịch mã byte không khả thi về phần cứng mà họ có và vì một trong những nhiệm vụ quan trọng nhất là viết kernel hệ điều hành.
tdammers

2
@BillyONeal với một ngoại lệ lớn là trong c / c ++, bạn với tư cách là một lập trình viên phải làm công cụ theo một cách nhất định (tạo tệp hoặc đổ mọi thứ vào cùng một blob) trong python, bạn chỉ cần thực hiện công việc của mình và trình biên dịch cùng với VM lo phần còn lại
Rune FS

3
"C ++ cần phơi bày quá trình biên dịch của nó vì bản thân ngôn ngữ chưa hoàn chỉnh" Er, cái gì ??
Cuộc đua nhẹ nhàng với Monica

3
Bạn đọc phần ngay sau đó , phải không? "nó không chỉ định mọi thứ mà trình liên kết cần biết để xây dựng chương trình của bạn, cũng như không thể chỉ định các tùy chọn biên dịch một cách hợp lý." Bạn không thể xây dựng bất kỳ tệp C ++ nào bằng cách cung cấp cho trình biên dịch; thường xuyên bạn phải cung cấp siêu dữ liệu như cờ biên dịch, bao gồm các đường dẫn, v.v. Siêu dữ liệu này không được chỉ định bởi tiêu chuẩn và không thể mang theo được, đó là lý do tại sao chúng ta phải kéo theo những thứ khác như make, cmake, Visual Studio hoặc bất cứ thứ gì để hoàn thành công việc Vì vậy, tiêu chuẩn phải gọi ra một số điều như trong đơn vị biên dịch và những thứ khác là toàn chương trình.
Mike DeSimone

7

Python là một ngôn ngữ được giải thích. Điều này có nghĩa là có phần mềm trên máy tính của bạn đọc mã Python và gửi "hướng dẫn" đến máy. Các bài viết trên Wikipedia về ngôn ngữ giải thích có thể quan tâm.

Khi một ngôn ngữ như C ++ (một ngôn ngữ được biên dịch) được biên dịch, điều đó có nghĩa là nó được chuyển đổi thành mã máy để được phần cứng đọc trực tiếp khi thực thi. Các bài viết trên Wikipedia về ngôn ngữ biên dịch có thể cung cấp một sự tương phản thú vị.


21
Không có những thứ như một ngôn ngữ được giải thích hoặc biên dịch. Một ngôn ngữ là một tập hợp trừu tượng của các quy tắc toán học. Một ngôn ngữ không được biên dịch hoặc giải thích. Một ngôn ngữ chỉ . Biên dịch và giải thích là đặc điểm của trình biên dịch hoặc trình thông dịch (duh!), Chứ không phải ngôn ngữ. Mọi ngôn ngữ có thể được thực hiện với một trình biên dịch và mọi ngôn ngữ có thể được thực hiện với một trình thông dịch. Hầu hết các ngôn ngữ có cả triển khai biên dịch và giải thích. Có trình thông dịch cho C ++ và có trình biên dịch cho Python. (Trên thực tế, tất cả các triển khai Python hiện có đều có trình biên dịch.)
Jörg W Mittag

4
Phần lớn các triển khai ngôn ngữ hiệu suất cao hiện đại kết hợp cả trình thông dịch và trình biên dịch (hoặc thậm chí một số trình biên dịch) để có hiệu suất tối đa. Trên thực tế, không thể chạy bất kỳ chương trình nào mà không có người phiên dịch. Xét cho cùng, trình biên dịch chỉ là một chương trình dịch một chương trình từ ngôn ngữ này sang ngôn ngữ khác. Nhưng đến một lúc nào đó bạn phải thực sự chạy chương trình, được thực hiện bởi một thông dịch viên (có thể hoặc không thể thực hiện bằng silicon).
Jörg W Mittag

10
@ JörgWMittag: Bạn đúng về mặt kỹ thuật. Tuy nhiên, hầu hết các ngôn ngữ được thiết kế cho một bối cảnh diễn giải hoặc để biên dịch đầy đủ. Viết một trình thông dịch cho GW BASIC hoặc Common Lisp dễ dàng hơn nhiều so với việc viết một trình thông dịch cho C ++ hoặc C #; Python mất nhiều điểm bán hàng mà không có môi trường tương tác; việc viết một trình biên dịch cho PHP khá khó khăn và có thể không hiệu quả khủng khiếp, vì trình thực thi được biên dịch sẽ phải chứa toàn bộ trình thông dịch PHP, do eval () và các cấu trúc tương tự - người ta có thể lập luận rằng trình biên dịch như vậy sẽ gian lận.
tdammers

2
@tdammers, vâng. Chúng ta có thể sử dụng hợp lý "ngôn ngữ được biên dịch" để có nghĩa là "ngôn ngữ thường được biên dịch." Nhưng điều đó bỏ lỡ quan điểm rằng PHP, Java, Python, Lua và C # đều được triển khai dưới dạng trình biên dịch thành mã byte. Tất cả các ngôn ngữ này cũng đã được JIT thực hiện cho chúng. Vì vậy, thực sự, bạn thực sự không thể gọi một số ngôn ngữ này được biên dịch và một số ngôn ngữ được giải thích vì chúng có cùng một chiến lược thực hiện.
Winston Ewert

2
@BillyONeal, không đúng với ít nhất là trăn. Bạn có thể phân phối mã trăn python và chạy mà không cần nguồn. Nhưng sự thật là bạn không thể phân phối python mà không có trình biên dịch.
Winston Ewert

5

Không phải tất cả các ngôn ngữ được biên dịch đều có chu trình chỉnh sửa-biên dịch-liên kết-chạy trong khuôn mặt của bạn.

Những gì bạn đang chạy vào là một tính năng / giới hạn của C ++ (hoặc ít nhất là triển khai C ++).

Để làm bất cứ điều gì, bạn phải lưu trữ mã của mình vào các tệp và xây dựng hình ảnh nguyên khối bằng một quá trình gọi là liên kết.

Cụ thể, đó là quá trình liên kết nguyên khối bị nhầm lẫn giữa sự phân biệt giữa biên dịch và phiên dịch.

Một số ngôn ngữ thực hiện tất cả các công cụ này linh hoạt hơn nhiều, bằng cách loại bỏ bước liên kết nguyên khối vụng về, không phải bằng cách loại bỏ biên dịch sang mã máy. Nguồn vẫn được biên dịch vào các tệp đối tượng, nhưng chúng được tải vào một hình ảnh thời gian chạy, thay vì được liên kết thành một tệp thực thi nguyên khối.

Bạn nói "tải lại mô-đun này", và nó tải nguồn và diễn giải nó, hoặc biên dịch nó, tùy thuộc vào một số chuyển đổi chế độ.

Lập trình nhân Linux có một số hương vị này mặc dù bạn đang làm việc trong C. Bạn có thể biên dịch lại một mô-đun và tải và dỡ bỏ nó. Tất nhiên, bạn vẫn nhận thức được rằng bạn đang sản xuất một số thứ có thể thực hiện được và nó được quản lý bởi một hệ thống xây dựng phức tạp, vẫn còn một số bước thủ công. Nhưng thực tế là cuối cùng bạn có thể dỡ và tải lại chỉ mô-đun nhỏ đó và không phải khởi động lại toàn bộ kernel.

Một số ngôn ngữ có mô-đun hóa hạt mịn thậm chí còn tốt hơn thế này, và việc xây dựng và tải được thực hiện từ trong thời gian chạy của chúng, vì vậy nó liền mạch hơn.


2

thật là một sự chuyển hướng từ câu hỏi ban đầu ... Một điểm không được đề cập là nguồn của chương trình python là những gì bạn sử dụng và phân phối, từ góc độ người dùng, đó là chương trình. Chúng ta có xu hướng đơn giản hóa mọi thứ thành các danh mục không được xác định rõ.

Các chương trình biên dịch thường được coi là các tệp độc lập của mã máy. (phải thừa nhận thường chứa các liên kết đến các thư viện liên kết động được liên kết với các hệ điều hành cụ thể). Điều này nói rằng ... có sự khác biệt của hầu hết các ngôn ngữ lập trình có thể được mô tả là biên dịch hoặc giải thích.

Python không cần trình biên dịch vì nó dựa vào một ứng dụng (được gọi là trình thông dịch) biên dịch và chạy mã mà không lưu mã máy được tạo ở dạng mà bạn có thể dễ dàng truy cập hoặc phân phối.


1

Tất cả các ngôn ngữ lập trình yêu cầu dịch từ các khái niệm của con người sang mã máy đích. Ngay cả ngôn ngữ lắp ráp phải được dịch sang mã máy. Bản dịch đó thường diễn ra trong các giai đoạn sau:

Giai đoạn 1: Phân tích và dịch (phân tích cú pháp) thành một mã trung gian. Giai đoạn 2: Dịch mã trung gian thành mã máy đích với giá đỡ địa điểm để tham chiếu bên ngoài. Giai đoạn 3: Phân giải các tham chiếu bên ngoài và đóng gói thành một chương trình thực thi máy.

Bản dịch này thường được gọi là biên dịch trước và "Chỉ trong thời gian" (JIT) hoặc biên dịch theo thời gian.

Các ngôn ngữ như C, C ++, COBOL, Fortran, Pascal (không phải tất cả) và hội là những ngôn ngữ được biên dịch sẵn có thể được hệ thống xử lý trực tiếp thực hiện mà không cần thông dịch viên.

Các ngôn ngữ như Java, BASIC, C # và Python được diễn giải. Tất cả đều sử dụng mã trung gian được tạo trong Giai đoạn 1, nhưng đôi khi sẽ khác nhau về cách họ dịch mã thành mã máy. Các biểu mẫu đơn giản nhất sử dụng mã trung gian đó để thực hiện các thói quen mã máy thực hiện công việc mong đợi. Những người khác sẽ biên dịch mã trung gian xuống mã máy và thực hiện sửa lỗi phụ thuộc bên ngoài trong thời gian chạy. Sau khi biên dịch nó có thể được thực hiện ngay lập tức. Cũng như mã máy được lưu trữ trong bộ đệm của mã máy tái sử dụng được biên dịch trước đó, sau này có thể được sử dụng lại nếu chức năng này được sử dụng lại sau đó. Nếu một chức năng đã được lưu vào bộ đệm, trình thông dịch không cần phải biên dịch lại.

Hầu hết các ngôn ngữ cấp cao hiện đại đều thuộc danh mục được giải thích (với JIT). Nó chủ yếu là các ngôn ngữ cũ như C & C ++ được biên dịch trước.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.