เกิดอะไรขึ้นกับการนำเข้าที่สัมพันธ์กันใน Python


89

ฉันเพิ่งอัพเกรดpylintเวอร์ชั่นตัวตรวจสอบ Python สไตล์ยอดนิยม

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

ข้อความแสดงข้อผิดพลาดใหม่คือ W0403

W0403: การนำเข้าสัมพัทธ์% r ควรเป็น% r

ใช้เมื่อตรวจพบการนำเข้าที่สัมพันธ์กับไดเรกทอรีแพ็คเกจ


ตัวอย่าง

ตัวอย่างเช่นถ้าแพ็คเกจของฉันมีโครงสร้างแบบนี้:

/cake
  /__init__.py
  /icing.py
  /sponge.py
/drink

และในแพ็คเกจฟองน้ำฉันเขียน:

import icing

แทน

import cake.icing

ฉันจะได้รับข้อผิดพลาดนี้


ในขณะที่ฉันเข้าใจว่าไม่ใช่ข้อความ Pylint ทั้งหมดที่มีความสำคัญเท่ากันและฉันไม่กลัวที่จะยกเลิกข้อความเหล่านั้น แต่ฉันไม่เข้าใจว่าทำไมการฝึกเช่นนี้จึงถือเป็นแนวคิดที่ไม่ดี

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

คำตอบ:


97

ปัญหาimport icingคือคุณไม่ทราบว่าการนำเข้าแบบสัมบูรณ์หรือการนำเข้าแบบสัมพัทธ์ icingสามารถโมดูลในเส้นทางของงูใหญ่หรือแพคเกจในโมดูลปัจจุบัน สิ่งนี้ค่อนข้างน่ารำคาญเมื่อแพ็คเกจโลคัลมีชื่อเหมือนกับแพคเกจไลบรารีมาตรฐานของไพ ธ อน

คุณสามารถเลือกfrom __future__ import absolute_importปิดการนำเข้าแบบสัมพัทธ์โดยนัยได้ มันอธิบายรวมทั้งมีเหตุผลเกี่ยวกับความคลุมเครือในPEP 328 ฉันเชื่อว่า Python 3000 มีการนำเข้าที่สัมพันธ์โดยนัยปิดการใช้งานโดยสิ้นเชิง

คุณยังสามารถทำการนำเข้าแบบสัมพัทธ์ได้ แต่คุณต้องทำอย่างชัดเจนเช่นนี้

from . import icing

2
+1 โดยเฉพาะอย่างยิ่งสำหรับวิธีการประนีประนอมซึ่งน่าจะเป็นวิธีที่ฉันควรไป
Oddthinking

2
หมายเหตุคุณสามารถทำได้import .icingแทนfrom . import icing
แจ็ค

11
@ แจ็คจริง ๆ แล้วฉันไม่คิดว่าคุณจะทำได้ จากส่วนนี้ของ PEP328 : การนำเข้าญาติต้องใช้เสมอfrom <> import; import <>แน่นอนอยู่เสมอ แน่นอนการนำเข้าแบบสัมบูรณ์สามารถใช้from <> importโดยการละเว้นจุดนำ เหตุผลที่import .fooต้องห้ามคือเพราะหลังจาก import XXX.YYY.ZZZนั้น XXX.YYY.ZZZสามารถใช้งานได้ในการแสดงออก แต่ .moduleYไม่สามารถใช้งานได้ในการแสดงออก
A.

48

มีเหตุผลดีๆอยู่สองสามข้อ:

  1. การนำเข้าสัมพัทธ์จะแตกง่ายเมื่อคุณย้ายโมดูลไปรอบ ๆ

    ลองนึกภาพคุณมีความfoo.barเป็นfoo.bazและbazโมดูลในแพคเกจของคุณ foo.barนำเข้าfoo.bazแต่ใช้การนำเข้าแบบสัมพัทธ์

    ตอนนี้ถ้าคุณต้องย้ายfoo.barไปที่barโมดูลของคุณก็กำลังนำเข้าที่แตกต่างกันbaz!

  2. การนำเข้าสัมพัทธ์ไม่ชัดเจน แม้จะไม่มีการเคลื่อนที่ไปรอบ ๆbarโมดูลในตัวอย่างข้างต้นนักพัฒนาใหม่ที่เข้ามาในโครงการของคุณก็อาจได้รับการอภัยเนื่องจากไม่ทราบว่าbazเป็นแพ็กเกจfoo.bazระดับรากbazจริงๆ

    การนำเข้าแบบสัมบูรณ์ทำให้ชัดเจนว่าโมดูลใดกำลังใช้อยู่ และอย่างที่import thisบอกกล่าวชัดกว่าดีกว่า

  3. Python 3 ได้ปิดใช้งานการนำเข้าที่สัมพันธ์โดยนัยทั้งหมด; ตอนนี้การตีความการนำเข้าจะถูกตีความว่าเป็นสัมบูรณ์ซึ่งหมายความว่าในตัวอย่างด้านบนimport bazจะนำเข้าโมดูลระดับบนสุดเสมอ คุณจะต้องใช้ไวยากรณ์การนำเข้าที่ชัดเจนแทน ( from . import baz)

    การย้ายตัวอย่างจาก Python 2 ถึง 3 จะทำให้เกิดปัญหาที่ไม่คาดคิดการใช้การนำเข้าแบบสัมบูรณ์จะทำให้โค้ดของคุณพิสูจน์ได้ในอนาคต


10
+1 สำหรับ # 2 และ # 3 แต่ # 1 จะต้องชดเชยกับสิ่งที่เกิดขึ้นเมื่อย้ายไดเรกทอรีทั้งหมด (เช่นผลักลงระดับ)
Oddthinking
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.