2010-06-22 41 views
3

比方說,我有3個文件:python中的導入關鍵字如何實際工作?

a.py

from d import d 

class a: 
    def type(self): 
     return "a" 
    def test(self): 
     try: 
      x = b() 
     except: 
      print "EXCEPT IN A" 
      from b import b 
      x = b() 
     return x.type() 

b.py

import sys 

class b: 
    def __init__(self): 
     if "a" not in sys.modules: 
      print "Importing a!" 
      from a import a 
     pass 
    def type(self): 
     return "b" 
    def test(self): 
     for modules in sys.modules: 
      print modules 
     x = a() 
     return x.type() 

c.py

from b import b 
import sys 

x = b() 
print x.test() 

和運行蟒蛇c.py

Python帶有背面抱怨:

NameError: global name 'a' is not defined

但是,在sys.modules中A爲:

copy_reg 
sre_compile 
locale 
_sre 
functools 
encodings 
site 
__builtin__ 
operator 
__main__ 
types 
encodings.encodings 
abc 
errno 
encodings.codecs 
sre_constants 
re 
_abcoll 
ntpath 
_codecs 
nt 
_warnings 
genericpath 
stat 
zipimport 
encodings.__builtin__ 
warnings 
UserDict 
encodings.cp1252 
sys 
a 
codecs 
os.path 
_functools 
_locale 
b 
d 
signal 
linecache 
encodings.aliases 
exceptions 
sre_parse 
os 

,我還可以改變b.py使得:

X = A()
更改爲
x = sys.modules [「a」]。a()

而python會很高興地運行它。

一對夫婦從這個出現的問題:

爲什麼蟒蛇說,這不知道是,當它在sys.modules中呢?
正在使用sys.modules「適當」的方式來訪問類和函數的定義?
什麼是導入模塊的「正確」方式?
即 從模塊的進口X

導入模塊

回答

3

我想這是作用域的問題,如果你輸入你的構造模塊,你只能在構造函數中使用它,import語句之後。

0

根據程序邏輯條件導入代碼模塊是不好的方式。在你的代碼中,一個名字應該總是意味着同樣的東西。想想如何混亂,這將是調試:

if (something) 
    from office import desk 
else 
    from home import desk 

... somewhere later in the code... 
desk() 

即使你沒有範圍的問題(你很可能會),它仍然撲朔迷離。

將所有導入語句放在文件頂部。這就是其他編碼人員會尋找他們的地方。至於是否使用「from foo import bar」verses只是「import foo」,折衷更多的是鍵入(不得不鍵入「foo.bar()」或只是鍵入「bar()」)和清晰度和特異性。如果你想讓你的代碼真正可讀並且毫不含糊,只需說「import foo」,並在任何地方完全指定呼叫。請記住,閱讀代碼比編寫代碼要困難得多。

+2

其實,當你有一個可選的依賴項時,這可能是一個非常好的功能。它遍佈Python標準庫。主要的是要確保你聲明的任何標記(在這種情況下爲「桌面」)在某種意義上需要是「等價的」。也就是說,你要麼使用'office'的'desk'實現,要麼使用'home'的'desk'實現,但它們都是辦公桌,所以你可以對其中的任何一個做同樣的事情。 – 2010-06-22 15:58:59

+0

我可以看到有關創建可選依賴項的唯一好處是它是一種性能破壞。無論用戶需要什麼功能,您都可以導入所有依賴項,但涉及的內存使用量超過您可能會喜歡使用的內存量,並且可能會降低性能。這可能是爲什麼他們在標準庫中使用可選的導入。性能攻擊通常會弄糟代碼,使其不易讀,這也不例外。最清楚的事情就是始終將導入放在文件頂部 - 這在我所知道的幾乎所有編程語言中都適用。 – eeeeaaii 2010-06-22 16:42:37

1

在你的情況,a是在sys.modules ..但不是在sys.modules中的所有東西都在b的範圍內。如果你想使用re,你也必須導入。

有條件的導入有時是可以接受的,但這不是其中的一種。首先,在這種情況下,a和b之間的循環依賴是不幸的,應該避免(在Fowler的重構中有很多模式)。也就是說,沒有必要有條件地在這裏導入。

b應該簡單地導入一個。通過不直接在文件頂部導入它,你試圖避免什麼?

+0

我正在做一些測試,並忘記更改原來的代碼。最初我有一個導入b和b導入a。這就是爲什麼我將它作爲條件導入移動的原因。 – 2010-06-22 15:53:26

2

the Python documentation

Import statements are executed in two steps: (1) find a module, and initialize it if necessary; (2) define a name or names in the local namespace (of the scope where the import statement occurs).

所以問題是,即使模塊a已經進口的,名字a只被在b.__init__方法,而不是b.py整個範圍上的約束。所以在b.test方法中,不存在這樣的名稱a,所以你得到一個NameError

您可能想要閱讀這個article on importing Python modules,因爲它有助於解釋使用import s的最佳實踐。