天天看點

Python module

Python 子產品導入

請注意,通常不贊成*從子產品或包中導入的做法,因為它通常會導緻代碼可讀性差。但是,可以使用它來儲存互動式會話中的輸入。

import fibo    # 隐式相對導入
from fibo import fibo1, fibo2    # 絕對路徑導入
import fibo as fib    # 重命名
from fibo import fib as fibonacci
      

筆記

出于效率原因,每個子產品在每個解釋器會話中僅導入一次。是以,如果您更改您的子產品,您必須重新啟動解釋器——或者,如果它隻是您想要互動式測試的一個子產品,請使用​

​importlib.reload()​

​,例如.

import importlib; 
importlib.reload(modulename)
      

​from package import item​

​,item可以是package的子module,也可以是子package, 還可以是其他各種定義在這個包裡面的變量、類和函數。

​import item.subitem.subsubitem​

​ ,這種文法則要求最後一層item必須是子package,或者子module,不能是item中定義的變量、類或者函數。如果最後一層是一個變量、類或者函數,則在編譯改檔案的時候會報錯ModuleNotFoundError: No module named 'xxx'; 'xxx' is not a package

from <module> import *

包外的可見效是通過在包裡面的__init.py__裡面設定__all__來控制包内的對象和方法等對包外的可見性,如:如果設定了__all__,如果這個包内的類或方法不在__all__裡面,外面的包就不能正常使用這些方法和類。如果沒有設定__all__,那麼外面可以通過包内的約定來顯示可見性。python通過private對應兩個下劃線__,protected對應一個下劃線_,public 對應沒有下劃線,來約定類似于java的可見性控制。

__all__作用是是限制​

​from <module> import *​

​中​

​import​

​的包名。需要注意的是 ​

​__all__​

​ 隻影響到了 ​

​from <module> import *​

​ 這種導入方式,對于 ​

​from <module> import <member>​

​ 導入方式并沒有影響,仍然可以從外部導入。

all__如果在module檔案中,則限制的是module中變量、類和函數的可見性,是以這種情況下__all__變量的元素都是變量名、類名和函數名;如果是在__init.py中,則設定的是該package下的module的可見性,這種情況下,__all__變量的元素都是module名。

├──__init__.py
├── package1
│ ├── __init__.py
│ ├── foo.py 
│ ├── foo1.py
│ └── foo2.py
└──example.py
      

每個檔案的内容分别如下

package1.init.py,在__all__變量中隻定義了"foo1"和"foo2"兩個module,當使用​

​from package1 import *​

​導入package1下的module時,隻會導入foo1和foo2兩個module

__all__ = ["foo1", "foo2"]
      

package1.foo.py

ccc = 5
bar = 10
def baz(): return 'baz'
      

package1.foo1.py

aaa = 123
str = "aaa"
      

package1.foo2.py

bbb = 456
      

example.py

from package1 import *

if __name__ == "__main__":
    print(foo1.aaa)
    print(foo2.bbb)
    print(foo.ccc)    # 報錯,NameError: name 'foo' is not defined
      

因為​

​__all__​

​from <module> import *​

​from <module> import <member>​

​ 導入方式并沒有影響,仍然可以從外部導入。是以我們可以使用​

​from package1 import foo​

​來導入foo這個module。

example.py改成如下,即不會報錯。

from package1 import *
from package1 import foo

if __name__ == "__main__":
    print(foo1.aaa)
    print(foo2.bbb)
    print(foo.ccc)    # 不報錯
      

相對導入

from . import echo    # 表示從目前檔案所在目錄導入echo這個module
from .. import formats    # 表示從目前檔案所在目錄的上層目錄導入formats這個package或者moudle
from ..filters import equalizer # 表示從目前檔案所在目錄的上層目錄的filters這個子package或者子module中導入equalizer
      

相對導入基于目前子產品的名稱。由于主子產品的名稱始終為​

​"__main__"​

​,是以用作 Python 應用程式主子產品的子產品必須始終使用絕對導入。主子產品所在檔案夾不會被視作package,是以除了主子產品外,與主子產品處在同個檔案夾的子產品(也就是同級的子產品)也必須使用絕對導入。

關于相對導入,建議閱讀,能讓你對相對導入有一個深刻的認識,再也不用怕相對導入引起的編譯失敗了。

将子產品作為腳本執行

fibo.py

# Fibonacci numbers module
def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while a < n:
        print(a, end=' ')
        a, b = b, a+b
    print()

def fib2(n):   # return Fibonacci series up to n
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a+b
    return result

if __name__ == "__main__":
    import sys
    fib(int(sys.argv[1]))
      

腳本中的__main__="__name"下的代碼僅在子產品作為“主”檔案執行時才運作:

$ python fibo.py 50
0 1 1 2 3 5 8 13 21 34
      

如果module是作為導入的子產品,則不會執行該子產品的__main__代碼:

>>>import fibo
>>>
      

這通常用于為子產品提供友善的使用者界面,或用于測試目的(将子產品作為腳本執行測試套件運作)。

子產品搜尋路徑

當import一個module時,比如spam,解釋器首先搜尋具有該名稱的内置子產品。如果未找到,它将從​

​sys.path​

​這個目錄清單中搜尋spam.py這個檔案。 ​

​sys.path​

​初始狀态一般由三部分組成:python正在執行的腳本的目錄,PYTHONPATH路徑,包的預設安裝路徑。

在支援符号連結的檔案系統上,包含輸入腳本的目錄是在符号連結之後計算的。換句話說,包含符号連結的目錄不會添加到子產品搜尋路徑中。

初始化後,Python 程式可以修改​

​sys.path​

​. 包含正在運作的腳本的目錄位于搜尋路徑的開頭,在标準庫路徑之前。這意味着将加載該目錄中的腳本而不是庫目錄中的同名子產品。最好不要有和内置子產品相同的名字的module, 因為目前檔案夾的module在被搜尋時會被優先搜尋。

“已編譯”的 Python 檔案

我們在運作python檔案後經常能看到被運作的檔案的目錄下增加了一個__pycache__檔案夾,裡面多了很多.pyc檔案。以前可能不太清楚這些.pyc檔案是什麼,重要不重要,能不能随便删除以及這些檔案是怎麼産生的等等疑問。現在看完這個章節就完全了解了__pycache__這個神秘的檔案夾。

為了加速子產品載入,Python會把每個子產品的編譯後版本存在在 pycache 目錄中,每個module的命名格式為 moduleName.cpython-version.pyc ,其中名稱中的version是python的版本号。例如,在CPython版本3.3中,spam.py的編譯版本将被緩存為 pycache/spam.cpython-33.pyc。因為帶上了版本号,是以不同版本的python的已編譯子產品可以共存。

Python根據編譯版本檢查源的修改日期,以檢視它是否已過期并判斷需要重新編譯。這是一個完全自動化的過程。

Python在兩種情況下不會檢查緩存。首先,對于從指令行直接載入的子產品,它從來都是重新編譯并且不存儲編譯結果;其次,如果沒有源子產品,它不會檢查緩存。為了支援無源檔案(僅編譯)發行版本, 編譯子產品必須是在源目錄下,并且絕對不能有源子產品。

  • 程式從​

    ​.pyc​

    ​ 檔案中讀取時的運作速度并不比從檔案中讀取時快​

    ​.py​

    ​;唯一比​

    ​.pyc​

    ​檔案更快的是它們的加載速度。

dir()函數

dir()函數會找到并列出一個module定義的所有函數、變量和類。

>>> import fibo, sys
 >>> dir(fibo)
['__name__', 'fib', 'fib2']
 >>> dir(sys)  ['__breakpointhook__', '__displayhook__', '__doc__', '__excepthook__',
 '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__',
 '__stderr__', '__stdin__', '__stdout__', '__unraisablehook__',
 '_clear_type_cache', '_current_frames', '_debugmallocstats', '_framework',
 '_getframe', '_git', '_home', '_xoptions', 'abiflags', 'addaudithook',
 'api_version', 'argv', 'audit', 'base_exec_prefix', 'base_prefix',
 'breakpointhook', 'builtin_module_names', 'byteorder', 'call_tracing',
 'callstats', 'copyright', 'displayhook', 'dont_write_bytecode', 'exc_info',
 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info',
 'float_repr_style', 'get_asyncgen_hooks', 'get_coroutine_origin_tracking_depth',
 'getallocatedblocks', 'getdefaultencoding', 'getdlopenflags',
 'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile',
 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval',
 'gettrace', 'hash_info', 'hexversion', 'implementation', 'int_info',
 'intern', 'is_finalizing', 'last_traceback', 'last_type', 'last_value',
 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks',
 'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 'pycache_prefix',
 'set_asyncgen_hooks', 'set_coroutine_origin_tracking_depth', 'setdlopenflags',
 'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr',
 'stdin', 'stdout', 'thread_info', 'unraisablehook', 'version', 'version_info',
 'warnoptions']
      

如果dir()函數的參數為空,會預設列出目前已經定義的所有變量、函數名和類。

>>> import fibo
 >>> fib = fibo.fib
 >>> dir()
['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys']
      

​dir()​

​預設不列出内置函數和變量的名稱。所有内置函數的名稱和變量都定義在标準子產品​

​builtins​

​中。

>>> import builtins
>>> dir(builtins)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '_', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
      

可以看到,很多我們過去使用過的函數其實都是内置函數,包括len, list, int, print,pow等等。

參考: ​​6.子產品​​