ไฟล์. pyc จะรีเฟรชเมื่อใด


92

ฉันเข้าใจว่าไฟล์ ".pyc" เป็นไฟล์ ".py" เวอร์ชันคอมไพล์ซึ่งสร้างขึ้นที่รันไทม์เพื่อให้โปรแกรมทำงานได้เร็วขึ้น อย่างไรก็ตามฉันสังเกตเห็นบางสิ่ง:

  1. เมื่อแก้ไขไฟล์ "py" พฤติกรรมของโปรแกรมจะเปลี่ยนไป สิ่งนี้บ่งชี้ว่าไฟล์ "py" ได้รับการคอมไพล์แล้วหรืออย่างน้อยก็ผ่านกระบวนการแฮชบางประเภทหรือเปรียบเทียบการประทับเวลาเพื่อที่จะบอกได้ว่าควรจะคอมไพล์ใหม่
  2. เมื่อลบไฟล์ ".pyc" ทั้งหมด ( rm *.pyc) บางครั้งพฤติกรรมของโปรแกรมจะเปลี่ยนไป ซึ่งจะแสดงว่าไม่มีการคอมไพล์ในการอัปเดต ".py"

คำถาม:

  • พวกเขาตัดสินใจอย่างไรเมื่อจะรวบรวม?
  • มีวิธีตรวจสอบที่เข้มงวดมากขึ้นในระหว่างการพัฒนาหรือไม่?

15
ระวังการลบไฟล์rm *.pyc. pyc ด้วย. การดำเนินการนี้จะไม่ลบไฟล์. pyc ในโฟลเดอร์ที่ซ้อนกัน ใช้find . -name '*.pyc' -deleteแทน
Zags

6
อาจจะมีข้อสังเกตหนึ่งในคำถามของคุณ: โปรแกรมจะไม่ทำงานเร็วขึ้นเมื่ออ่านจากไฟล์ ".pyc" หรือ ".pyo" มากกว่าเมื่ออ่านจากไฟล์ ".py" สิ่งเดียวที่เร็วกว่าเกี่ยวกับไฟล์ ".pyc" หรือ ".pyo" คือความเร็วในการโหลดไฟล์ ลิงค์
maggie

@maggie เวลาในการโหลดและเวลาดำเนินการต่างกันอย่างไร?
Daniel Springer

3
@Dani loading คือเวลาที่ใช้ในการอ่านและคอมไพล์โปรแกรม เวลาดำเนินการคือเวลาที่โปรแกรมกำลังทำงานจริงซึ่งเกิดขึ้นหลังจากการโหลด หากคุณต้องการเป็นทางเทคนิคประเภทเวลา ได้แก่ เวลาโหลดเวลาคอมไพล์เวลาลิงก์และเวลาดำเนินการ การทำ. pyc จะช่วยลดเวลาในการคอมไพล์
Eric Klien

@EricKlien ขอบคุณผู้ชาย
Daniel Springer

คำตอบ:


81

.pycไฟล์จะถูกสร้างขึ้น (และอาจจะเขียนทับ) เฉพาะเมื่อไฟล์หลามที่นำเข้าโดยสคริปต์อื่น ๆ บาง หากมีการเรียกการนำเข้า Python จะตรวจสอบว่าการ.pycประทับเวลาภายในของไฟล์นั้นไม่เก่ากว่า.pyไฟล์ที่เกี่ยวข้องหรือไม่ ถ้าเป็นเช่นนั้นจะโหลด.pyc; ถ้าไม่ใช่หรือ.pycยังไม่มีอยู่ Python จะคอมไพล์.pyไฟล์เป็น a .pycและโหลดขึ้นมา

"การตรวจสอบที่เข้มงวดขึ้น" หมายความว่าอย่างไร


3
ฉันสามารถแก้ไขปัญหาเกี่ยวกับrm *.pyc. ฉันรู้ว่าถ้าฉันบังคับให้สร้างไฟล์ทั้งหมดใหม่ปัญหาบางอย่างจะได้รับการแก้ไขซึ่งบ่งชี้ว่าไฟล์นั้นไม่ได้ถูกคอมไพล์ด้วยตัวเอง ฉันคิดว่าถ้าพวกเขาใช้การประทับเวลาแล้วจะไม่มีวิธีใดที่จะทำให้พฤติกรรมนี้เข้มงวดขึ้น แต่ปัญหาก็ยังคงอยู่
Aaron Schif

14
นี่ไม่ถูกต้องเสียทีเดียว การประทับเวลาไม่จำเป็นต้องตรงกัน (และมักจะไม่ตรงกัน) การ.pycประทับเวลาของจะต้องเก่ากว่าการ.pyประทับเวลาที่สอดคล้องกันเพื่อเริ่มการคอมไพล์ใหม่
Tim Pietzcker

4
@Aaron คุณอาจเปลี่ยนไฟล์. py หรือไม่และในกระบวนการทำให้ไฟล์เก่า (เช่นโดยการคัดลอกไฟล์จาก dir อื่นโดยใช้การดำเนินการที่รักษา 'เวลาแก้ไข')
greggo

1
@greggo ฉันใช้คอมไพล์และอัปเดตจากที่เก็บใช่ในแบบที่ฉันเป็น ที่สามารถทำได้ ขอบคุณ.
Aaron Schif

1
ดีแล้วที่รู้. แล้วจะแก้ไขคำตอบของคุณได้อย่างไร?
Piotr Dobrogost

30

ไฟล์. pyc สร้างขึ้นเมื่อใดก็ตามที่มีการนำเข้าองค์ประกอบรหัสที่เกี่ยวข้องและอัปเดตหากไฟล์รหัสที่เกี่ยวข้องได้รับการอัปเดต หากไฟล์. pyc ถูกลบไฟล์เหล่านั้นจะถูกสร้างใหม่โดยอัตโนมัติ อย่างไรก็ตามจะไม่ถูกลบโดยอัตโนมัติเมื่อไฟล์รหัสที่เกี่ยวข้องถูกลบ

สิ่งนี้อาจทำให้เกิดบั๊กที่สนุกมากระหว่างตัวอ้างอิงระดับไฟล์

ก่อนอื่นคุณสามารถลงเอยด้วยการกดรหัสที่ใช้งานได้กับเครื่องของคุณเท่านั้นและไม่มีใครอื่น หากคุณมีการอ้างอิงถึงไฟล์ที่คุณลบสิ่งเหล่านี้จะยังคงใช้งานได้ในเครื่องหากคุณไม่ได้ลบไฟล์. pyc ที่เกี่ยวข้องด้วยตนเองเนื่องจากไฟล์. pyc สามารถใช้ในการนำเข้าได้ สิ่งนี้ประกอบไปด้วยข้อเท็จจริงที่ว่าระบบควบคุมเวอร์ชันที่กำหนดค่าไว้อย่างเหมาะสมจะพุชไฟล์. py ไปยังที่เก็บส่วนกลางเท่านั้นไม่ใช่ไฟล์. pyc ซึ่งหมายความว่าโค้ดของคุณสามารถผ่าน "การทดสอบการนำเข้า" (นำเข้าทุกอย่างได้หรือไม่) ก็ใช้ได้ดีและไม่ ทำงานบนคอมพิวเตอร์ของใครก็ได้

ประการที่สองคุณสามารถมีจุดบกพร่องที่น่ากลัวได้หากคุณเปลี่ยนแพ็คเกจเป็นโมดูล เมื่อคุณแปลงแพ็กเกจ (โฟลเดอร์ที่มี__init__.pyไฟล์) เป็นโมดูล (ไฟล์. py) ไฟล์. pyc ที่เคยเป็นตัวแทนของแพ็กเกจนั้นจะยังคงอยู่ โดยเฉพาะอย่างยิ่ง__init__.pycซากศพ ดังนั้นหากคุณมีแพ็คเกจ foo ที่มีรหัสบางอย่างที่ไม่สำคัญให้ลบแพ็คเกจนั้นในภายหลังและสร้างไฟล์ foo.py ด้วยฟังก์ชันบางอย่างdef bar(): passและเรียกใช้:

from foo import bar

คุณได้รับ:

ImportError: cannot import name bar

เนื่องจาก python ยังคงใช้ไฟล์. pyc เก่าจากแพ็คเกจ foo ซึ่งไม่มีแถบกำหนดใดเลย ซึ่งอาจเป็นปัญหาโดยเฉพาะอย่างยิ่งบนเว็บเซิร์ฟเวอร์ซึ่งโค้ดที่ใช้งานได้ทั้งหมดอาจพังได้เนื่องจากไฟล์. pyc

จากสาเหตุทั้งสองนี้ (และอาจเป็นอื่น ๆ ) โค้ดการปรับใช้และโค้ดทดสอบของคุณควรลบไฟล์. pyc เช่นด้วย bash บรรทัดต่อไปนี้:

find . -name '*.pyc' -delete

นอกจากนี้ใน python 2.6 คุณสามารถรัน python ด้วย-Bแฟล็กเพื่อไม่ใช้ไฟล์. pyc ดูวิธีหลีกเลี่ยงไฟล์. pyc สำหรับรายละเอียดเพิ่มเติม

ดูเพิ่มเติม: ฉันจะลบไฟล์. pyc ทั้งหมดออกจากโปรเจ็กต์ได้อย่างไร


"เมื่อคุณแปลงโมดูล (โฟลเดอร์ที่มี__init__.pyไฟล์) ... ". นั่นจะเป็นแพ็คเกจไม่ใช่โมดูล
Robert David Grant

2
โดยเฉพาะอย่างยิ่ง__init__.pycซากศพ - มาได้ยังไง? เนื่องจากแพ็กเกจคือไดเร็กทอรีลบแพ็กเกจหมายถึงการลบไดเร็กทอรีจึงไม่มีไฟล์เหลืออยู่ ...
Piotr Dobrogost

3
@PiotrDobrogost การควบคุมแหล่งที่มาที่มีการจัดการอย่างเหมาะสมเกี่ยวข้องกับการไม่ตรวจสอบไฟล์ pyc ของคุณเป็นแหล่งที่มา ดังนั้นในขณะที่คุณสามารถลบโฟลเดอร์รวมถึงไฟล์ pyc ในสำเนาในเครื่องของคุณได้ แต่จะไม่ถูกลบสำหรับคนอื่นที่ดึงคอมไพล์ สิ่งนี้อาจทำให้เซิร์ฟเวอร์ของคุณขัดข้องหากการปรับใช้ของคุณเกี่ยวข้องกับการดึงคอมไพล์ด้วย
Zags

มีสาเหตุหลายประการที่จะไม่ไว้วางใจสภาพแวดล้อม dev ของคุณให้เป็นตัวแทนของตำแหน่งที่โค้ดของคุณจะถูกปรับใช้ นี้.pycปัญหาคือเหตุผลหนึ่งที่ยัง: อ้างอิงที่ซ่อนอยู่ในระบบปฏิบัติการและยูทิลิตี้แพทช์ระดับ.soไฟล์ config ไฟล์, libs งูใหญ่อื่น ๆ (ถ้าคุณไม่ได้ทำงานใน env เสมือน), env ปิดบัง vars ... รายการไปที่ เพื่อให้ละเอียดถี่ถ้วนและค้นหาปัญหาดังกล่าวทั้งหมดคุณต้องทำสำเนาโค้ดทั้งหมดใน git repo หรือเผยแพร่เป็นแพ็กเกจไปยังเซิร์ฟเวอร์สไตล์ PyPi และทำการโคลนแบบเต็มหรือตั้งค่าบน VM ใหม่ ปัญหาที่อาจเกิดขึ้นเหล่านี้ทำให้ปัญหานี้.pycซีดลงเมื่อเปรียบเทียบ
Chris Johnson
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.