Nếu Python được diễn giải, các tệp .pyc là gì?


1084

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 .pyccá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?


3
Xem stackoverflow.com/questions/11433579/ cho sự biện minh. Trong một từ: tốc độ.
user7610



Điều đó có nghĩa là ngay cả con trăn cũng có 'Viết một lần, chạy mọi nơi' giống như Java.?
Mrak Vladar

2
@MrakVladar Ngay cả Java là "Viết một lần, chạy bất cứ nơi nào [mà bạn có JVM]". Python không khác nhau; đó là "chạy bất cứ nơi nào bạn có máy ảo Python". Sự khác biệt lớn là hầu hết các triển khai Python kết hợp trình biên dịch và trình thông dịch thành một tệp thực thi, thay vì tách chúng ra như javajavac.
chepner

Câu trả lời:


660

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.


10
Thú vị, cảm ơn. Vì vậy, Python được coi là một ngôn ngữ hoàn toàn giải thích?
froadie

194
@froadie: một ngôn ngữ không được "diễn giải" hoặc "biên dịch" như vậy. Một triển khai cụ thể có thể là trình thông dịch hoặc trình biên dịch (hoặc trình biên dịch lai hoặc trình biên dịch JIT).
Joachim Sauer

30
Một thử nghiệm của 'được biên dịch': nó có được biên dịch theo hướng dẫn máy thực tế không? Mã byte của Python không phải là hướng dẫn máy và cũng không phải là hướng dẫn 'JVM' của Java, vì vậy cả hai ngôn ngữ này đều không được biên dịch theo định nghĩa đó. Nhưng cả hai 'được biên dịch' thành mã 'máy trừu tượng' trung gian và cả hai đều nhanh hơn nhiều so với việc chạy chương trình bằng cách ít nhiều trực tiếp giải thích mã nguồn (đó là điều BASIC trường học cũ làm).
greggo

20
Để được mô phạm, 'biên dịch' có nghĩa là 'dịch'. Python sau đó được biên dịch thành mã byte. AFAIK, chỉ Bash thực sự được giải thích, tất cả các ngôn ngữ "được giải thích" phổ biến khác đều được biên dịch thành mã byte.
bfontaine

13
Trên thực tế, chúng là các hướng dẫn máy, không phải là hướng dẫn máy gốc cho CPU vật lý của máy chủ. Do đó tại sao chúng ta gọi nó là VM? Giống như Esperanto cho ngôn ngữ lắp ráp thực sự. Ngày nay, chúng ta thậm chí còn có mã riêng cho CPU hư cấu (nhưng vẫn được mô phỏng) (nỗ lực của Mojang để khiến những đứa trẻ quan tâm). Rexx đã (hoặc có thể) thực sự được giải thích, và BAT và CMD (và DCL) được diễn giải.
mckenzm

994

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 .classtiệ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,


2
Câu trả lời đẹp. Chỉ cần một chỉnh sửa nhỏ cho đoạn cuối: Python được thiết kế để biên dịch nhanh nhất có thể (v.v.). Lần này nó thực sự là ngôn ngữ, với việc thiếu hệ thống và công cụ tĩnh. Khi mọi người nói về ngôn ngữ "diễn giải", họ thường có nghĩa là ngôn ngữ "động".
Elazar

1
@Elazar, trên thực tế, các triển khai khác của Python, chẳng hạn như PyPy, không vội biên dịch, quản lý để thực hiện phân tích kỹ lưỡng hơn do thiếu gõ tĩnh và tạo ra trình biên dịch đúng lúc cho mã máy (do đó tăng tốc lên chương trình dài hạn nhiều lần).
Alex Martelli

Cython phù hợp ở đâu? Bạn sẽ coi nó là một ngôn ngữ khác hay nó là một triển khai Python? Ngoài ra, có phải meme của "phiên dịch" so với được biên dịch có lẽ chỉ là một sự nhầm lẫn thuật ngữ bởi vì VM của Python thường được gọi là "trình thông dịch" của nó? Sẽ là hợp lệ nếu gọi trình thông dịch JVM hoặc .NET runtime. Cả hai chủ yếu diễn giải mã byte thành mã máy JIT (với một số ngoại lệ tối ưu hóa bộ đệm)
Davos

181

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:

  • IronPython: biên dịch thành các cây DLR mà DLR sau đó biên dịch thành mã byte CIL. Điều gì xảy ra với mã byte CIL phụ thuộc vào CLI VES mà bạn đang chạy, nhưng Microsoft .NET, GNU Portable.NET và Novell Mono cuối cùng sẽ biên dịch nó thành mã máy gốc.
  • Jython: diễn giải mã nguồn Python cho đến khi nó xác định các đường dẫn mã nóng, sau đó nó sẽ biên dịch thành mã byte JVML. Điều gì xảy ra với mã byte JVML phụ thuộc vào JVM mà bạn đang chạy. Maxine sẽ trực tiếp biên dịch nó thành mã gốc chưa được tối ưu hóa cho đến khi xác định được các đường dẫn mã nóng, sau đó nó sẽ biên dịch lại thành mã gốc được tối ưu hóa. Đầu tiên, HotSpot sẽ diễn giải mã byte JVML và sau đó biên dịch các đường dẫn mã nóng thành mã máy được tối ưu hóa.
  • PyPy: biên dịch thành mã byte PyPy, sau đó được PyPy VM giải thích cho đến khi nó xác định các đường dẫn mã nóng mà sau đó nó biên dịch thành mã gốc, mã byte JVML hoặc mã byte CIL tùy thuộc vào nền tảng bạn đang chạy.
  • CPython: biên dịch thành mã byte CPython mà sau đó nó diễn giải.
  • Stackless Python: biên dịch thành mã byte CPython mà sau đó nó diễn giải.
  • Unladen Swallow: biên dịch thành mã byte CPython mà sau đó nó diễn giải cho đến khi nó xác định các đường dẫn mã nóng mà sau đó nó biên dịch thành LLVM IR mà trình biên dịch LLVM sau đó biên dịch thành mã máy gốc.
  • Cython: biên dịch mã Python thành mã C di động, sau đó được biên dịch với trình biên dịch C tiêu chuẩn
  • Nuitka: biên dịch mã Python thành mã C ++ phụ thuộc vào máy, sau đó được biên dịch với trình biên dịch C tiêu chuẩn

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 .pyctệ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.


5
Cơ bản trường học cũ như MSBASIC không có hình thức trung gian. Chương trình được giải thích trực tiếp từ dạng nguồn (hoặc gần nguồn, một dạng trong đó các từ khóa được biểu thị bằng mã thông báo 1 byte và dòng # của các số nhị phân 2 byte, nhưng phần còn lại chỉ là ASCII). Vì vậy, trên thực tế, một 'goto' sẽ mất nhiều thời gian khác nhau tùy thuộc vào số lượng dòng nguồn mà nó phải tìm kiếm thông qua việc tìm kiếm điểm đến phù hợp. Các biểu thức như * b-2 * cos (x) được phân tích lại một cách hiệu quả mỗi khi chúng được thực thi.
greggo

4
@greggo: Và nếu bạn muốn đi học cũ hơn nữa, phiên bản gốc của BASIC là trình biên dịch mã gốc. Điều này sẽ chứng minh khái niệm của một ngôn ngữ "được biên dịch" hoặc "diễn giải" kỳ cục đến mức nào.
Jörg W Mittag

Cảm ơn đã giải thích cách các trình biên dịch / phiên dịch python khác nhau hoạt động. Tôi tự hỏi nếu có trình biên dịch Python tốt tạo ra C hoặc JavaScript hiệu quả chưa. Có vẻ như rất khả thi, có thể không phải để tiêu thụ hàng loạt, nhưng ít nhất là cho một tập hợp con Python hợp lý. Ngoài ra tôi tự hỏi Cython là gì.
Personal_cloud

Cython đã được đề cập trong SciPy 2009, nhưng tôi có thể tha thứ cho bạn vì đã không biết về nó vào năm 2010 (ở đây tôi năm 2017 chỉ mới tìm hiểu về nó). Tuy nhiên, chúng ta vẫn phải tìm một ví dụ JavaScript ... Jython không có ý nghĩa gì với tôi (không phải Java đã chết vào năm 2009 phải không? Chà, có lẽ không ... C ++ boost không tốt lắm rồi)
Personal_cloud

1
@personal_cloud: Tôi không theo dõi bình luận của bạn. Vâng, tất nhiên, tôi biết về Cython, nhưng điều đó có liên quan gì? Đây không phải là một triển khai của Python, nó là một ngôn ngữ hoàn toàn khác. Ngoài ra, thực sự không khó để tìm thấy một ví dụ JavaScript, trên thực tế, tất cả các triển khai JavaScript chính hiện tại đều có trình biên dịch. Cuối cùng, Jython là một triển khai Python giống như bất kỳ triển khai Python nào khác. Và nó là một triển khai ngôn ngữ trên nền tảng Java giống như bất kỳ ngôn ngữ nào khác trên nền tảng Java.
Jörg W Mittag

61

Chúng được tạo bởi trình thông dịch Python khi một .pytệ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 importnếu tệp .pycmới hơn .pytệ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.


10
Thật. Ngoại trừ nhiều thư viện Python lõi được viết bằng C. Vì vậy, các phần của python chạy được diễn giải, một phần chạy trong C. Bạn có thể làm tương tự với các đoạn mã nhạy cảm về hiệu năng của chính bạn.
bwawok

44

Để 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:

nhập mô tả hình ảnh ở đây

Để biết thêm thông tin:

ref: PEP3147
ref: Phần mềm biên dịch tập tin Python Python


38

ĐÂ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_compilecompileall.

Các py_compilemô-đun có thể tự biên dịch bất kỳ mô-đun. Một cách là sử dụng py_compile.compilechứ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


6
và lợi ích của việc biên dịch để có được abc.py là gì?
Saher Ahwal

@SaherAhwal Một lợi ích tôi có thể nghĩ đến là kiểm tra cú pháp.
Yi Bao

20

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 ...


12

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.


7

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.

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.