[英]Namespaces with Module Imports
盡管我已經學習Python大約一年了,但是我正在學習Python並仍然是一個初學者。 我正在嘗試編寫一個在主模塊中調用的功能模塊。 被調用模塊中的每個函數都需要math模塊才能運行。 我想知道是否有一種方法可以不將數學模塊導入被調用模塊中。 這是我所擁有的:
main.py
:
from math import *
import module1
def wow():
print pi
wow()
module1.cool()
module1.py
:
def cool():
print pi
運行main.py
我得到:
3.14159265359
Traceback (most recent call last):
File "Z:\Python\main.py", line 10, in <module>
module1.cool()
File "Z:\Python\module1.py", line 3, in cool
print pi
NameError: global name 'pi' is not defined
我很難理解的是為什么在運行main.py
時出現名稱錯誤。 我知道變量pi
在導入時對主模塊變為全局,因為wow
可以訪問它。 我也知道cool
在導入時成為主模塊的全局對象,因為我可以打印module1.cool
並獲取<function cool at 0x02B11AF0>
。 因此,由於cool
在主模塊的全局命名空間中,因此程序不應該首先在變量cool
內部查找pi
,然后在其中找不到它時,在main
模塊內部查找 pi
並查找在那嗎?
解決此問題的唯一方法是將math模塊導入module1.py
。 我不喜歡這樣的想法,盡管因為它會使事情變得更復雜,並且我喜歡漂亮,簡單的代碼。 我覺得我即將掌握名稱空間,但是在這方面需要幫助。 謝謝。
如回溯所示,問題不在main.py
,而在module1.py
:
Traceback (most recent call last):
File "Z:\Python\main.py", line 10, in <module>
module1.cool()
File "Z:\Python\module1.py", line 3, in cool
print pi
NameError: global name 'pi' is not defined
換句話說, 在module1
,沒有全局名稱pi
,因為您尚未將其導入。 from math import *
main.py
from math import *
main.py
,這只是將所有內容從math
模塊的命名空間導入到main
模塊的命名空間中,而不是導入到每個模塊的命名空間中。
我認為您在這里缺少的關鍵是每個模塊都有自己的“全局”名稱空間。 剛開始時這可能有點令人困惑,因為在諸如C之類的語言中,所有extern
變量和函數共享一個全局名稱空間。 但是一旦您克服了這個假設,Python的方式就很有意義了。
所以,如果你想使用pi
從module1
,你所要做的from math import *
在module1.py
。 (或者,您可以找到其他方式注入它—例如, module1.py
可以from main import *
,或者main.py
可以進行module1.pi = pi
,等等。或者您可以將pi
塞入神奇的builtins
/ __builtin__
模塊,或使用其他各種技巧。但顯而易見的解決方案是在要import
位置進行導入。)
附帶說明一下,您通常不希望from foo import *
進行交互交互式解釋器或頂級腳本之外的任何操作。 也有例外(例如,一些模塊明確設計為以這種方式使用),但經驗法則是import foo
或使用from foo import bar, baz
。
“顯式勝於隱式”是Python的創建者做出的設計決定(啟動python並運行import this
)。
因此,當您運行module1.cool()
,Python不會在main
模塊中查找未定義的pi
。
每當需要使用數學模塊時,都必須顯式導入它-這就是Python的工作方式。
另外,您應避免from X import *
-style導入,這也是一種不好的做法。 在這里,您可以執行以下操作: from math import pi
。
@abarnert的注釋中提到的exec
(python 3)或execfile
(python 2)的簡單方法可能對某些工作流程很有用。 所需要做的就是將導入行替換為:
exec( open("module1.py").read() ) # python 3
然后您可以簡單地使用cool()
而不是module1.cool()
調用函數。 在cool()
,變量pi
行為將像全局變量一樣,如OP最初期望的那樣。
簡而言之,這只是隱藏了一個函數定義,否則該函數定義將出現在主程序的頂部,並且具有優點和缺點。 對於具有多個模塊和導入的大型項目,使用exec
(而不是適當的名稱空間)可能是一個錯誤,因為您通常不希望在單個全局名稱空間中保留太多內容。
但是對於簡單的情況(例如使用Python作為shell腳本), exec
提供了一種簡單明了的方法來隱藏共享函數,同時讓它們共享全局名稱空間。 請注意,在這種情況下,您可能需要進一步考慮函數的命名方式(例如,使用v1_cool
和v2_cool
來跟蹤不同的版本,因為您無法執行v1.cool
和v2.cool
)。
在這里使用exec
一個不太明顯的缺點是,盡管您可以解決此問題,但是執行的代碼中的錯誤可能不會顯示錯誤的行號: 如何在Python中從exec或execfile獲取錯誤的行號
就像其他人所說的那樣,您的module1
實際上沒有全局pi
。 一個很好的解決方案是,它僅從math
導入pi
一次,並明確確保您獲取的pi
是從module1
獲取的pi
:
main.py
:
import module1
def wow():
print module1.pi
wow()
module1.cool()
module1.py
:
from math import pi
def cool():
print pi
在模塊內部,您可以簡單地from math import pi
定義,這只會from math import pi
,而不是整個math模塊。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.