วิธีการนำเข้าคลาสที่กำหนดไว้ใน __init__.py


105

ฉันกำลังพยายามจัดระเบียบโมดูลสำหรับการใช้งานของฉันเอง ฉันมีสิ่งนี้:

lib/
  __init__.py
  settings.py
  foo/
    __init__.py
    someobject.py
  bar/
    __init__.py
    somethingelse.py

ในlib/__init__.pyฉันต้องการกำหนดคลาสบางคลาสที่จะใช้หากฉันนำเข้า lib อย่างไรก็ตามฉันไม่สามารถเข้าใจได้โดยไม่ต้องแยกคลาสออกเป็นไฟล์และนำเข้าใน__init__.pyไฟล์.

แทนที่จะพูดว่า:

    lib/
      __init__.py
      settings.py
      helperclass.py
      foo/
        __init__.py
        someobject.py
      bar/
        __init__.py
        somethingelse.py

from lib.settings import Values
from lib.helperclass import Helper

ฉันต้องการสิ่งนี้:

    lib/
      __init__.py  #Helper defined in this file
      settings.py
      foo/
        __init__.py
        someobject.py
      bar/
        __init__.py
        somethingelse.py

from lib.settings import Values
from lib import Helper

เป็นไปได้ไหมหรือฉันต้องแยกคลาสเป็นไฟล์อื่น

แก้ไข

ตกลงถ้าฉันนำเข้า lib จากสคริปต์อื่นฉันสามารถเข้าถึงคลาส Helper ได้ ฉันจะเข้าถึงคลาส Helper จาก settings.py ได้อย่างไร

ตัวอย่างที่นี่อธิบายการอ้างอิงภายในแพ็คเกจ ฉันอ้างว่า "โมดูลย่อยมักต้องอ้างถึงกันและกัน" ในกรณีของฉัน lib.settings.py ต้องการ Helper และ lib.foo.someobject ต้องการการเข้าถึง Helper ดังนั้นฉันควรกำหนดคลาส Helper ที่ไหน


ตัวอย่างสุดท้ายของคุณควรใช้งานได้ คุณเห็น ImportError หรือไม่ แปะรายละเอียดได้ไหม
Joe Holloway

คำตอบ:


81
  1. ' lib/'s sys.pathไดเรกทอรีแม่จะต้องอยู่ใน

  2. '' ของคุณlib/__init__.pyอาจมีลักษณะดังนี้:

    from . import settings # or just 'import settings' on old Python versions
    class Helper(object):
          pass

จากนั้นตัวอย่างต่อไปนี้ควรใช้งานได้:

from lib.settings import Values
from lib import Helper

ตอบคำถามฉบับแก้ไข:

__init__.pyกำหนดลักษณะของแพ็คเกจของคุณจากภายนอก หากคุณจำเป็นต้องใช้Helperในการsettings.pyระบุHelperในเช่นไฟล์ที่แตกต่างกัน ' lib/helper.py'

.
| `- import_submodule.py
    `- lib
    | - __init__.py
    | - ฟู
    | | - __init__.py
    | `- someobject.py
    | - helper.py
    `- settings.py

2 ไดเร็กทอรี 6 ไฟล์

คำสั่ง:

$ python import_submodule.py

เอาท์พุต:

settings
helper
Helper in lib.settings
someobject
Helper in lib.foo.someobject

# ./import_submodule.py
import fnmatch, os
from lib.settings import Values
from lib import Helper

print
for root, dirs, files in os.walk('.'):
    for f in fnmatch.filter(files, '*.py'):
        print "# %s/%s" % (os.path.basename(root), f)
        print open(os.path.join(root, f)).read()
        print


# lib/helper.py
print 'helper'
class Helper(object):
    def __init__(self, module_name):
        print "Helper in", module_name


# lib/settings.py
print "settings"
import helper

class Values(object):
    pass

helper.Helper(__name__)


# lib/__init__.py
#from __future__ import absolute_import
import settings, foo.someobject, helper

Helper = helper.Helper


# foo/someobject.py
print "someobject"
from .. import helper

helper.Helper(__name__)


# foo/__init__.py
import someobject

ฉันจะนำเข้าคลาส Helper ในไฟล์ settings.py ในตัวอย่างได้อย่างไร
scottm

ฉันไม่เข้าใจว่าทำไมถึงเป็นวงกลม หาก settings.py ต้องการตัวช่วยและพูดว่า foo.someobject.py ต้องการตัวช่วยคุณจะแนะนำให้ฉันกำหนดได้จากที่ไหน
scottm

ว้าวคำว่า "ตัวช่วย" เริ่มมีความหมายหลวม ๆ ในตัวอย่างนั้น อย่างไรก็ตามคุณได้แสดงให้ฉันเห็นแล้วว่าฉันกำลังมองหาอะไร
scottm

3
ได้รับการโหวตให้ "__init__.py กำหนดลักษณะของแพ็กเกจของคุณจากภายนอก"
Petri

20

หากlib/__init__.pyกำหนดคลาส Helper แล้วใน settings.py คุณสามารถใช้:

from . import Helper

สิ่งนี้ได้ผลเพราะ. คือไดเร็กทอรีปัจจุบันและทำหน้าที่เป็นคำพ้องความหมายสำหรับแพ็คเกจ lib จากมุมมองของโมดูลการตั้งค่า __all__หมายเหตุว่ามันไม่จำเป็นที่จะต้องส่งออกผ่านทางผู้ช่วย

(ยืนยันด้วย python 2.7.10 ทำงานบน Windows)


1
วิธีนี้ใช้ได้ดีสำหรับฉันผู้ลงคะแนนโปรดอธิบายความไม่พอใจของคุณ?
โยโย่

8

คุณใส่ไว้ใน __init__.py

ดังนั้นด้วยการทดสอบ / class.py เป็น:

class A(object): pass
class B(object): pass

... และทดสอบ / __ init__.py เป็น:

from classes import *

class Helper(object): pass

คุณสามารถนำเข้าการทดสอบและเข้าถึง A, B และ Helper ได้

>>> import test
>>> test.A
<class 'test.classes.A'>
>>> test.B
<class 'test.classes.B'>
>>> test.Helper
<class 'test.Helper'>

คุณกำลังนำเข้าจากที่ไหน
Aaron Maenpaa

สมมติว่าต้องการนำเข้า Helper จาก lib / settings.py?
scottm

1
นั่นแทบจะทำให้เกิดการนำเข้าแบบวงกลม (การตั้งค่าจะนำเข้าการทดสอบและการทดสอบจะนำเข้าการตั้งค่า) ... ซึ่งจะสร้าง NameError ที่คุณอธิบาย หากคุณต้องการตัวช่วยที่ใช้ภายในแพ็คเกจคุณควรกำหนดโมดูลภายในที่รหัสของคุณใช้
Aaron Maenpaa

1
ผู้ช่วยเหลือในinit. py ควรมีไว้สำหรับผู้ใช้ภายนอกเพื่อทำให้ API ของคุณง่ายขึ้น
Aaron Maenpaa

1
หากไม่ได้เป็นส่วนหนึ่งของ API แสดงว่าinit. py ไม่ใช่ที่สำหรับมัน lib / internal.py หรือคล้ายกันจะดีกว่ามาก (ซึ่งมีจุดประสงค์สองครั้งในการลดโอกาสในการนำเข้าแบบวงกลม)
Aaron Maenpaa

5

เพิ่มสิ่งนี้ลงใน lib/__init__.py

from .helperclass import Helper

ตอนนี้คุณสามารถนำเข้าได้โดยตรง:

from lib import Helper


4

แก้ไขเนื่องจากฉันเข้าใจคำถามผิด:

เพียงแค่ใส่ชั้นในHelper __init__.pyนั่นคือ pythonic ที่สมบูรณ์แบบ มันรู้สึกแปลก ๆ ที่มาจากภาษาเช่น Java


คุณเข้าใจผิด ฉันต้องการลบไฟล์ helperClass.py ถ้าเป็นไปได้
scottm

ริชาร์ดไม่ใช่คนเดียวที่เข้าใจผิด ตัวอย่างของคุณควรใช้งานได้ การย้อนกลับคืออะไร?
Troy J.Farrell

ถ้าอย่างนั้นฉันก็อ่านเอกสารอย่างถูกต้อง ตอนนี้ฉันเพิ่งทำกรณีทดสอบและใช้งานได้ดี
scottm

ฉันมีการตั้งค่าเดียวกันในแพ็คเกจของฉัน แต่ฉันได้รับ ImportError "ไม่สามารถนำเข้าชื่อผู้ช่วย"
scottm

ฉันคิดว่าปัญหาของฉันคือฉันกำลังพยายามนำเข้าคลาส Helper จาก settings.py ฉันจะทำเช่นนั้นได้อย่างไร
scottm

2

ใช่มันเป็นไปได้ คุณอาจต้องการกำหนด__all__ใน__init__.pyไฟล์ เป็นรายชื่อโมดูลที่จะนำเข้าเมื่อคุณทำ

from lib import *

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