Maison  >  Article  >  développement back-end  >  Module manuel Python

Module manuel Python

巴扎黑
巴扎黑original
2017-06-23 16:29:361429parcourir

[Traduction]Le Tutoriel Python#Modules

6. Modules

Si vous quittez et rentrez dans l'interpréteur Python, les noms (fonctions et variables) précédemment définis sont perdus. Par conséquent, si vous souhaitez écrire des programmes plus longs, il est préférable d'utiliser un éditeur de texte pour préparer l'entrée à l'interpréteur, en utilisant plutôt des fichiers comme entrée. Ceci est également connu sous le nom de création d'un script. Au fur et à mesure que votre programme s'allonge, vous pouvez le diviser en plusieurs fichiers pour faciliter la maintenance. Vous souhaiterez peut-être également utiliser une fonction utile dans plusieurs programmes sans copier sa définition dans chaque programme.

Pour répondre à ces besoins, Python fournit un moyen de mettre des définitions dans un fichier et de les utiliser dans un script ou une instance interactive de l'interpréteur. Un tel fichier est appelé un module ; les définitions d'un module peuvent être importées dans d'autres modules ou dans le module principal (un ensemble de variables accessibles dans les scripts et les modes de calcul de niveau supérieur) .

Un module est un fichier contenant des définitions et des instructions Python. Le nom du fichier est le nom du module et possède un suffixe .py. Au sein d'un module, le nom du module (sous forme de chaîne) est disponible comme valeur de la variable globale __name__. Par exemple, utilisez votre éditeur de texte préféré pour créer un fichier fibo.py dans le répertoire courant avec le contenu suivant :

# Fibonacci numbers moduledef fib(n):    # write Fibonacci series up to na, b = 0, 1while b < n:print(b, end=&#39; &#39;)
        a, b = b, a+bprint()def fib2(n):   # return Fibonacci series up to nresult = []
    a, b = 0, 1while b < n:
        result.append(b)
        a, b = b, a+breturn result

Entrez l'interpréteur Python et importez ce module en utilisant ce qui suit commande :

>>> import fibo

Cette opération n'importe pas le nom de la fonction définie dans fibo dans la table des symboles actuelle ; elle importe uniquement le nom du module fibo. Les fonctions sont accessibles à l'aide des noms de module :

>>> fibo.fib(1000)1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987>>> fibo.fib2(100)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]>>> fibo.__name__&#39;fibo&#39;

Si vous souhaitez utiliser une fonction fréquemment, vous pouvez lui attribuer un nom local :

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

6.1 En savoir plus sur les modules

Les modules peuvent contenir à la fois des instructions exécutables et des définitions de fonctions. Les instructions exécutables sont utilisées pour initialiser le module. Lorsque le nom du module apparaît dans une instruction d'importation, ces instructions exécutables ne sont exécutées qu'une seule fois [1]. (Si le fichier est un script, ces exécutables seront également exécutés)

Chaque module possède sa propre table de symboles privée, qui est utilisée comme table de symboles globale par toutes les fonctions définies dans le module. Par conséquent, les auteurs de modules peuvent utiliser ces variables globales sans se soucier des conflits de noms accidentels avec ceux utilisés pour les variables globales. D'un autre côté, si vous savez ce que vous faites, vous pouvez référencer les variables globales d'un module de la même manière que vous référencez des fonctions, modname.itemname.

Les modules peuvent référencer d'autres modules. C'est une bonne pratique de placer toutes les instructions import au début d'un module (ou d'un script), mais ce n'est pas obligatoire. Le nom du module importé sera placé dans la table des symboles globaux du module actuel.

Il existe une variante de l'instruction import qui importe directement le nom du module dans la table des symboles du module actuel. Par exemple :

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

Ce qui précède n'introduit pas le nom du module (dans l'exemple ci-dessus, fibo ne sera pas défini).

Il existe même un moyen d'importer tous les noms définis dans un module :

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

Cette méthode importe tous les noms qui ne commencent pas par un trait de soulignement _ . Dans la plupart des cas, les programmeurs Python n'utiliseront pas cette méthode, car elle importera un ensemble inconnu de noms dans l'interpréteur et bloquera peut-être certains noms déjà définis.

Il est à noter qu'en pratique, l'importation depuis un module ou un package est généralement déconseillée, car cela réduirait la lisibilité du programme. Cependant, il est possible de l'utiliser dans un environnement interactif pour réduire la frappe.

Remarque : Pour des raisons de performances, chaque module n'est importé qu'une seule fois par session d'interprétation. Ainsi, si le module est modifié, l'interpréteur doit être redémarré ; si vous souhaitez uniquement tester un module de manière interactive, utilisez importlib.reload(), par exemple : import importlib; importlin.reload(modulename)

6.1.1 Exécuter les modules comme scripts

Lors de l'exécution d'un module Python à l'aide de la commande suivante :

python fibo.py <arguments>

Le code du module sera exécuté comme si le module était importé, mais ensuite __name__ est réglé sur __main__. Cela signifie que le code suivant sera ajouté à la fin du module :

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

Le module est exécuté comme un script et peut également être importé en tant que module, car seulement lorsque le module est exécuté sous forme de fichier mian, Le code qui analyse la ligne de commande sera exécuté :

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

Si le module est importé, le code ne sera pas exécuté :

>>> import fibo>>>

这可以用来为使用者提供一个模块用户接口的使用约定,也可以用作测试(模块作为脚本时执行测试用例)

6.1.2 The Module Search Path

当模块spam被导入时,解释器首先搜索built-in模块。如果没有找到,解释器在变量sys.path提供的路径列表中搜索名为spam.py的文件。sys.path从下列位置初始化:

  • 包含输入脚本的目录(或者没有指定文件时的当前目录)

  • PYTHONPATH(目录名字集合,与shell环境变量PATH相似,也是环境变量)

  • 安装默认目录

注意: 在支持符号链接的文件系统,包含输入脚本的目录是符号链接指向的目录。也就是说包含符号链接的目录不会被加入到搜索路径中。

初始化后,Python程序可以修改sys.path。包含执行脚本的目录被放置到搜索路径的开始,在标准库路径之前。这意味着该目录中的脚本会被加载,而标准库目录中的同名模块不会被加载。这会引发错误,除非是有意替换标准库的模块。阅读Standard Modules获取更多信息。 (译注:自定义的模块不应与标准模块重名,否则标准模块会被覆盖。)

6.1.3 “Compiled” Python files

为加速模块加载,Python会在__pycache__目录中缓存每个模块的编译版本,缓存文件名为module.version.pycversion编码了被编译文件的版本;通常包含了Python的版本号。例如,在CPython release 3.3中,文件spam.py的编译版本会被缓存为__pycache__/spam.cpython-33.pyc。这种命名约定允许来自不同Python发行版本的模块得以共存。

Python检查源文件的修改日期与编译版本,来确定编译版本是否过期,是否需要重新编译。这是一个完全自动化的过程。另外,编译模块是平台独立的,因此异构系统可以共享相同的库。

Python不会检查在两个环境中的缓存。首先,Python总是重新编译,并且不会存储直接从命令行加载的模块的结果。其次,如果没有源模块,Python不检查缓存。若要支持无源文件(只有编译版本)分布,那么编译的模块必须放在源文件目录中,并且源模块必需不存在。

给专家的建议:

  • 可以在命令行使用-O或者-OO开关来减少编译模块的大小。-O参数移除assert语句,-OO参数同时移除assert语句和__doc__字符串。由于一些程序依赖这些变量,那么只有当你确认你要这么做时,才能使用这两个参数。“优化的”模块有一个opt-标签并且通常更小。未来的发型版本可能改变优化的影响。

  • .pyc文件中读取的程序不会比从.py文件读取的程序跑得快;.pyc文件快的地方在于加载。

  • compileall模块可以为目录中的所有模块创建.pyc文件。

  • PEP 3147中有关系这点的更多信息,包括一个决策流程

6.2 Standard Modules

Python提供了标准模块库,在独立文档中描述,名为Python Library Reference(以后叫做Library Reference)。有一些模块内嵌入解释器中,这些模块不是语言核心的一部分,但是它们是内嵌的,这既是为性能考虑,也提供了访问如系统调用般的操作系统原生接口的方式。这些模块集合依赖底层平台的配置选项。例如winreg模块只在Windows系统中提供。一个特殊的模块值得注意:sys,这个模块内嵌在所有Python解释器中。变量sys.ps1sys.ps2定义了主提示符和辅助提示符的字符串:

>>> import sys>>> sys.ps1&#39;>>> &#39;>>> sys.ps2&#39;... &#39;>>> sys.ps1 = &#39;C> &#39;C> print(&#39;Yuck!&#39;)
Yuck!C>

只有当解释器以交互模式运行才会定义这两个变量。

变量sys.path是决定解释器模块搜索路径的字符列表。该变量从环境变量PYTHONPATH,或者内置默认路径(PYTHONPATH未指定时)初始化。可以使用标准list操作修改它的值:

>>> import sys>>> sys.path.append(&#39;/ufs/guido/lib/python&#39;)

6.3 The dir() Function

内嵌函数dir()用于搜索模块定义的名字。返回一个有序字符串列表:

>>> import fibo, sys>>> dir(fibo)
['__name__', 'fib', 'fib2']>>> dir(sys)  
['__displayhook__', '__doc__', '__excepthook__', '__loader__', '__name__', '__package__', '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache', '_current_frames', '_debugmallocstats', '_getframe', '_home', '_mercurial', '_xoptions', 'abiflags', 'api_version', 'argv', 'base_exec_prefix', 'base_prefix', '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', 'getcheckinterval', 'getdefaultencoding', 'getdlopenflags', 'getfilesystemencoding', 'getobjects', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettotalrefcount', 'gettrace', 'hash_info', 'hexversion', 'implementation', 'int_info', 'intern', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'ps1', 'setcheckinterval', 'setdlopenflags', 'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr', 'stdin', 'stdout', 'thread_info', 'version', 'version_info', 'warnoptions']

不带参数使用dir()函数,会列出当前作用域的全部名字:

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

需要注意该函数列出所有类型的名字:变量,模块,函数,等等。

dir()不会列出内嵌函数和变量的名字。如果希望列出,这些名字定义在标准模块builtins中:

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

6.4 Packages

包是使用“圆点模块名”结构化Python模块名字空间的方式。例如,模块名A.B表示包A中的子模块B。就像模块使得不同模块的作者免于担忧每个模块的全局名字一样,圆点模块名的使用使得多模块包(如NumPy或者Python图像库)的作者免于担忧每个模块的名字。

假设需要为统一音频文件和音频数据的处理设计一个模块的集合(包)。有许多不同的音频文件格式(通常通过扩展名辨认,如.wav, .aiff, .au),因此需要为不同文件格式的转换创建和维护一个持续增长的模块集合。也存在许多对音频数据不同的操作(例如混合,增加回声,增加均衡器函数,创建人造立体效果),因此需要额外编写执行这些操作的大量模块。以下是包的可能结构(以层级文件结构来表示):

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
              ...

导入包时,Python搜索sys.path提供的路径寻找包子目录。

为使Python将普通目录看做包,目录中必须包含__init__.py文件。这样做是为了避免普通的目录名(如string)将以后会出现在模块搜索路径中的有效模块无意识的隐藏掉。最简单的情况是,__init__.py可以是一个空文件,但是它也可以包含可执行的初始化包的代码或者设置__all__变量,后面讲述。

包的用户可以从包中导入独立的模块:

import sound.effects.echo

这将加在子模块sound.effects.echo。必须使用全名引用:

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

导入子模块可选方式:

from sound.effects import echo

以上也加载子模块echo,不使用包前缀引用模块,因此可以像下面一样使用:

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

另外的方式是直接导入需要的函数或者变量:

from sound.effects.echo import echofilter

同样的,这将加在子模块echo,但使函数echofilter()直接可用:

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

注意当使用from package import item时,item可以使子模块(子包),也可以是包内定义的其他名字,如函数,类或者变量。import语句首先测试要导入的项是否在包中存在;如果不存在,Python假设这个项是模块并尝试加载它。如果最后寻找失败,ImportError异常抛出。

相对的,使用import item.subitem.subsubitem时,除了最后一项,每一项都必须是包;最后一项可以是模块或者包但是不能是前面的项中定义的类,函数或者变量。

6.4.1 Importing * From a Package

使用from sound.effects import *会发生什么?理想情况下,总是期望在文件系统中找出所有子模块,并全部导入。全部导入会耗费很长时间,并且导入子模块可能会有不期待的副作用,这些副作用应该在显式导入时发生。

唯一的解决方案是包作者提供一个包的显式索引。import语句遵循以下约定:如果包的__init__.py代码中定义了名为__all__的变量,那么使用from package import *时会导入该变量指定的所有模块。当包的新版本发布时,由包作者负责更新列表__all__。如果包作者不希望可以使用from package import *导入包中的模块,也可以不支持__all__。 例如,文件sound/effects/__init__.py可能包含以下代码:

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

这意味着from sound.effects import *会导入sound包中指定的三个模块。

如果__all__没有定义,语句from sound.effects import *不会将包sound.effects中的子模块全部倒入到当前名字空间中,只保证包sound.effects被导入了(可能会运行__init__.py中的初始化代码)并且导入任意在包中定义的名字。包括在__init__.py中定义的任意名字(以及显式加载的子模块)。也会包括前面的import语句显式加载的任意包子模块。考虑如下代码:

import sound.effects.echoimport sound.effects.surroundfrom sound.effects import *

这个例子中,echosurround模块被导入到当前名字空间中,因为执行from... import时,它们已经定义在sound.effects包中定义了。(定义了__all__时同样有效)

尽管使用import *时只有符合特定模式的名字会被导出,但仍然不建议在生产代码中使用。

记住,使用form Package import specific_submodle没有错误。实际上,这是推荐的方法,除非当前模块需要使用其他包中的同名模块。

6.4.2 Intra-package References

当包中包含了子包结构(就如例子中的sound包),可以使用绝对导入的方式引用兄弟包中的子模块。例如,如果模块sound.filters.vocoder需要使用包sound.effects中的echo模块,可以使用from sound.effects import echo

也可以使用from modul import name语句来相对导入模块。这种方式使用点.指示当前包和相对导入中涉及的父包。以surround模块为例:

from . import echofrom .. import formatsfrom ..filters import equalizer

相对导入基于当前模块的名字。由于主模块的名字总是__main__,要当做Python应用主模块使用的模块必须总是使用绝对导入的方式。

6.4.3 Packages in Multiple Directories

包还支持一个特殊属性,__path__。在__init__.py中的代码执行之前,属性__path__被初始化为一个列表,这个列表包含了持有该__init__.py文件的目录的路径。该变量可修改,这样做会影响将来的对包内模块和子包的搜索。

然而这个特性不总是需要的,它可以用来扩展包的模块集合

Footnotes

[1] 实际上,函数定义也是可“执行”的“语句”;模块级别的函数执行将函数的名字放置到模块的全局符号表中

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Article précédent:vue de classeArticle suivant:vue de classe