如何在Python中進行相對導入?

想象一下這個目錄結構: python

app/
   __init__.py
   sub1/
      __init__.py
      mod1.py
   sub2/
      __init__.py
      mod2.py

我正在編碼mod1 ,我須要從mod2導入一些東西。 我該怎麼辦? app

我嘗試from ..sub2 import mod2嘗試from ..sub2 import mod2但出現「未打包的相對嘗試導入」。 測試

我四處搜尋,但只發現「 sys.path操縱」黑客。 有沒有一種乾淨的方法? 編碼


編輯:我全部的__init__.py當前爲空 spa

Edit2:我正在嘗試執行此操做,由於sub2包含跨子包( sub1subX等)共享的類。 code

Edit3:我要尋找的行爲與PEP 366中描述的相同(感謝John B) ip


#1樓

def import_path(fullpath):
    """ 
    Import a file with full path specification. Allows one to
    import from anywhere, something __import__ does not do. 
    """
    path, filename = os.path.split(fullpath)
    filename, ext = os.path.splitext(filename)
    sys.path.append(path)
    module = __import__(filename)
    reload(module) # Might be out of date
    del sys.path[-1]
    return module

我正在使用此代碼片斷從路徑導入模塊,但願對您有所幫助 ci


#2樓

除了John B所說的之外,設置__package__變量彷佛應該有所幫助,而不是更改__main__可能會搞砸其餘事情。 可是據我測試,它並不能徹底正常工做。 字符串

我遇到了一樣的問題,而據我所知,PEP 328或366都沒法徹底解決問題,由於二者在一天結束時都須要將程序包的頭包含在sys.pathget

我還要提到的是,我沒有找到如何格式化應放入這些變量的字符串的格式。 是"package_head.subfolder.module_name"仍是什麼?


#3樓

讓我將其放在此處以供我本身參考。 我知道這不是很好的Python代碼,可是我須要一個腳原本處理我正在從事的項目,因此我想將該腳本放在scripts目錄中。

import os.path
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

#4樓

這是對我有效的解決方案:

from ..sub2 import mod2進行相對from ..sub2 import mod2 ,而後,若是我想運行mod1.py則轉到app的父目錄,並使用python -m開關做爲python -m app.sub1.mod1運行模塊python -m app.sub1.mod1

相對導入發生此問題的真正緣由是,相對導入經過採用模塊的__name__屬性__name__ 。 若是模塊直接運行,則__name__設置爲__main__ ,而且不包含有關包結構的任何信息。 而且,這就是爲何python抱怨relative import in non-package錯誤中的relative import in non-package

所以,經過使用-m開關,您能夠將包結構信息提供給python,經過它能夠成功解析相對導入。

在進行相對導入時,我屢次遇到此問題。 並且,在閱讀了全部先前的答案以後,我仍然沒法弄清楚如何解決此問題,而無需在全部文件中都放入樣板代碼。 (儘管有些評論確實頗有幫助,這要感謝@ncoghlan和@XiongChiamiov)

但願這對正在解決相對進口問題的人有所幫助,由於經過PEP確實頗有趣。


#5樓

用示例解釋nosklo's答案

注意:全部__init__.py文件均爲空。

main.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       fun_a.py
    package_b/ ->
       __init__.py
       fun_b.py

app / package_a / fun_a.py

def print_a():
    print 'This is a function in dir package_a'

app / package_b / fun_b.py

from app.package_a.fun_a import print_a
def print_b():
    print 'This is a function in dir package_b'
    print 'going to call a function in dir package_a'
    print '-'*30
    print_a()

main.py

from app.package_b import fun_b
fun_b.print_b()

若是運行$ python main.py它將返回:

This is a function in dir package_b
going to call a function in dir package_a
------------------------------
This is a function in dir package_a
  • main.py能夠: from app.package_b import fun_b
  • fun_b.py from app.package_a.fun_a import print_a

所以,文件夾package_b中的文件使用了文件夾package_a中的文件,這就是您想要的。 對??

相關文章
相關標籤/搜索