Tôi đã được hiểu rằng Python là ngôn ngữ được dịch ...
Tuy nhiên, khi tôi nhìn vào mã nguồn Python của mình, tôi thấy .pyc
các tệp mà Windows xác định là "Tệp Python đã biên dịch".
Những thứ này đi vào đâu?
java
và javac
.
Tôi đã được hiểu rằng Python là ngôn ngữ được dịch ...
Tuy nhiên, khi tôi nhìn vào mã nguồn Python của mình, tôi thấy .pyc
các tệp mà Windows xác định là "Tệp Python đã biên dịch".
Những thứ này đi vào đâu?
java
và javac
.
Câu trả lời:
Chúng chứa mã byte , đó là những gì trình thông dịch Python biên dịch nguồn thành. Mã này sau đó được thực thi bởi máy ảo của Python.
Tài liệu của Python giải thích định nghĩa như thế này:
Python là một ngôn ngữ được giải thích, trái ngược với ngôn ngữ được biên dịch, mặc dù sự khác biệt có thể bị mờ vì sự hiện diện của trình biên dịch mã byte. Điều này có nghĩa là các tệp nguồn có thể được chạy trực tiếp mà không tạo rõ ràng một tệp thực thi được chạy.
Tôi đã được hiểu rằng Python là một ngôn ngữ được dịch ...
Meme phổ biến này là không chính xác, hoặc, đúng hơn, được xây dựng dựa trên sự hiểu lầm về trình độ ngôn ngữ (tự nhiên): một sai lầm tương tự sẽ là "Kinh thánh là một cuốn sách bìa cứng". Hãy để tôi giải thích rằng simile ...
"Kinh thánh" là "một cuốn sách" theo nghĩa là một lớp (các vật thể thực tế, được xác định là); những cuốn sách được xác định là "bản sao của Kinh Thánh" được cho là có điểm chung cơ bản (nội dung, mặc dù những cuốn sách này có thể bằng các ngôn ngữ khác nhau, với các bản dịch khác nhau, mức độ chú thích và chú thích khác) - tuy nhiên, những cuốn sách đó là hoàn toàn tốt cho phép khác nhau trong vô số các khía cạnh không được coi là cơ bản - loại ràng buộc, màu của ràng buộc, phông chữ được sử dụng trong in ấn, minh họa nếu có, lề có thể ghi rộng hay không, số và loại dấu trang dựng sẵn , Vân vân và vân vân.
Rất có khả năng một bản in điển hình của Kinh thánh thực sự sẽ được đóng bìa cứng - xét cho cùng, đó là một cuốn sách thường được đọc đi đọc lại, đánh dấu ở một vài nơi, xem qua việc tìm kiếm những gợi ý về chương và câu. , v.v., và một ràng buộc bìa cứng tốt có thể làm cho một bản sao nhất định tồn tại lâu hơn trong quá trình sử dụng đó. Tuy nhiên, đây là những vấn đề trần tục (thực tế) không thể được sử dụng để xác định xem một đối tượng sách thực tế nhất định có phải là bản sao của Kinh Thánh hay không: bản in bìa mềm là hoàn toàn có thể!
Tương tự, Python là "một ngôn ngữ" theo nghĩa là xác định một lớp triển khai ngôn ngữ , tất cả đều phải giống nhau ở một số khía cạnh cơ bản (cú pháp, hầu hết các ngữ nghĩa ngoại trừ những phần mà chúng được phép rõ ràng khác nhau) nhưng được phép hoàn toàn khác nhau về mọi chi tiết "triển khai" - bao gồm cả cách chúng xử lý các tệp nguồn mà chúng được cung cấp, liệu chúng có biên dịch các nguồn thành một số biểu mẫu cấp thấp hơn không (và nếu vậy, hình thức nào - và liệu chúng có lưu như vậy không các biểu mẫu được biên dịch, vào đĩa hoặc ở nơi khác), cách chúng thực thi các biểu mẫu đã nói, v.v.
Việc triển khai cổ điển, CPython, thường được gọi ngắn gọn là "Python" - nhưng nó chỉ là một trong một số triển khai chất lượng sản xuất, song song với IronPython của Microsoft (biên dịch thành mã CLR, tức là ".NET"), Jython (biên dịch thành mã JVM), PyPy (được viết bằng chính Python và có thể biên dịch thành rất nhiều dạng "back-end" bao gồm cả ngôn ngữ máy được tạo ra "chỉ trong thời gian"). Tất cả đều là Python (== "triển khai ngôn ngữ Python") giống như nhiều đối tượng sách khác nhau bề ngoài đều có thể là Kinh thánh (== "bản sao của Kinh thánh").
Nếu bạn quan tâm đến CPython một cách cụ thể: nó biên dịch các tệp nguồn thành một dạng cấp thấp hơn dành riêng cho Python (được gọi là "mã byte"), sẽ tự động thực hiện khi cần (khi không có tệp mã byte tương ứng với tệp nguồn hoặc tệp mã byte cũ hơn nguồn hoặc được biên dịch bởi một phiên bản Python khác), thường lưu tệp tệp mã byte vào đĩa (để tránh biên dịch lại chúng trong tương lai). OTOH IronPython thường sẽ biên dịch thành mã CLR (lưu chúng vào đĩa hay không, tùy theo) và Jython thành mã JVM (lưu chúng vào đĩa hay không - nó sẽ sử dụng .class
tiện ích mở rộng nếu nó lưu chúng).
Các biểu mẫu mức thấp hơn này sau đó được thực thi bởi các "máy ảo" thích hợp còn được gọi là "trình thông dịch" - máy ảo CPython, thời gian chạy .Net, máy ảo Java (còn gọi là JVM), nếu phù hợp.
Vì vậy, theo nghĩa này (việc triển khai điển hình làm gì), Python là "ngôn ngữ được dịch" nếu và chỉ khi C # và Java là: tất cả chúng đều có chiến lược triển khai điển hình là tạo mã byte trước, sau đó thực thi nó thông qua VM / trình thông dịch .
Nhiều khả năng tập trung vào quá trình biên soạn "nặng", chậm và cao. CPython được thiết kế để biên dịch nhanh nhất có thể, càng nhẹ càng tốt, càng ít lễ càng khả thi - trình biên dịch thực hiện rất ít kiểm tra và tối ưu hóa lỗi, do đó, nó có thể chạy nhanh và trong một lượng nhỏ bộ nhớ, do đó cho phép nó được chạy tự động và minh bạch bất cứ khi nào cần, mà không cần người dùng thậm chí cần phải biết rằng có một quá trình biên dịch đang diễn ra, hầu hết thời gian. Java và C # thường chấp nhận nhiều công việc hơn trong quá trình biên dịch (và do đó không thực hiện biên dịch tự động) để kiểm tra lỗi kỹ hơn và thực hiện nhiều tối ưu hóa hơn. Đó là sự liên tục của vảy xám, không phải là tình huống đen hay trắng,
Không có thứ gọi là ngôn ngữ diễn giải. Cho dù một trình thông dịch hay trình biên dịch được sử dụng hoàn toàn là một đặc điểm của việc triển khai và hoàn toàn không có gì để làm với ngôn ngữ.
Mỗi ngôn ngữ có thể được thực hiện bởi trình thông dịch hoặc trình biên dịch. Phần lớn các ngôn ngữ có ít nhất một triển khai của từng loại. (Ví dụ: có trình thông dịch cho C và C ++ và có trình biên dịch cho JavaScript, PHP, Perl, Python và Ruby.) Bên cạnh đó, phần lớn các triển khai ngôn ngữ hiện đại thực sự kết hợp cả trình thông dịch và trình biên dịch (hoặc thậm chí nhiều trình biên dịch).
Một ngôn ngữ chỉ là một tập hợp các quy tắc toán học trừu tượng. Thông dịch viên là một trong một số chiến lược thực hiện cụ thể cho một ngôn ngữ. Hai người đó sống ở mức độ trừu tượng hoàn toàn khác nhau. Nếu tiếng Anh là ngôn ngữ được gõ, thuật ngữ "ngôn ngữ được dịch" sẽ là lỗi loại. Câu lệnh "Python là ngôn ngữ được dịch" không chỉ sai (vì sai sẽ ngụ ý rằng câu lệnh thậm chí còn có ý nghĩa, ngay cả khi nó sai), nó chỉ đơn giản là không có nghĩa , bởi vì một ngôn ngữ không bao giờ có thể được định nghĩa là "giải thích."
Cụ thể, nếu bạn xem các triển khai Python hiện có, đây là các chiến lược triển khai mà chúng đang sử dụng:
Bạn có thể nhận thấy rằng mỗi một trong những triển khai trong danh sách đó (cộng với một số khác mà tôi không đề cập đến, như tinypy, Shed leather hoặc Psyco) đều có trình biên dịch. Trong thực tế, theo như tôi biết, hiện tại không có triển khai Python nào được hiểu hoàn toàn, không có kế hoạch triển khai nào như vậy và chưa bao giờ có một triển khai như vậy.
Không chỉ thuật ngữ "ngôn ngữ được giải thích" không có ý nghĩa, ngay cả khi bạn diễn giải nó có nghĩa là "ngôn ngữ với việc thực hiện được diễn giải", rõ ràng nó không đúng. Bất cứ ai nói với bạn điều đó, rõ ràng là không biết anh ta đang nói về cái gì.
Cụ thể, các .pyc
tệp bạn đang thấy là các tệp mã byte được lưu trong bộ nhớ cache được tạo bởi CPython, Stackless Python hoặc Unladen Swallow.
Chúng được tạo bởi trình thông dịch Python khi một .py
tệp được nhập và chúng chứa "mã byte được biên dịch" của mô-đun / chương trình đã nhập, ý tưởng là "dịch" từ mã nguồn sang mã byte (chỉ cần thực hiện một lần) có thể được bỏ qua trong các lần tiếp theo import
nếu tệp .pyc
mới hơn .py
tệp tương ứng , do đó tăng tốc khởi động một chút. Nhưng nó vẫn được giải thích.
Để tăng tốc độ tải các mô-đun, Python lưu trữ nội dung đã biên dịch của các mô-đun trong .pyc.
CPython biên dịch mã nguồn của nó thành "mã byte" và vì lý do hiệu năng, nó lưu mã byte này trên hệ thống tệp bất cứ khi nào tệp nguồn thay đổi. Điều này làm cho việc tải các mô-đun Python nhanh hơn nhiều vì giai đoạn biên dịch có thể được bỏ qua. Khi tệp nguồn của bạn là foo.py, CPython lưu mã byte trong tệp foo.pyc ngay bên cạnh nguồn.
Trong python3, máy móc nhập của Python được mở rộng để ghi và tìm kiếm các tệp bộ đệm mã byte trong một thư mục bên trong mỗi thư mục gói Python. Thư mục này sẽ được gọi là __pycache__.
Dưới đây là biểu đồ mô tả cách các mô-đun được tải:
Để biết thêm thông tin:
ref: PEP3147
ref: Phần mềm biên dịch tập tin Python Python
ĐÂY LÀ CHO NGƯỜI BẮT ĐẦU,
Python tự động biên dịch tập lệnh của bạn thành mã được biên dịch, được gọi là mã byte, trước khi chạy nó.
Chạy tập lệnh không được coi là nhập và không có .pyc sẽ được tạo.
Ví dụ: nếu bạn có tệp tập lệnh abc.py nhập mô-đun xyz.py khác , khi bạn chạy abc.py , xyz.pyc sẽ được tạo vì xyz được nhập, nhưng không có tệp abc.pyc nào được tạo kể từ abc. py không được nhập khẩu.
Nếu bạn cần tạo tệp .pyc cho mô-đun không được nhập, bạn có thể sử dụng mô-đun py_compile
và compileall
.
Các py_compile
mô-đun có thể tự biên dịch bất kỳ mô-đun. Một cách là sử dụng py_compile.compile
chức năng trong mô-đun đó một cách tương tác:
>>> import py_compile
>>> py_compile.compile('abc.py')
Điều này sẽ ghi .pyc vào cùng vị trí với abc.py (bạn có thể ghi đè lên đó bằng tham số tùy chọn cfile
).
Bạn cũng có thể tự động biên dịch tất cả các tệp trong một thư mục hoặc thư mục bằng cách sử dụng mô đun compileall.
python -m compileall
Nếu tên thư mục (thư mục hiện tại trong ví dụ này) bị bỏ qua, mô-đun sẽ biên dịch mọi thứ tìm thấy trên sys.path
Python (ít nhất là cách triển khai phổ biến nhất của nó) tuân theo mô hình biên dịch nguồn gốc thành mã byte, sau đó diễn giải mã byte trên máy ảo. Điều này có nghĩa (một lần nữa, việc thực hiện phổ biến nhất) không phải là trình thông dịch thuần túy hay trình biên dịch thuần túy.
Tuy nhiên, mặt khác của quá trình biên dịch này hầu hết bị ẩn - các tệp .pyc về cơ bản được xử lý như một bộ đệm; họ tăng tốc mọi thứ, nhưng bạn thường không cần phải biết về chúng. Nó tự động vô hiệu hóa và tải lại chúng (biên dịch lại mã nguồn) khi cần thiết dựa trên tem ngày / giờ của tệp.
Về lần duy nhất tôi gặp vấn đề với điều này là khi một tệp mã byte được biên dịch bằng cách nào đó có dấu thời gian trong tương lai, điều đó có nghĩa là nó luôn trông mới hơn tệp nguồn. Vì nó trông mới hơn, tệp nguồn không bao giờ được biên dịch lại, vì vậy cho dù bạn có thay đổi gì đi nữa, chúng vẫn bị bỏ qua ...
Tệp * .py của Python chỉ là một tệp văn bản trong đó bạn viết một số dòng mã. Khi bạn cố gắng thực thi tệp này bằng cách sử dụng nói "python filename.py"
Lệnh này gọi Python Virtual Machine. Python Virtual Machine có 2 thành phần: "trình biên dịch" và "trình thông dịch". Trình thông dịch không thể đọc trực tiếp văn bản trong tệp * .py, do đó, văn bản này trước tiên được chuyển đổi thành mã byte được nhắm mục tiêu đến PVM (không phải phần cứng mà là PVM) . PVM thực thi mã byte này. Tệp * .pyc cũng được tạo, như là một phần của việc chạy tệp thực hiện thao tác nhập của bạn trên tệp trong shell hoặc trong một số tệp khác.
Nếu tệp * .pyc này đã được tạo thì mỗi lần bạn chạy / thực thi tệp * .py tiếp theo, hệ thống sẽ tải trực tiếp tệp * .pyc của bạn mà không cần bất kỳ trình biên dịch nào (Điều này sẽ giúp bạn tiết kiệm một số chu kỳ xử lý của máy).
Khi tệp * .pyc được tạo, không cần tệp * .py, trừ khi bạn chỉnh sửa tệp.
Mã Python trải qua 2 giai đoạn. Bước đầu tiên biên dịch mã thành các tệp .pyc thực sự là mã byte. Sau đó, tệp .pyc này (mã byte) được diễn giải bằng trình thông dịch CPython. Vui lòng tham khảo liên kết này . Ở đây quá trình biên dịch và thực thi mã được giải thích bằng các thuật ngữ dễ dàng.