Khi nào các tệp .pyc được làm mới?


91

Tôi hiểu rằng tệp ".pyc" là phiên bản được biên dịch của tệp ".py" văn bản thuần túy, được tạo trong thời gian chạy để làm cho chương trình chạy nhanh hơn. Tuy nhiên, tôi đã quan sát thấy một số điều:

  1. Sau khi sửa đổi tệp "py", hành vi của chương trình sẽ thay đổi. Điều này cho thấy rằng các tệp "py" được biên dịch hoặc ít nhất là trải qua một số loại quy trình băm hoặc so sánh các dấu thời gian để cho biết liệu chúng có nên được biên dịch lại hay không.
  2. Khi xóa tất cả các tệp ".pyc" ( rm *.pyc), đôi khi hành vi của chương trình sẽ thay đổi. Điều này cho thấy rằng chúng không được biên dịch khi cập nhật ".py" s.

Câu hỏi:

  • Làm thế nào để họ quyết định khi nào được biên dịch?
  • Có cách nào để đảm bảo rằng họ được kiểm tra chặt chẽ hơn trong quá trình phát triển không?

14
Cẩn thận với việc xóa tệp .pyc với rm *.pyc. Thao tác này sẽ không xóa các tệp .pyc trong các thư mục lồng nhau. Sử dụng find . -name '*.pyc' -deletethay thế
Zags

6
Có lẽ một lưu ý cho câu hỏi của bạn: Một chương trình không chạy nhanh hơn bất kỳ khi nó được đọc từ tệp '.pyc' hoặc '.pyo' so với khi nó được đọc từ tệp '.py'; điều duy nhất nhanh hơn về các tệp '.pyc' hoặc '.pyo' là tốc độ tải chúng. liên kết
maggie

@maggie sự khác biệt giữa thời gian tải và thời gian thực thi là gì?
Daniel Springer

3
@Dani tải là thời gian cần thiết để đọc và sau đó biên dịch chương trình. Thời gian thực thi là khi chương trình thực sự đang được chạy, xảy ra sau khi tải. Nếu bạn muốn mang tính kỹ thuật, các loại thời gian là thời gian tải, thời gian biên dịch, thời gian liên kết và thời gian thực hiện. Tạo .pyc loại bỏ phần thời gian biên dịch.
Eric Klien

@EricKlien cảm ơn anh bạn
Daniel Springer

Câu trả lời:


79

Các .pyctệp chỉ được tạo (và có thể bị ghi đè) khi tệp python đó được nhập bởi một số tập lệnh khác. Nếu quá trình nhập được gọi, Python sẽ kiểm tra xem .pycdấu thời gian bên trong của tệp có cũ hơn .pytệp tương ứng hay không . Nếu có, nó sẽ tải .pyc; nếu nó không có hoặc nếu .pycnó chưa tồn tại, Python sẽ biên dịch .pytệp thành một.pyc và tải nó.

Ý bạn là gì khi "kiểm tra chặt chẽ hơn"?


3
Tôi có thể khắc phục sự cố với rm *.pyc. Tôi biết rằng nếu tôi buộc tất cả các tệp phải được tạo lại thì một số sự cố đã được khắc phục, cho thấy rằng các tệp không được biên dịch lại. Tôi cho rằng nếu họ sử dụng dấu thời gian thì không có cách nào để làm cho hành vi này nghiêm ngặt hơn, nhưng vấn đề vẫn còn tồn tại.
Aaron Schif

13
Điều này không hoàn toàn chính xác. Các dấu thời gian không cần phải khớp (và chúng thường không khớp). Các .pyc's timestamp phải lớn tuổi hơn tương ứng .pycủa dấu thời gian để kích hoạt một biên dịch lại.
Tim Pietzcker

4
@Aaron, Bạn có thể thay đổi các tệp .py và trong quá trình này làm cho chúng cũ hơn (ví dụ: bằng cách sao chép chúng từ một dir khác, sử dụng một thao tác bảo toàn 'thời gian sửa đổi') không?
greggo

1
@greggo, tôi đang sử dụng git và cập nhật từ một kho lưu trữ, vì vậy theo một cách nào đó thì tôi cũng vậy. Điều đó có thể làm được. Cảm ơn.
Aaron Schif

1
Tốt để biết. Làm thế nào về việc sửa câu trả lời của bạn sau đó?
Piotr Dobrogost

29

Các tệp .pyc được tạo bất cứ khi nào các phần tử mã tương ứng được nhập và được cập nhật nếu các tệp mã tương ứng đã được cập nhật. Nếu các tệp .pyc bị xóa, chúng sẽ tự động được tạo lại. Tuy nhiên, chúng không tự động bị xóa khi các tệp mã tương ứng bị xóa.

Điều này có thể gây ra một số lỗi thực sự thú vị trong quá trình tái cấu trúc cấp tệp.

Trước hết, bạn có thể kết thúc việc đẩy mã chỉ hoạt động trên máy của bạn chứ không phải của ai khác. Nếu bạn có các tham chiếu lơ lửng đến các tệp bạn đã xóa, những tệp này sẽ vẫn hoạt động cục bộ nếu bạn không xóa các tệp .pyc có liên quan theo cách thủ công vì tệp .pyc có thể được sử dụng trong quá trình nhập. Điều này kết hợp với thực tế là hệ thống kiểm soát phiên bản được định cấu hình đúng sẽ chỉ đẩy tệp .py vào kho lưu trữ trung tâm, không phải tệp .pyc, có nghĩa là mã của bạn có thể vượt qua "kiểm tra nhập" (mọi thứ nhập đều ổn). làm việc trên máy tính của người khác.

Thứ hai, bạn có thể gặp một số lỗi khá khủng khiếp nếu bạn biến các gói thành mô-đun. Khi bạn chuyển đổi một gói (một thư mục có __init__.pytệp) thành một mô-đun (tệp .py), các tệp .pyc đã từng đại diện cho gói đó vẫn còn. Đặc biệt, __init__.pychài cốt. Vì vậy, nếu bạn có gói foo với một số mã không quan trọng, sau đó hãy xóa gói đó và tạo tệp foo.py với một số chức năng def bar(): passvà chạy:

from foo import bar

bạn lấy:

ImportError: cannot import name bar

vì python vẫn đang sử dụng các tệp .pyc cũ từ gói foo, không có thanh định nghĩa nào trong số đó. Điều này có thể đặc biệt có vấn đề trên một máy chủ web, nơi mã hoạt động hoàn toàn có thể bị hỏng do tệp .pyc.

Do cả hai lý do này (và có thể cả những lý do khác), mã triển khai và mã thử nghiệm của bạn sẽ xóa các tệp .pyc, chẳng hạn như với dòng bash sau:

find . -name '*.pyc' -delete

Ngoài ra, kể từ python 2.6, bạn có thể chạy python với -Bcờ để không sử dụng tệp .pyc. Xem Cách tránh tệp .pyc? để biết thêm chi tiết.

Xem thêm: Làm cách nào để xóa tất cả các tệp .pyc khỏi một dự án?


"Khi bạn chuyển đổi một mô-đun (một thư mục có __init__.pytệp) ...". Đó sẽ là một gói, không phải một mô-đun.
Robert David Grant

2
Đặc biệt, __init__.pychài cốt. - Làm thế nào mà? Là một gói là một thư mục xóa một thư mục phương tiện gói xóa do đó không có tập tin còn lại ...
Piotr Dobrogost

3
@PiotrDobrogost Kiểm soát nguồn được quản lý thích hợp liên quan đến việc không kiểm tra các tệp pyc của bạn vào nguồn. Vì vậy, mặc dù bạn có thể xóa thư mục, bao gồm các tệp pyc, trong bản sao cục bộ của mình, nó sẽ không bị xóa đối với người khác thực hiện thao tác kéo git. Điều này có thể làm hỏng máy chủ của bạn nếu quá trình triển khai của bạn cũng liên quan đến kéo git.
Zags

Có nhiều lý do để không tin tưởng môi trường phát triển của bạn là đại diện cho nơi mã của bạn sẽ được triển khai. Đây .pycvấn đề là một lý do, cũng: phụ thuộc ẩn trên hệ điều hành và vá tiện ích cấp, .socác file, các file cấu hình, libs Python khác (nếu bạn không chạy trong một env ảo), env che khuất vars ... danh sách đi về. Để xem xét kỹ lưỡng và tìm thấy tất cả các vấn đề như vậy, bạn cần tạo một bản sao mã sạch của mình trong git repo hoặc xuất bản dưới dạng gói lên máy chủ kiểu PyPi và thực hiện sao chép hoặc thiết lập đầy đủ trên một máy ảo mới. Một số vấn đề tiềm ẩn làm cho vấn đề này trở nên .pycnhạt nhoà khi so sánh.
Chris Johnson
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.