ฉันได้รับการเข้าใจว่า Python เป็นภาษาที่ถูกตีความ ...
อย่างไรก็ตามเมื่อฉันดูซอร์สโค้ดPythonของฉันฉันเห็น.pyc
ไฟล์ซึ่ง Windows ระบุว่าเป็น "รวบรวมไฟล์ไพ ธ อน"
สิ่งเหล่านี้มาจากไหน
java
javac
ฉันได้รับการเข้าใจว่า Python เป็นภาษาที่ถูกตีความ ...
อย่างไรก็ตามเมื่อฉันดูซอร์สโค้ดPythonของฉันฉันเห็น.pyc
ไฟล์ซึ่ง Windows ระบุว่าเป็น "รวบรวมไฟล์ไพ ธ อน"
สิ่งเหล่านี้มาจากไหน
java
javac
คำตอบ:
ประกอบด้วยโค้ดไบต์ซึ่งเป็นสิ่งที่ Python interpreter รวบรวมแหล่งที่มา รหัสนี้จะถูกดำเนินการโดยเครื่องเสมือนของ Python
เอกสารของ Python อธิบายคำจำกัดความเช่นนี้:
Python เป็นภาษาที่ถูกตีความเมื่อเทียบกับภาษาที่รวบรวมแม้ว่าความแตกต่างสามารถเลือนลางเนื่องจากการมีอยู่ของคอมไพเลอร์ bytecode ซึ่งหมายความว่าไฟล์ต้นฉบับสามารถรันได้โดยตรงโดยไม่ต้องสร้างไฟล์ที่รันได้อย่างชัดเจน
ฉันได้รับการเข้าใจว่า Python เป็นภาษาที่ตีความ ...
meme ที่ได้รับความนิยมนี้ไม่ถูกต้องหรือค่อนข้างถูกสร้างขึ้นจากความเข้าใจผิดของระดับภาษา (ธรรมชาติ): ความผิดพลาดที่คล้ายกันคือการพูดว่า "พระคัมภีร์เป็นหนังสือปกแข็ง" ฉันขออธิบายว่าอุปมา ...
"พระคัมภีร์" คือ "หนังสือ" ในแง่ของการเป็นชั้นหนังสือ (จริงวัตถุทางกายภาพระบุว่า) หนังสือ; หนังสือที่ระบุว่า "สำเนาของพระคัมภีร์" ควรจะมีอะไรบางอย่างพื้นฐานเหมือนกัน (เนื้อหาแม้ว่าจะเป็นภาษาต่าง ๆ ด้วยการแปลที่ยอมรับได้ระดับเชิงอรรถและคำอธิบายประกอบอื่น ๆ ) - อย่างไรก็ตามหนังสือเหล่านั้น ได้รับอนุญาตอย่างสมบูรณ์แบบที่จะแตกต่างกันในแง่มุมมากมายที่ไม่ถือว่าเป็นพื้นฐาน - ชนิดของการผูก, สีของการผูก, ตัวอักษร (s) ที่ใช้ในการพิมพ์, ภาพประกอบถ้ามี, ระยะขอบเขียนได้กว้างหรือไม่, , และอื่น ๆ และอื่น ๆ.
มีความเป็นไปได้ค่อนข้างมากที่การพิมพ์คัมภีร์ไบเบิลโดยทั่วไปจะมีผลผูกพันปกแข็ง - หลังจากนั้นเป็นหนังสือที่มีความหมายโดยทั่วไปว่าจะต้องอ่านซ้ำแล้วซ้ำอีกคั่นหนังสือไว้หลายแห่งด้วยการมองหาพอยน์เตอร์ ฯลฯ ฯลฯ และการเชื่อมโยงปกแข็งที่ดีสามารถทำสำเนาที่กำหนดได้นานขึ้นภายใต้การใช้งานดังกล่าว อย่างไรก็ตามสิ่งเหล่านี้เป็นประเด็นทางโลก (ทางปฏิบัติ) ที่ไม่สามารถใช้เพื่อตรวจสอบว่าหนังสือวัตถุจริงที่ให้มาเป็นสำเนาของคัมภีร์ไบเบิลหรือไม่: สิ่งพิมพ์ปกอ่อนเป็นไปได้อย่างสมบูรณ์!
ในทำนองเดียวกัน Python คือ "ภาษา" ในแง่ของการกำหนดระดับของการใช้ภาษาซึ่งทุกคนจะต้องคล้ายกันในบางประการพื้นฐาน (ไวยากรณ์ความหมายส่วนใหญ่ยกเว้นส่วนของผู้ที่พวกเขาได้รับอนุญาตอย่างชัดเจนแตกต่างกัน) แต่ได้รับอนุญาตอย่างเต็มที่ จะแตกต่างกันในรายละเอียด "การใช้งาน" ทุกครั้ง - รวมถึงวิธีจัดการกับแฟ้มต้นฉบับที่ได้รับไม่ว่าจะเป็นการรวบรวมแหล่งที่มาในรูปแบบระดับล่าง (และถ้าเป็นเช่นนั้นแบบฟอร์มใด - และบันทึกว่า แบบฟอร์มที่คอมไพล์ไปยังดิสก์หรือที่อื่น ๆ ) วิธีที่จะดำเนินการกับแบบฟอร์มดังกล่าวและอื่น ๆ
การใช้งานแบบดั้งเดิม CPython มักเรียกว่า "Python" เพียงช่วงสั้น ๆ - แต่เป็นเพียงหนึ่งในการนำไปใช้งานคุณภาพการผลิตหลายอย่างเคียงข้างกับ IronPython ของ Microsoft (ซึ่งรวบรวมรหัส CLR เช่น ".NET"), Jython (ซึ่งคอมไพล์กับรหัส JVM), PyPy (ซึ่งเขียนด้วยภาษา Python เองและสามารถรวบรวมรูปแบบ "แบ็คเอนด์" ที่หลากหลายรวมถึงภาษาของเครื่องที่เพิ่งสร้างขึ้น) พวกเขาคือ Python ทั้งหมด (== "การใช้งานภาษา Python") เช่นเดียวกับวัตถุหนังสือที่แตกต่างกันอย่างพิถีพิถันอาจเป็น Bibles (== "สำเนาของพระคัมภีร์")
หากคุณสนใจ CPython โดยเฉพาะมันรวบรวมไฟล์ต้นฉบับไว้ในแบบฟอร์มระดับล่างเฉพาะ Python (รู้จักกันในชื่อ "bytecode") จะทำเช่นนั้นโดยอัตโนมัติเมื่อจำเป็น (เมื่อไม่มีไฟล์ bytecode ที่สอดคล้องกับไฟล์ต้นฉบับหรือ ไฟล์ bytecode นั้นเก่ากว่าแหล่งที่มาหรือรวบรวมโดย Python เวอร์ชั่นอื่นซึ่งมักจะบันทึกไฟล์ bytecode ลงในดิสก์ (เพื่อหลีกเลี่ยงการคอมไพล์ใหม่ในอนาคต) โดยทั่วไปแล้ว OTOH IronPython จะรวบรวมรหัส CLR (บันทึกลงในดิสก์หรือไม่ขึ้นอยู่กับ) และรหัส Jython กับ JVM (บันทึกลงในดิสก์หรือไม่ - มันจะใช้.class
ส่วนขยายหากบันทึกไว้)
แบบฟอร์มระดับล่างเหล่านี้จะถูกดำเนินการโดย "เครื่องเสมือน" ที่เหมาะสมหรือที่เรียกว่า "ล่าม" - CPython VM, รันไทม์. Net, Java VM (aka JVM) ตามความเหมาะสม
ดังนั้นในแง่นี้ (การใช้งานทั่วไปทำอะไร) Python เป็น "ตีความภาษา" ถ้าหาก C # และ Java เป็น: ทั้งหมดของพวกเขามีกลยุทธ์การดำเนินงานโดยทั่วไปของการผลิต bytecode ก่อนจากนั้นดำเนินการผ่าน VM / ล่าม .
มีความเป็นไปได้สูงที่จะเน้นว่า "หนัก" ช้าและสูงในกระบวนการรวบรวม - พิธี CPython ได้รับการออกแบบให้คอมไพล์เร็วที่สุดเท่าที่จะเป็นไปได้โดยมีพิธีการน้อยที่สุด - คอมไพเลอร์ทำการตรวจสอบข้อผิดพลาดและการปรับให้เหมาะสมน้อยที่สุดดังนั้นจึงสามารถรันได้อย่างรวดเร็ว ทำงานโดยอัตโนมัติและโปร่งใสเมื่อใดก็ตามที่จำเป็นโดยที่ผู้ใช้ไม่จำเป็นต้องทราบว่ามีการรวบรวมเกิดขึ้นส่วนใหญ่ Java และ C # มักจะยอมรับการทำงานมากขึ้นในระหว่างการรวบรวม (และดังนั้นจึงไม่ทำการรวบรวมอัตโนมัติ) เพื่อตรวจสอบข้อผิดพลาดอย่างละเอียดมากขึ้นและดำเนินการเพิ่มประสิทธิภาพมากขึ้น มันเป็นเครื่องชั่งสีเทาต่อเนื่องไม่ใช่สถานการณ์ดำหรือขาว
ไม่มีสิ่งใดในภาษาที่ตีความได้ ไม่ว่าจะใช้ล่ามหรือคอมไพเลอร์เป็นลักษณะของการใช้งานและไม่มีอะไรเกี่ยวข้องกับภาษา
ทุกภาษาสามารถดำเนินการโดยล่ามหรือคอมไพเลอร์ ภาษาส่วนใหญ่มีการใช้งานอย่างน้อยหนึ่งประเภท (ตัวอย่างเช่นมีล่ามสำหรับ C และ C ++ และมีคอมไพเลอร์สำหรับ JavaScript, PHP, Perl, Python และ Ruby) นอกจากนี้การใช้ภาษาที่ทันสมัยส่วนใหญ่รวมทั้งล่ามและคอมไพเลอร์ (หรือแม้แต่คอมไพเลอร์หลายตัว)
ภาษาเป็นเพียงชุดของกฎทางคณิตศาสตร์ที่เป็นนามธรรม ล่ามเป็นหนึ่งในกลยุทธ์การใช้งานที่เป็นรูปธรรมสำหรับภาษา ทั้งสองอาศัยอยู่ในระดับนามธรรมที่แตกต่างอย่างสิ้นเชิง หากภาษาอังกฤษเป็นภาษาที่พิมพ์คำว่า "ตีความภาษา" จะเป็นข้อผิดพลาดประเภท คำสั่ง "Python เป็นภาษาที่ถูกตีความ" ไม่เพียง แต่เป็นเท็จ (เพราะความเท็จจะแปลว่าคำสั่งนั้นมีเหตุผลแม้ว่ามันจะผิด) มันก็ไม่สมเหตุสมผลเพราะภาษานั้นไม่สามารถนิยามได้ว่าเป็น "ตีความ".
โดยเฉพาะถ้าคุณดูการใช้งาน Python ที่มีอยู่ในปัจจุบันนี่เป็นกลยุทธ์การใช้งานที่ใช้:
คุณอาจสังเกตเห็นว่าทุกการใช้งานในรายการนั้น (รวมถึงคนอื่น ๆ ที่ฉันไม่ได้พูดถึงเช่นตัวเล็ก, Shedskin หรือ Psyco) มีคอมไพเลอร์ ในความเป็นจริงเท่าที่ฉันรู้ในปัจจุบันไม่มีการนำ Python มาใช้ซึ่งตีความอย่างหมดจดไม่มีการวางแผนการใช้งานดังกล่าวและไม่เคยมีการนำไปปฏิบัติ
คำว่า "ตีความภาษา" ไม่เพียงทำให้รู้สึกถึงแม้ว่าคุณจะตีความว่ามันเป็นความหมาย "ภาษาที่มีการใช้งานตีความ" มันไม่ชัดเจนจริง ใครก็ตามที่บอกคุณว่าเห็นได้ชัดว่าไม่รู้ว่าเขากำลังพูดถึงอะไร
โดยเฉพาะอย่างยิ่ง.pyc
ไฟล์ที่คุณเห็นจะถูกเก็บไว้ในไฟล์ bytecode ที่สร้างโดย CPython, Stackless Python หรือ Unladen Swallow
สิ่งเหล่านี้ถูกสร้างขึ้นโดย Python interpreter เมื่อมี.py
การนำเข้าไฟล์และประกอบด้วย "คอมไพล์ bytecode" ของโมดูล / โปรแกรมที่นำเข้าความคิดที่ว่า "การแปล" จากซอร์สโค้ดไปยัง bytecode (ซึ่งจะต้องทำเพียงครั้งเดียวเท่านั้น) สามารถข้ามกับimport
s ที่ตามมาถ้า.pyc
ใหม่กว่า.py
ไฟล์ที่เกี่ยวข้องจึงเร่งการเริ่มต้นเพียงเล็กน้อย แต่มันก็ยังตีความ
เพื่อเพิ่มความเร็วในการโหลดโมดูล Python แคชเนื้อหาที่รวบรวมของโมดูลใน. pyc
CPython รวบรวมซอร์สโค้ดของมันเป็น "รหัสไบต์" และด้วยเหตุผลด้านประสิทธิภาพมันเก็บรหัสไบต์นี้ไว้ในระบบไฟล์เมื่อใดก็ตามที่ไฟล์ต้นฉบับมีการเปลี่ยนแปลง สิ่งนี้ทำให้การโหลดโมดูล Python เร็วขึ้นมากเนื่องจากขั้นตอนการคอมไพล์สามารถข้ามได้ เมื่อไฟล์ต้นฉบับของคุณคือ foo.py, CPython จะแคชโค้ดไบต์ในไฟล์ foo.pyc ถัดจากซอร์ส
ใน python3 เครื่องจักรนำเข้าของ Python จะถูกขยายเพื่อเขียนและค้นหาไฟล์แคชรหัสไบต์ในไดเรกทอรีเดียวภายในทุก ๆ แพ็คเกจของ Python ไดเรกทอรีนี้จะถูกเรียกว่า __pycache__
นี่คือโฟลว์แผนภูมิที่อธิบายวิธีโหลดโมดูล:
สำหรับข้อมูลเพิ่มเติม:
ref: PEP3147
อ้างอิง: ไฟล์ Python“ รวบรวม”
นี่คือสำหรับผู้เริ่มต้น
Python รวบรวมสคริปต์ของคุณเพื่อรวบรวมรหัสโดยอัตโนมัติเรียกว่ารหัสไบต์ก่อนที่จะเรียกใช้
การเรียกใช้สคริปต์ไม่ถือเป็นการอิมพอร์ตและจะไม่มีการสร้าง. pyc
ตัวอย่างเช่นถ้าคุณมีไฟล์สคริปต์abc.pyการนำเข้าที่โมดูลอื่นxyz.pyเมื่อคุณเรียกabc.py , xyz.pycจะถูกสร้างขึ้นตั้งแต่ xyz จะถูกนำเข้า แต่ไม่มีไฟล์ abc.pyc จะได้รับการสร้างขึ้นตั้งแต่ abc py ไม่ได้ถูกนำเข้า
หากคุณต้องการสร้างไฟล์. pyc สำหรับโมดูลที่ไม่ได้นำเข้าคุณสามารถใช้py_compile
และcompileall
โมดูล
py_compile
โมดูลด้วยตนเองสามารถรวบรวมโมดูลใด ๆ วิธีหนึ่งคือการใช้py_compile.compile
ฟังก์ชันในโมดูลนั้นแบบโต้ตอบ:
>>> import py_compile
>>> py_compile.compile('abc.py')
สิ่งนี้จะเขียน. pyc ไปยังตำแหน่งเดียวกับ abc.py (คุณสามารถแทนที่ด้วยพารามิเตอร์เสริมcfile
)
นอกจากนี้คุณยังสามารถรวบรวมไฟล์ทั้งหมดในไดเรกทอรีหรือไดเรกทอรีโดยอัตโนมัติโดยใช้โมดูลรวบรวม
python -m compileall
หากไม่ระบุชื่อไดเรกทอรี (ไดเรกทอรีปัจจุบันในตัวอย่างนี้) โมดูลจะรวบรวมทุกสิ่งที่พบ sys.path
Python (อย่างน้อยการใช้งานที่พบบ่อยที่สุดของมัน) ตามรูปแบบของการรวบรวมแหล่งต้นฉบับเพื่อรหัสไบต์แล้วตีความรหัสไบต์บนเครื่องเสมือน นี่หมายถึง (อีกครั้งการติดตั้งทั่วไป) ไม่ใช่ทั้งล่ามและผู้แปล
อย่างไรก็ตามอีกด้านหนึ่งของกระบวนการนี้คือกระบวนการรวบรวมส่วนใหญ่จะถูกซ่อนไว้ - ไฟล์. pyc นั้นเสมือนว่าเป็นแคช มันเพิ่มความเร็วในการทำงาน แต่โดยปกติคุณไม่จำเป็นต้องรับรู้เลย มันจะทำให้โมฆะโดยอัตโนมัติและโหลดซ้ำอีกครั้ง (รวบรวมซอร์สโค้ดใหม่) เมื่อจำเป็นตามการประทับเวลา / วันที่ของไฟล์
เกี่ยวกับครั้งเดียวที่ฉันเห็นปัญหาเกี่ยวกับเรื่องนี้คือเมื่อไฟล์ bytecode ที่คอมไพล์ได้รับการประทับเวลาในอนาคตซึ่งหมายความว่ามันจะดูใหม่กว่าไฟล์ต้นฉบับเสมอ เนื่องจากมันดูใหม่กว่าเดิมซอร์สไฟล์จึงไม่เคยถูกคอมไพล์ซ้ำดังนั้นไม่ว่าคุณจะเปลี่ยนแปลงอะไรพวกเขาก็ถูกเพิกเฉย ...
ไฟล์ Python * .py เป็นเพียงไฟล์ข้อความที่คุณเขียนโค้ดบางบรรทัด เมื่อคุณพยายามเรียกใช้ไฟล์นี้โดยใช้คำว่า "python filename.py"
คำสั่งนี้เรียกใช้ Python Virtual Machine Python Virtual Machine มี 2 องค์ประกอบคือ "compiler" และ "interpreter" ล่ามไม่สามารถอ่านข้อความในไฟล์ * .py ดังนั้นข้อความนี้จะถูกแปลงแรกเป็นรหัสไบต์ซึ่งมีการกำหนดเป้าหมายที่จะ PVM (ไม่ฮาร์ดแวร์ แต่ PVM) PVM เรียกใช้งานโค้ดไบต์นี้ ไฟล์ * .pyc ยังถูกสร้างขึ้นโดยเป็นส่วนหนึ่งของการเรียกใช้ซึ่งดำเนินการนำเข้าของคุณบนไฟล์ในเชลล์หรือในไฟล์อื่น
หากไฟล์ * .pyc นี้สร้างขึ้นแล้วทุกครั้งที่คุณเรียกใช้ / เรียกใช้ไฟล์ * .py ของคุณระบบจะโหลดไฟล์ * .pyc ของคุณโดยตรงซึ่งไม่จำเป็นต้องมีการรวบรวมใด ๆ
เมื่อสร้างไฟล์ * .pyc แล้วไม่จำเป็นต้องใช้ไฟล์ * .py เว้นแต่ว่าคุณจะแก้ไข
รหัส Python ต้องผ่าน 2 ขั้นตอน ขั้นตอนแรกรวบรวมรหัสเป็นไฟล์. pyc ซึ่งเป็นจริง bytecode จากนั้นไฟล์. pyc นี้ (bytecode) จะถูกตีความโดยใช้ CPython interpreter โปรดดูที่นี้การเชื่อมโยง ขั้นตอนการรวบรวมและประมวลผลโค้ดในที่นี้มีคำอธิบายอย่างง่าย