天天看點

Python基礎之:Python中的子產品簡介子產品基礎執行子產品子產品搜尋路徑dir包

簡介

Python的解釋環境是很好用,但是如果我們需要編寫一個大型的程式的時候,解釋環境就完全不夠用了。這個時候我們需要将python程式儲存在一個檔案裡。通常這個檔案是以.py結尾的。

對于大型的應用程式來說,一個檔案可能是不夠的,這個時候我們需要在檔案中引用其他的檔案,這樣檔案就叫做子產品。

子產品是一個包含Python定義和語句的檔案。檔案名就是子產品名後跟檔案字尾

.py

。在子產品内部,子產品名可以通過全局變量

__name__

獲得。

子產品基礎

還是之前的斐波拉赫數列的例子,我們在fibo.py檔案中存放了函數的實作:

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()      

編寫完畢之後,我們可以在Python的解釋環境中導入它:

>>> import fibo      

然後直接使用即可:

>>> fibo.fib(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987      

常用的函數,我們可以将其指派給一個變量:

>>> fib = fibo.fib
>>> fib(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987      

或者,我們在導入的時候,直接給這個子產品起個名字:

>>> import fibo as fib
>>> fib.fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377      

或者導入子產品中的函數:

>>> from fibo import fib as fibonacci
>>> fibonacci(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377      

每個子產品都有它自己的私有符号表,該表用作子產品中定義的所有函數的全局符号表。是以,子產品的作者可以在子產品内使用全局變量,而不必擔心與使用者的全局變量發生意外沖突。

執行子產品

前面我們提到了可以使用import來導入一個子產品,并且

__name__

中儲存的是子產品的名字。

和java中的main方法一樣,如果我們想要在子產品中進行一些測試工作,有沒有類似java中main方法的寫法呢?

先看一個例子:

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

在子產品中,我們需要進行一個判斷

__name__

是不是被指派為

"__main__"

我們這樣來執行這個子產品:

python fibo.py <arguments>      

以腳本執行的情況下,子產品的

__name__

屬性會被指派為

__main__

, 這也是例子中為什麼要這樣寫的原因。

看下執行效果:

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

如果是以子產品導入的話,那麼将不會被執行:

>>> import fibo
>>>      

子產品搜尋路徑

使用import導入子產品的時候,解釋器首先會去找該名字的内置子產品,如果沒找到的話,解釋器會從

sys.path

變量給出的目錄清單裡尋找。

sys.path

的初始目錄包括:

  • 目前目錄
  • PYTHONPATH 指定的目錄
  • 安裝的預設值

dir

要想檢視子產品中定義的内容,可以使用dir函數。

>>> a = [1, 2, 3, 4, 5]
>>> import fibo
>>> fib = fibo.fib
>>> dir()
['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys']      

上面的例子列出了目前子產品中定義的内容,包括變量,子產品,函數等。

注意,

dir()

不會列出内置函數和變量的名稱。如果你想要這些,它們的定義是在标準子產品

builtins

中。

我們可以給dir加上參數,來擷取特定子產品的内容:

>>> 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', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented',
 'NotImplementedError', 'OSError', 'OverflowError',
 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError',
 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning',
 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError',
 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError',
 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError',
 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning',
 'ValueError', 'Warning', 'ZeroDivisionError', '_', '__build_class__',
 '__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs',
 'all', 'any', 'ascii', 'bin', 'bool', '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']      

java中有package的概念,用來隔離程式代碼。同樣的在Python中也有包。

我們看一個Python中包的例子:

sound/                          Top-level package
      __init__.py               Initialize the sound package
      formats/                  Subpackage for file format conversions
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  Subpackage for sound effects
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  Subpackage for filters
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...      

上面我們定義了4個包,分别是sound,sound.formats, sound.effects, sound.filters。

注意,如果是包的話,裡面一定要包含

__init__.py

檔案。

__init__.py

可以是一個空檔案,也可以執行包的初始化代碼或設定

__all__

變量。

當導入的時候, python就會在

sys.path

路徑中搜尋該包。

包的導入有很多種方式,我們可以導入單個子產品:

import sound.effects.echo      

但是這樣導入之後,使用的時候必須加載全名:

sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)      

如果不想加載全名,可以這樣導入:

from sound.effects import echo      

那麼就可以這樣使用了:

echo.echofilter(input, output, delay=0.7, atten=4)      

還可以直接導入子產品中的方法:

from sound.effects.echo import echofilter      

然後這樣使用:

echofilter(input, output, delay=0.7, atten=4)      

如果一個包裡面的子包比較多,我們可能會希望使用 * 來一次性導入:

from sound.effects import *      

那麼如何去控制到底會導入effects的哪一個子包呢?

我們可以在

__init__.py

中定義一個名叫

__all__

的清單,在這個清單中列出将要導出的子包名,如下所示:

__all__ = ["echo", "surround", "reverse"]      

這樣

from sound.effects import *

将導入

sound

包的三個命名子子產品。

如果沒有定義

__all__

from sound.effects import *

語句 不會 從包

sound.effects

中導入所有子子產品到目前命名空間;它隻會導入包

sound.effects

包的相對路徑

Import 可以指定相對路徑,我們使用 . 來表示目前包, 使用 .. 來表示父包。

如下所示:

from . import echo
from .. import formats
from ..filters import equalizer      
本文已收錄于 http://www.flydean.com/07-python-module/

最通俗的解讀,最深刻的幹貨,最簡潔的教程,衆多你不知道的小技巧等你來發現!

歡迎關注我的公衆号:「程式那些事」,懂技術,更懂你!