ใช้ 'โมดูลนำเข้า' หรือ 'จากโมดูลนำเข้า' หรือไม่


411

ฉันพยายามค้นหาคำแนะนำที่ครอบคลุมว่าควรใช้import moduleหรือfrom module importไม่? ฉันเพิ่งเริ่มต้นด้วย Python และฉันพยายามเริ่มด้วยแนวทางปฏิบัติที่ดีที่สุดในใจ

โดยพื้นฐานแล้วฉันหวังว่าถ้ามีใครสามารถแบ่งปันประสบการณ์ของพวกเขานักพัฒนารายอื่น ๆ ที่มีความพึงพอใจและสิ่งที่เป็นวิธีที่ดีที่สุดที่จะหลีกเลี่ยงgotchasตามถนน?


5
ฉันแค่อยากให้คุณรู้ว่าคำตอบที่เลือกนั้นผิด มันระบุว่าความแตกต่างเป็นอัตนัยในขณะที่มีความแตกต่าง สิ่งนี้อาจนำไปสู่การตรวจจับข้อบกพร่องได้ยาก ดูคำตอบ Michael Ray Lovetts
Mayou36


2
มีนรกของความแตกต่างระหว่างการนำเข้าเฉพาะชื่อตัวระบุเป็น'from module import X,Y,Z'from module import * VS หลังเนมสเปซของคุณและสามารถให้ผลลัพธ์ที่คาดเดาไม่ได้ขึ้นอยู่กับสิ่งที่เกิดขึ้นในโมดูล ที่แย่กว่านั้นก็คือการทำfrom module import *กับหลายโมดูล
smci

คำตอบ:


474

ความแตกต่างระหว่างimport moduleและfrom module import fooเป็นส่วนตัว เลือกคนที่คุณชอบที่สุดและสอดคล้องกับการใช้งานของคุณ นี่คือบางจุดที่จะช่วยคุณตัดสินใจ

import module

  • ข้อดี:
    • บำรุงรักษาimportงบของคุณน้อยลง ไม่จำเป็นต้องเพิ่มการนำเข้าเพิ่มเติมเพื่อเริ่มใช้รายการอื่นจากโมดูล
  • จุดด้อย:
    • การพิมพ์module.fooรหัสของคุณอาจทำให้เบื่อและซ้ำซ้อน (สามารถลดความน่าเบื่อโดยใช้import module as moจากนั้นพิมพ์mo.foo)

from module import foo

  • ข้อดี:
    • พิมพ์น้อยลงเพื่อใช้ foo
    • ควบคุมรายการของโมดูลที่สามารถเข้าถึงได้มากขึ้น
  • จุดด้อย:
    • ในการใช้รายการใหม่จากโมดูลคุณต้องอัปเดตimportคำสั่งของคุณ
    • fooคุณจะสูญเสียเกี่ยวกับบริบท ตัวอย่างเช่นมันชัดเจนน้อยกว่าสิ่งที่ceil()จะเปรียบเทียบmath.ceil()

วิธีการอย่างใดอย่างหนึ่งเป็นที่ยอมรับ แต่ไม่ได้from module import *ใช้งาน

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


66
+1 สำหรับการใช้ที่ทำให้ท้อใจของ "จากโมดูลนำเข้า *" มันเป็นเพียงแค่ตัดส่วนชื่อ
Christian Witts

22
การทำให้ namespace ยุ่งเหยิงไม่ใช่ส่วนที่มีปัญหามากที่สุดของ "import *" แต่เป็นการลดความสามารถในการอ่าน: ความขัดแย้งของชื่อใด ๆ จะแสดงตัวเองในการทดสอบ (หน่วย) แต่ชื่อทั้งหมดที่คุณใช้จากโมดูลที่นำเข้าจะถูกเปิดเผยโดยไม่มีคำใบ้ว่ามาจากไหน ฉันเกลียด "การนำเข้า *" อย่างยิ่ง
Jürgen A. Erhard

21
Zen of Python พูดอย่างชัดเจนไม่ได้ดีไปกว่านัยหรือไม่?
Antony Koch

8
from module import *อาจมีประโยชน์อย่างยิ่งหากใช้เป็น: if(windows):\n\t from module_win import * \n else: \n\t from module_lin import *. ดังนั้นโมดูลหลักของคุณอาจมีชื่อฟังก์ชั่นที่เป็นอิสระจาก OS หากชื่อฟังก์ชันใน module_lin & module_win มีชื่อเหมือนกัน มันเหมือนกับการสืบทอดคลาสอย่างมีเงื่อนไข
anishsane

19
@anishsane มีวิธีอื่นทำมัน นำเข้า module_win เป็นบางสิ่ง จากนั้นใช้ some.method_name ()
Vinay

163

มีรายละเอียดอื่นที่นี่ไม่ได้กล่าวถึงเกี่ยวข้องกับการเขียนไปยังโมดูล ได้รับสิ่งนี้อาจไม่ธรรมดามาก แต่ฉันต้องการมันเป็นครั้งคราว

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

โมดูล foo:

bar = "apples"

โมดูล a:

import foo
foo.bar = "oranges"   # update bar inside foo module object

โมดูล b:

import foo           
print foo.bar        # if executed after a's "foo.bar" assignment, will print "oranges"

อย่างไรก็ตามหากคุณนำเข้าชื่อสัญลักษณ์แทนชื่อโมดูลสิ่งนี้จะไม่ทำงาน

ตัวอย่างเช่นถ้าฉันทำสิ่งนี้ในโมดูล a:

from foo import bar
bar = "oranges"

ไม่มีโค้ดที่อยู่นอกจะเห็นแถบเป็น "ส้ม" เนื่องจากการตั้งค่าแถบของฉันมีผลกับชื่อ "บาร์" ในโมดูล a เท่านั้นมันไม่ได้ "เข้าถึง" วัตถุโมดูล foo และอัปเดต "บาร์" ของมัน


จากตัวอย่างสุดท้ายคุณยังสามารถเรียก 'foo.bar = "orange"' เพื่ออัปเดต 'bar' ภายใน 'foo' ได้หรือไม่
velocirabbit

4
ไม่ในตัวอย่างสุดท้ายไม่ทราบชื่อ 'foo'
Ghislain Leveque

31
คำตอบนี้ให้คำตอบที่ "จริง" กับคำถาม: อะไรคือความแตกต่างระหว่างสองตัวแปรการนำเข้า
Mayou36

3
เขียนตัวอย่างบางส่วนเพื่อพิสูจน์คำตอบนี้ถูกต้อง แต่เหตุผลของสิ่งนี้คืออะไร?
huangbeidu

ฉันคิดว่าสิ่งที่คุณกำลังพูดคือชื่อสัญลักษณ์นำเข้าที่มีตัวแปรท้องถิ่น แต่นำเข้าชื่อโมดูลที่จะมีตัวแปรทั่วโลก ???
WinEunuuchs2Unix

79

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


import foo:

นำเข้าfooและสร้างการอ้างอิงถึงโมดูลนั้นในเนมสเปซปัจจุบัน จากนั้นคุณต้องกำหนดพา ธ โมดูลที่สมบูรณ์เพื่อเข้าถึงแอททริบิวหรือวิธีการเฉพาะจากภายในโมดูล

เช่นfoo.barแต่ไม่bar

from foo import bar:

นำเข้าfooและสร้างการอ้างอิงถึงสมาชิกทั้งหมดในรายการ ( bar) fooไม่ได้ตั้งค่าตัวแปร

เช่นbarแต่ไม่ใช่bazหรือfoo.baz

from foo import *:

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

เช่นbarและbazแต่ไม่หรือ_quxfoo._qux


ตอนนี้เรามาดูกันเมื่อเราimport X.Y:

>>> import sys
>>> import os.path

ตรวจสอบsys.modulesกับชื่อosและos.path:

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

ตรวจสอบglobals()และกำหนดlocals()เนมสเปซด้วยosและos.path:

 >>> globals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> locals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> globals()['os.path']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os.path'
>>>

จากตัวอย่างข้างต้นเราพบว่าosมีการแทรกเฉพาะใน namespace ท้องถิ่นและทั่วโลก ดังนั้นเราควรจะสามารถใช้:

 >>> os
 <module 'os' from
  '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
 >>> os.path
 <module 'posixpath' from
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
 >>>

pathแต่ไม่ได้

>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

เมื่อคุณลบosเนมสเปซจาก locals () แล้วคุณจะไม่สามารถเข้าถึงได้osรวมos.pathถึงแม้ว่าจะมีอยู่ใน sys.modules:

>>> del locals()['os']
>>> os
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

ตอนนี้เรามาพูดถึงimport from:

from:

>>> import sys
>>> from os import path

ตรวจสอบsys.modulesกับosและos.path:

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

เราพบว่าในsys.modulesเราพบเช่นเดียวกับที่เราเคยทำมาก่อนโดยใช้import name

ตกลงให้ตรวจสอบว่ามีลักษณะอย่างไรในlocals()และกำหนดglobals()เนมสเปซ:

>>> globals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> locals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['os']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os'
>>>

คุณสามารถเข้าถึงโดยใช้ชื่อpathไม่ใช่โดยos.path:

>>> path
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

ลองลบ 'path' จากlocals():

>>> del locals()['path']
>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

ตัวอย่างสุดท้ายโดยใช้นามแฝง:

>>> from os import path as HELL_BOY
>>> locals()['HELL_BOY']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['HELL_BOY']
<module 'posixpath' from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>>

และไม่มีการกำหนดเส้นทาง:

>>> globals()['path']
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
KeyError: 'path'
>>>

8
แม้ว่านี่จะเป็นคำพูดที่ละเอียด แต่นี่เป็นคำตอบที่ดีที่สุดในรายการสำหรับคำถามที่ค่อนข้างซับซ้อน มันมีรหัสจริงเพื่อช่วยอธิบายรายละเอียดปลีกย่อย "ภายใต้ประทุน" ซึ่งมีความสำคัญมากกว่าสไตล์สำหรับปัญหานี้โดยเฉพาะ ฉันหวังว่าฉันจะสามารถลงคะแนนมากกว่าหนึ่งครั้ง!
Mike Williamson

การใช้as SYMBOLคำสั่งนี้เปลี่ยนไปหรือไม่?
Maximilian Burszley

40

ทั้งสองวิธีได้รับการสนับสนุนด้วยเหตุผล: มีบางครั้งที่วิธีหนึ่งเหมาะสมกว่าอีกวิธีหนึ่ง

  • import module: ดีเมื่อคุณใช้หลายบิตจากโมดูล ข้อเสียคือคุณจะต้องมีคุณสมบัติการอ้างอิงแต่ละรายการด้วยชื่อโมดูล

  • from module import ...: ดีที่รายการที่นำเข้าสามารถใช้งานได้โดยตรงโดยไม่มีส่วนนำหน้าชื่อโมดูล ข้อเสียเปรียบก็คือคุณจะต้องแสดงรายการสิ่งที่คุณใช้แต่ละรายการและมันไม่ชัดเจนในโค้ดว่ามีบางอย่างมาจากไหน

สิ่งที่ต้องใช้ขึ้นอยู่กับว่าอะไรทำให้รหัสชัดเจนและสามารถอ่านได้และมีอะไรที่เกี่ยวข้องกับความชอบส่วนตัว ฉันเอนไปimport moduleโดยทั่วไปเพราะในรหัสมันชัดเจนมากว่าวัตถุหรือฟังก์ชั่นมาจากไหน ฉันใช้from module import ...เมื่อฉันใช้วัตถุ / ฟังก์ชั่นจำนวนมากในรหัส


1
มีวิธีใช้อย่างไรfrom M import Xและยังคงได้รับประโยชน์จากการใช้ตัวระบุอย่างใด? ดูเหมือนว่าคุณจะได้รับสิ่งที่ดีที่สุดของทั้งสองโลกถ้าคุณยังสามารถทำได้M.Xหลังจากนำเข้านั้น
arthropod

@artgropod: ครับ class m: from something.too.long import x, y, zคุณสามารถทำได้ แม้ว่าจะไม่แนะนำจริง ๆ
โกหกที่โกหก

35

ส่วนตัวใช้เสมอ

from package.subpackage.subsubpackage import module

แล้วเข้าถึงทุกอย่างเป็น

module.function
module.modulevar

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

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

แน่นอนคุณสามารถมีปัญหาหากคุณมีชื่อโมดูลเดียวกันสำหรับสองโมดูลที่แตกต่างกันในสองแพ็คเกจที่แตกต่างกันเช่น

from package1.subpackage import module
from package2.subpackage import module

ในกรณีนี้แน่นอนว่าคุณประสบปัญหา แต่มีข้อแนะนำที่ชัดเจนว่าการจัดวางแพ็กเกจของคุณมีข้อบกพร่องและคุณต้องคิดใหม่


10
ในกรณีสุดท้ายคุณสามารถใช้: import pkgN.sub.module เป็น modN โดยให้ชื่อที่ต่างกันสำหรับแต่ละโมดูล นอกจากนี้คุณยังสามารถใช้รูปแบบ 'import modulename เป็น mod1' เพื่อย่อชื่อยาวหรือเพื่อสลับระหว่างการใช้งานของ API เดียวกัน (เช่นโมดูล DB API) ด้วยการเปลี่ยนชื่อเดียว
Jeff Shannon

15
import module

ดีที่สุดเมื่อคุณจะใช้ฟังก์ชั่นมากมายจากโมดูล

from module import function

ที่ดีที่สุดคือเมื่อคุณต้องการที่จะหลีกเลี่ยงการก่อให้เกิดมลพิษ namespace functionโลกกับทุกฟังก์ชั่นและประเภทจากโมดูลเมื่อคุณจำเป็นต้อง


7
แน่นอนสิ่งเดียวใน namespace ส่วนกลางถ้าคุณทำ 'โมดูลนำเข้า' คือ 'โมดูล'? คุณทำให้เนมสเปซสกปรกหากคุณทำ 'จาก .. นำเข้า *'
John Fouhy

10

ฉันเพิ่งค้นพบความแตกต่างที่ลึกซึ้งยิ่งขึ้นระหว่างวิธีการสองวิธีนี้

หากโมดูลfooใช้การนำเข้าต่อไปนี้:

from itertools import count

จากนั้นโมดูลbarสามารถใช้งานโดยไม่ได้ตั้งใจcountเหมือนว่ามันถูกกำหนดในfooไม่ใช่ในitertools:

import foo
foo.count()

ถ้าfooใช้:

import itertools

ความผิดพลาดยังคงเป็นไปได้ แต่มีโอกาสน้อยที่จะทำ barต้องการ:

import foo
foo.itertools.count()

สิ่งนี้ทำให้ฉันมีปัญหา ฉันมีโมดูลที่นำเข้าข้อยกเว้นจากโมดูลที่ไม่ได้กำหนดโดยไม่ได้ตั้งใจนำเข้าจากโมดูลอื่นเท่านั้น (โดยใช้from module import SomeException) เมื่อไม่จำเป็นต้องนำเข้าและนำออกอีกต่อไปโมดูลที่ละเมิดนั้นก็ขาด


10

นี่คือความแตกต่างอื่นที่ไม่ได้กล่าวถึง สิ่งนี้ถูกคัดลอกคำต่อคำจากhttp://docs.python.org/2/tutorial/modules.html

โปรดทราบว่าเมื่อใช้

from package import item

รายการสามารถเป็นได้ทั้ง submodule (หรือ subpackage) ของแพ็คเกจหรือชื่ออื่น ๆ ที่กำหนดไว้ในแพ็คเกจเช่นฟังก์ชั่นคลาสหรือตัวแปร คำสั่งการนำเข้าจะทำการทดสอบว่ารายการถูกกำหนดไว้ในแพ็คเกจหรือไม่ หากไม่ใช้จะถือว่าเป็นโมดูลและพยายามโหลด หากไม่สามารถค้นหาได้จะมีการยกข้อยกเว้น ImportError

ตรงกันข้ามเมื่อใช้ไวยากรณ์เช่น

import item.subitem.subsubitem

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


สิ่งที่ผมสังเกตเห็นก็คือว่าถ้ารายการยังเป็น submodule ภายในแพคเกจแล้ว "จากแพคเกจรายการนำเข้า" ผลงาน แต่ "แพคเกจนำเข้า" package.item.subitem = ... ไม่ได้ทำงานกับที่ว่างเปล่าinit .py ของแพคเกจเว้นแต่ว่าเรา มี "รายการนำเข้า" ในไฟล์initของแพ็คเกจ
Amitoz Dandiana

6

ตั้งแต่ฉันยังเป็นผู้เริ่มต้นฉันจะพยายามอธิบายสิ่งนี้ด้วยวิธีง่าย ๆ : ใน Python เรามีข้อความสามประเภทimportได้แก่ :

1. การนำเข้าทั่วไป:

import math

การนำเข้าประเภทนี้เป็นรายการโปรดส่วนตัวของฉันข้อเสียเพียงอย่างเดียวของเทคนิคการนำเข้านี้คือถ้าคุณต้องการใช้ฟังก์ชันของโมดูลใด ๆ คุณต้องใช้ไวยากรณ์ต่อไปนี้:

math.sqrt(4)

แน่นอนว่ามันจะเพิ่มความพยายามในการพิมพ์ แต่ในฐานะผู้เริ่มต้นมันจะช่วยให้คุณสามารถติดตามโมดูลและฟังก์ชั่นที่เกี่ยวข้องได้ (ตัวแก้ไขข้อความที่ดีจะลดความพยายามในการพิมพ์ลงอย่างมากและแนะนำ)

ความพยายามพิมพ์สามารถลดลงได้อีกโดยใช้คำสั่งนำเข้านี้:

import math as m

ตอนนี้แทนการใช้คุณสามารถใช้math.sqrt()m.sqrt()

2. ฟังก์ชั่นการนำเข้า:

from math import sqrt

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

3. การนำเข้าสากล:

from math import * 

แม้ว่าจะลดความพยายามในการพิมพ์ลงอย่างมาก แต่ไม่แนะนำเพราะมันจะเติมรหัสของคุณด้วยฟังก์ชั่นต่าง ๆ จากโมดูลและชื่อของพวกเขาอาจขัดแย้งกับชื่อของฟังก์ชั่นที่ผู้ใช้กำหนด ตัวอย่าง:

หากคุณมีฟังก์ชั่นของ sqrt ชื่อของคุณเองและคุณนำเข้าคณิตศาสตร์ฟังก์ชั่นของคุณมีความปลอดภัย: มี sqrt ของคุณและมี math.sqrt อย่างไรก็ตามถ้าคุณทำจากการนำเข้าทางคณิตศาสตร์ * คุณมีปัญหา: นั่นคือสองฟังก์ชันที่แตกต่างกันที่มีชื่อเดียวกันแน่นอน ที่มา: Codecademy


5
import package
import module

ด้วยimportโทเค็นจะต้องเป็นโมดูล (ไฟล์ที่มีคำสั่ง Python) หรือแพคเกจ (โฟลเดอร์ในsys.pathไฟล์ที่มี__init__.py)

เมื่อมีแพ็คเกจย่อย:

import package1.package2.package
import package1.package2.module

ข้อกำหนดสำหรับโฟลเดอร์ (แพ็คเกจ) หรือไฟล์ (โมดูล) เหมือนกัน แต่โฟลเดอร์หรือไฟล์ต้องอยู่ภายในpackage2ซึ่งต้องอยู่ข้างในpackage1และทั้งสองpackage1และpackage2ต้องมี__init__.pyไฟล์ https://docs.python.org/2/tutorial/modules.html

ด้วยfromรูปแบบของการนำเข้า:

from package1.package2 import package
from package1.package2 import module

แพคเกจหรือโมดูลเข้า namespace ของไฟล์ที่มีการimportคำสั่งเป็นmodule(หรือpackage) package1.package2.moduleแทน คุณสามารถผูกกับชื่อที่สะดวกกว่าได้เสมอ:

a = big_package_name.subpackage.even_longer_subpackage_name.function

fromสไตล์การนำเข้าเท่านั้นที่อนุญาตให้คุณตั้งชื่อฟังก์ชันหรือตัวแปรเฉพาะ:

from package3.module import some_function

ได้รับอนุญาต แต่

import package3.module.some_function 

ไม่อนุญาต


4

หากต้องการเพิ่มสิ่งที่ผู้คนพูดถึงfrom x import *: นอกจากทำให้ยากที่จะบอกว่าชื่อมาจากไหนแล้วสิ่งนี้จะทำให้ตัวตรวจสอบรหัสเช่น Pylint พวกเขาจะรายงานชื่อเหล่านั้นว่าเป็นตัวแปรที่ไม่ได้กำหนด


3

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

Usuaully ฉันชอบสไตล์การบันทึกด้วยตนเองของการนำเข้าแบบธรรมดาและเปลี่ยนจาก .. นำเข้าเมื่อจำนวนครั้งที่ฉันต้องพิมพ์ชื่อโมดูลเติบโตมากกว่า 10 ถึง 20 แม้ว่าจะมีเพียงโมดูลเดียวเท่านั้นที่นำเข้า


1

หนึ่งในความแตกต่างที่สำคัญที่ฉันพบว่าไม่มีใครพูดถึงอย่างน่าประหลาดใจคือการใช้การนำเข้าแบบธรรมดาคุณสามารถเข้าถึงprivate variableและprivate functionsจากโมดูลที่นำเข้าซึ่งไม่สามารถทำได้ด้วยคำสั่งจากการนำเข้า

ป้อนคำอธิบายรูปภาพที่นี่

รหัสในภาพ:

setting.py

public_variable = 42
_private_variable = 141
def public_function():
    print("I'm a public function! yay!")
def _private_function():
    print("Ain't nobody accessing me from another module...usually")

plain_importer.py

import settings
print (settings._private_variable)
print (settings.public_variable)
settings.public_function()
settings._private_function()

# Prints:
# 141
# 42
# I'm a public function! yay!
# Ain't nobody accessing me from another module...usually

from_importer.py

from settings import *
#print (_private_variable) #doesn't work
print (public_variable)
public_function()
#_private_function()   #doesn't work

0

นำเข้าโมดูล - คุณไม่ต้องการความพยายามเพิ่มเติมในการดึงสิ่งอื่นจากโมดูล มันมีข้อเสียเช่นการพิมพ์ซ้ำซ้อน

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


0

มีบางโมดูลในตัวที่มีฟังก์ชั่นเปลือยส่วนใหญ่ ( base64 , คณิตศาสตร์ , ระบบปฏิบัติการ , shutil , sys , เวลา , ... ) และเป็นวิธีปฏิบัติที่ดีที่จะมีฟังก์ชั่นเปล่า ๆ เหล่านี้ผูกติดกับเนมสเปซบางส่วน รหัส. พิจารณาว่าการเข้าใจความหมายของฟังก์ชั่นเหล่านี้ยากขึ้นเพียงใดโดยไม่มีเนมสเปซ:

copysign(foo, bar)
monotonic()
copystat(foo, bar)

กว่าเมื่อพวกเขาถูกผูกไว้กับโมดูลบางส่วน:

math.copysign(foo, bar)
time.monotonic()
shutil.copystat(foo, bar)

บางครั้งคุณต้องใช้เนมสเปซเพื่อหลีกเลี่ยงความขัดแย้งระหว่างโมดูลต่าง ๆ ( json.load vs. pickle.load )


ในทางกลับกันมีบางโมดูลที่มีคลาสส่วนใหญ่ ( configparser , datetime , tempfile , zipfile , ... ) และอีกหลายโมดูลทำให้ชื่อคลาสของพวกเขาอธิบายตัวเองได้ดีพอ:

configparser.RawConfigParser()
datetime.DateTime()
email.message.EmailMessage()
tempfile.NamedTemporaryFile()
zipfile.ZipFile()

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


0

ฉันต้องการเพิ่มสิ่งนี้มีสิ่งที่ต้องพิจารณาระหว่างการโทรเข้า:

ฉันมีโครงสร้างต่อไปนี้:

mod/
    __init__.py
    main.py
    a.py
    b.py
    c.py
    d.py

main.py:

import mod.a
import mod.b as b
from mod import c
import d

dis.dis แสดงความแตกต่าง:

  1           0 LOAD_CONST               0 (-1)
              3 LOAD_CONST               1 (None)
              6 IMPORT_NAME              0 (mod.a)
              9 STORE_NAME               1 (mod)

  2          12 LOAD_CONST               0 (-1)
             15 LOAD_CONST               1 (None)
             18 IMPORT_NAME              2 (b)
             21 STORE_NAME               2 (b)

  3          24 LOAD_CONST               0 (-1)
             27 LOAD_CONST               2 (('c',))
             30 IMPORT_NAME              1 (mod)
             33 IMPORT_FROM              3 (c)
             36 STORE_NAME               3 (c)
             39 POP_TOP

  4          40 LOAD_CONST               0 (-1)
             43 LOAD_CONST               1 (None)
             46 IMPORT_NAME              4 (mod.d)
             49 LOAD_ATTR                5 (d)
             52 STORE_NAME               5 (d)
             55 LOAD_CONST               1 (None)

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

example1

foo/
   __init__.py
   a.py
   b.py
a.py:
import foo.b 
b.py:
import foo.a
>>> import foo.a
>>>

วิธีนี้ใช้ได้ผล

example2

bar/
   __init__.py
   a.py
   b.py
a.py:
import bar.b as b
b.py:
import bar.a as a
>>> import bar.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "bar\a.py", line 1, in <module>
    import bar.b as b
  File "bar\b.py", line 1, in <module>
    import bar.a as a
AttributeError: 'module' object has no attribute 'a'

ไม่มีลูกเต๋า

ตัวอย่างที่ 3

baz/
   __init__.py
   a.py
   b.py
a.py:
from baz import b
b.py:
from baz import a
>>> import baz.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "baz\a.py", line 1, in <module>
    from baz import b
  File "baz\b.py", line 1, in <module>
    from baz import a
ImportError: cannot import name a

ปัญหาที่คล้ายกัน ... แต่ชัดเจนจาก x import y ไม่เหมือนกับ import import xy เป็น y

Example4

qux/
   __init__.py
   a.py
   b.py
a.py:
import b 
b.py:
import a
>>> import qux.a
>>>

อันนี้ยังใช้งานได้


0

นี่คือโครงสร้างไดเรกทอรีของฉันในไดเรกทอรีปัจจุบันของฉัน:

.  
└─a  
   └─b  
     └─c
  1. importคำสั่งจำชื่อกลางทั้งหมด
    ชื่อเหล่านี้จะต้องผ่านการรับรอง:

    In[1]: import a.b.c
    
    In[2]: a
    Out[2]: <module 'a' (namespace)>
    
    In[3]: a.b
    Out[3]: <module 'a.b' (namespace)>
    
    In[4]: a.b.c
    Out[4]: <module 'a.b.c' (namespace)>
  2. from ... import ...คำสั่งจำได้เพียงชื่อที่นำเข้า
    ชื่อนี้จะต้องไม่ผ่านการรับรอง:

    In[1]: from a.b import c
    
    In[2]: a
    NameError: name 'a' is not defined
    
    In[2]: a.b
    NameError: name 'a' is not defined
    
    In[3]: a.b.c
    NameError: name 'a' is not defined
    
    In[4]: c
    Out[4]: <module 'a.b.c' (namespace)>

  • หมายเหตุ:แน่นอนฉันรีสตาร์ทคอนโซล Python ระหว่างขั้นตอนที่ 1 และ 2

0

ตามที่Jan Wrobelกล่าวถึงการนำเข้าที่แตกต่างกันอย่างหนึ่งคือการเปิดเผยการนำเข้า

โมดูลmymath

from math import gcd
...

การใช้mymath :

import mymath
mymath.gcd(30, 42)  # will work though maybe not expected

หากฉันนำเข้าgcdเฉพาะสำหรับใช้ภายในเท่านั้นไม่เปิดเผยให้ผู้ใช้ทราบmymathสิ่งนี้อาจไม่สะดวก ฉันมีสิ่งนี้ค่อนข้างบ่อยและในกรณีส่วนใหญ่ฉันต้องการ "ทำให้โมดูลของฉันสะอาด"

นอกเหนือจากข้อเสนอของJan Wrobelเพื่อปิดบังเรื่องนี้เพิ่มขึ้นอีกเล็กน้อยโดยใช้import mathแทนฉันได้เริ่มซ่อนการนำเข้าจากการเปิดเผยโดยใช้ขีดเส้นใต้ชั้นนำ:

# for instance...
from math import gcd as _gcd
# or...
import math as _math

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

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