ทำไมบางครั้งโมดูล Python จึงไม่นำเข้าโมดูลย่อย


91

วันนี้ฉันสังเกตเห็นบางอย่างแปลก ๆ ฉันอยากจะอธิบาย ฉันไม่แน่ใจ 100% ว่าจะใช้วลีนี้เป็นคำถามได้อย่างไร Google จึงไม่ต้องสงสัย โมดูลการบันทึกไม่สามารถเข้าถึงการบันทึกโมดูลตัวจัดการด้วยเหตุผลแปลก ๆ ลองด้วยตัวคุณเองถ้าคุณไม่เชื่อฉัน:

>>> import logging
>>> logging.handlers
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'handlers'
>>> import logging.handlers
>>> logging.handlers
<module 'logging.handlers' from '/usr/lib/python2.6/logging/handlers.pyc'>

ใครสามารถอธิบายได้ว่าทำไมสิ่งนี้ถึงเกิดขึ้น?

คำตอบ:


122

ใน Python จำเป็นต้องนำเข้าโมดูลก่อนจึงจะเข้าถึงได้ import loggingนำเข้าเฉพาะโมดูลการบันทึก มันเกิดขึ้นได้ว่าloggingเป็นแพ็คเกจที่มีโมดูลย่อย แต่โมดูลย่อยเหล่านั้นยังไม่โหลดโดยอัตโนมัติ ดังนั้นคุณต้องนำเข้าอย่างชัดเจนlogging.handlersก่อนจึงจะสามารถเข้าถึงได้

หากคุณสงสัยว่าทำไมบางครั้งคุณจึงไม่ต้องการการนำเข้าเพิ่มเติมเหล่านั้นบางแพ็คเกจจะนำเข้าโมดูลย่อยบางส่วนหรือทั้งหมดเมื่อนำเข้า - เพียงแค่ทำการอิมพอร์ตเหล่านั้นใน__init__.pyไฟล์ ในกรณีอื่นอาจเป็นไปได้ว่าสิ่งอื่นที่คุณนำเข้านำเข้าlogging.handlersด้วย ไม่สำคัญว่าจะนำเข้าโค้ดชิ้นใด ตราบใดที่บางสิ่งในกระบวนการของคุณนำเข้าlogging.handlersก่อนที่คุณจะเข้าถึงสิ่งนั้นจะอยู่ที่นั่น และบางครั้งโมดูลที่มีลักษณะเช่นแพคเกจจริงๆไม่ได้เป็นหนึ่งเช่นและos ไม่ใช่แพ็คเกจ แต่เพียงแค่นำเข้าโมดูลอื่น ๆ ที่ถูกต้อง (สำหรับแพลตฟอร์มของคุณ) และเรียกใช้เพื่อให้คุณสามารถเข้าถึงได้ในรูปแบบไฟล์.os.pathospathos.path


4

ฉันยังใหม่กับ python และหลังจากมีการฝึกฝนมากมายตอนนี้ฉันสามารถแยกความแตกต่างระหว่างแพ็คเกจ (โฟลเดอร์) โมดูล (.py) คลาสตัวแปร ... ฯลฯ ...

หากคุณต้องการให้โฟลเดอร์ใด ๆ ของคุณเป็นแพคเกจ python - ต้องมี__init__.pyไฟล์แม้แต่ไฟล์เปล่าก็ทำได้ !!!

และอย่างที่โทมัสกล่าวคุณสามารถนำเข้าโมดูลพิเศษใน__init__.py ได้หากต้องการ !!! แต่โมดูล / แพ็คเกจสามารถเข้าถึงได้หลังจากนำเข้าเท่านั้น ...

หากคุณต้องการนำเข้าทุกอย่างจากโมดูลที่คุณสามารถใช้ได้

from logging import *

ส่วนที่เหลือคุณสามารถเข้าถึงโมดูลตัวจัดการเช่นด้านล่างได้เช่นกัน

from logging import handlers
print dir(handlers)


5
กรุณาอย่าใช้from module import *. เป็นเรื่องที่ผิดพลาดเกือบตลอดเวลา
Thomas Wouters

หากคุณต้องการให้นำเข้าทุกอย่างในแพ็คเกจโดยอัตโนมัติให้ทำการอิมพอร์ตเหล่านั้นในinit .py แทนการตั้งค่าทั้งหมดในinit .py และทำ 'from package import *' ที่ใดที่หนึ่ง
Thomas Wouters

2
@Pete: เนื่องจาก "สร้างมลพิษ" ให้กับเนมสเปซมาตรฐานซึ่งนำไปสู่ความคลุมเครือและความขัดแย้ง ถ้าฉันมีimport zipperและzipper.open()คุณจะรู้ว่าฉันโทรหาช่องไหน ตรงกันข้ามfrom zipper import *ตามด้วยopen()มันในตัวเปิดหรือ zipper.open หรือสิ่งอื่นใด import zipper as zเป็นที่ต้องการมากหากคุณเบื่อที่จะพิมพ์zipper
msw

3
@Pete: มันเป็นปัญหาเช่นกันเพราะคุณอาจเขียนทับเนมสเปซบางส่วนโดยไม่รู้ตัว ฉันเคยใช้numpy import *เนื่องจากฟังก์ชัน numpy บางอย่างไม่ทำงานเว้นแต่คุณจะนำเข้า numpy ทั้งหมด (ข้อบกพร่องในการออกแบบที่แย่มากในส่วนของ IMO) แต่ numpy มีวัตถุจำนวนมากที่นำเข้า ฉันลงเอยด้วยการเขียนทับฟังก์ชันจำนวนมาก (ฉันเชื่อว่าสำเนาเป็นสิ่งเดียว ... ฉันเหนื่อยเกินไปที่จะตรวจสอบ) ตอนนี้ฉันนำเข้า numpy เป็น np ถ้าฉันจะใช้ numpy มากจนทนไม่ไหวที่จะพิมพ์ซ้ำไปซ้ำมา
chriscauley

2
@dustynachos ฟังก์ชัน numpy ใดมีข้อบกพร่องนั้น
Winston Ewert

2

Thomas Woutersตอบคำถามนี้ได้เป็นอย่างดี แต่อนิจจาฉันพบคำถามนี้หลังจากพบคำตอบในเอกสารต้นฉบับเท่านั้น ด้วยเหตุนี้ฉันจึงคิดว่าฉันจะเพิ่มสิ่งนี้ด้วยความหวังว่ามันจะปรากฏขึ้นใกล้กับด้านบนของเครื่องมือค้นหาในอนาคต

คำถาม

เหตุใดข้อผิดพลาด: ' AttributeError: module' module_name 'จึงไม่มีแอตทริบิวต์' sub_module_name 'ปรากฏขึ้นแม้ว่าตัวแก้ไขของฉัน (เช่น Visual Code) จะกรอกชื่อโมดูลย่อยโดยอัตโนมัติ:

 import module_name
 module_name.sub_module_name(parameter)

ตอบ

ตัวแก้ไขของคุณใช้การเติมข้อความอัตโนมัติจากโครงสร้างไฟล์ของโปรเจ็กต์ของคุณไม่ใช่จากพฤติกรรมของ Python โมดูลย่อยจะไม่ถูกนำเข้า 'โดยอัตโนมัติ' เมื่อคุณนำเข้าโมดูล อ้างอิงเอกสารPythonสำหรับรายละเอียดเกี่ยวกับวิธีการนำเข้าโมดูลย่อย 'โดยอัตโนมัติ' เมื่อใช้

 import module_name

การมีส่วนร่วมที่สำคัญพร้อมคำตอบนี้คือการเพิ่ม AttributeError เมื่อพยายามนำเข้า 'โมดูล' หรือ 'แพ็คเกจ'

หวังว่านี่จะช่วยใครสักคน!


1

เมื่อเร็ว ๆ นี้ฉันต้องเผชิญกับสถานการณ์แปลก ๆ เหมือนกัน ดังนั้นฉันพนันได้เลยว่าคุณได้ลบการนำเข้า lib ของบุคคลที่สามออกไปแล้ว ที่ถูกลบออก lib ที่มีอยู่ from logging import handlersหรือและมีให้คุณfrom logging import * handlersและในสคริปต์อื่น ๆ คุณมีบางสิ่งที่เหมือนimport loggingและเพิ่งใช้logging.handlersและคุณคิดว่านั่นเป็นวิธีการทำงานเหมือนที่ฉันทำ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.