2017-03-19 121 views
2

我嘗試了一些不同的技術,試圖做一些對我來說似乎可行的,但我想我缺少一些關於python的疑難解答(使用2.7,但也希望這樣做也爲3。如果可能的話)。Python中模塊的相對路徑

我不確定像包或模塊這樣的術語,但對我來說,下面看起來相當「簡單」可行的場景。

這是目錄結構:

. 
├── job 
│   └── the_script.py 
└── modules 
   ├── __init__.py 
   └── print_module.py 

the_script.py內容:

# this does not work 
import importlib 
print_module = importlib.import_module('.print_module', '..modules') 

# this also does not work 
from ..modules import print_module 

print_module.do_stuff() 

print_module內容:

def do_stuff(): 
    print("This should be in stdout") 

我想運行這些「相對路徑「的東西爲:

/job$ python2 the_script.py 

importlib.import_module給出各種錯誤:

  • 如果我只使用1個輸入參數..modules.print_module,然後我得到:TypeError("relative imports require the 'package' argument")
  • 如果使用2個輸入參數(如在上面的例子中),然後我得到:ValueError: Empty module name

在使用from ..modules語法我得到的另一方面:ValueError: Attempted relative import in non-package

我認爲__init__.py空文件應該足以將代碼限定爲「包」(或模塊?不確定術語),但似乎我缺少有關如何管理相對路徑的信息。

我看,在過去的人被盜號這個利用import osimport syspath等功能,但根據官方文檔(Python 2.7版和3 *)這不應該不再需要。

我在做什麼錯,我怎麼能達到打印內容的效果modules/print_module.do_stuff從「相對目錄」中的腳本調用它job/

+0

爲什麼你會在這裏使用importlib?爲什麼不直接導入? –

+1

'__init __。py'只爲它所在的目錄創建一個包。你需要在顯示的樹中的所有目錄中添加__init __。py。您還需要確保包含頂級軟件包目錄的目錄位於'sys.path'上,並且如果您希望能夠將其中一個文件作爲腳本執行,則需要考慮這些問題描述[這裏](http://stackoverflow.com/questions/11536764/how-to-fix-attempted-relative-im-port-in-non-package-even-with-init-py)和[這裏](http: //stackoverflow.com/questions/14132789/relative-imports-for-the-billionth-time)。 – BrenBarn

回答

1

我發現使用sysos的解決方案。

腳本the_script.py應該是:

import sys 
import os 
lib_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../modules')) 
sys.path.append(lib_path) 

# commenting out the following shows the `modules` directory in the path 
# print(sys.path) 

import print_module 

print_module.do_stuff() 

然後我可以通過命令行運行它,不管我在哪裏路徑例如:

  • /job$ python2 the_script.py
  • <...>/job$ python2 <...>/job/the_script.py
1

如果您按照這裏本指南的結構:http://docs.python-guide.org/en/latest/writing/structure/#test-suite(強烈建議你閱讀這一切,這是非常有幫助的),你會看到:

To give the individual tests import context, create a tests/context.py file:

import os 
import sys 
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) 

import sample 

Then, within the individual test modules, import the module like so:

from .context import sample 

This will always work as expected, regardless of installation method.

你的情況進行翻譯,這意味着:

root_folder 
├── job 
│ ├── context.py <- create this file 
│ └── the_script.py 
└── modules 
    ├── __init__.py 
    └── print_module.py 

context.py文件寫入上面所示的線,但代替import modulesimport samples

網絡連接最後在你的the_script.pyfrom .context import module,你將會開始!

祝你好運:)

+0

謝謝:)但這給了:'ImportError:沒有模塊命名modules.print_module' – TPPZ

+0

我已經更新了我的答案,這可能會有所幫助! –

+0

在python 2中給出了'ImportError:No module named airflow_stuff.modules.print_module',在python 3中它給出了一個類似的錯誤信息 – TPPZ

1

如果您不能確定有關術語去非常好的教程:

http://docs.python-guide.org/en/latest/writing/structure/#modules

http://docs.python-guide.org/en/latest/writing/structure/#packages

但對你的結構:

. 
├── job 
│ └── the_script.py 
└── modules 
    ├── __init__.py 
    └── print_module.py 

只是說在the_script.py

import sys 
sys.append('..') 
import modules.print_module 

這將父目錄添加到PYTHONPATH和Python會看到目錄「平行」到工作目錄,它會工作。

我認爲,在最基本的層面是sufficent知道:

  1. __init__.py文件中的任何目錄
  2. 模塊.py文件,但是當你導入模塊你省略了擴展名。
+0

感謝您指出文檔:)但這給了:'ImportError:沒有模塊命名模塊。print_module' – TPPZ

+0

我改正了答案:) – jedruniu

+1

在python 2中,這給出了'AttributeError:'模塊'對象沒有屬性'append'',但是如果我把'sys.path.append('..')',那麼這個給出'ImportError:No module named modules.print_module'。在python 3中,它給出了類似的錯誤消息。 – TPPZ