From 68c21c80d1f090a782fed6035220d61fcfd25596 Mon Sep 17 00:00:00 2001 From: asahi Date: Sat, 16 Aug 2025 22:09:44 +0800 Subject: [PATCH] =?UTF-8?q?doc:=20=E9=98=85=E8=AF=BBpython=20module?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- python/py.md | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) diff --git a/python/py.md b/python/py.md index 4977e2e..8a8ef0f 100644 --- a/python/py.md +++ b/python/py.md @@ -82,6 +82,13 @@ - [from ... import ...](#from--import--1) - [as](#as) - [execute module as script](#execute-module-as-script) + - [module search path](#module-search-path-1) + - [`sys.path`初始化](#syspath初始化) + - [standard module](#standard-module) + - [dir function](#dir-function) + - [packages](#packages) + - [import \* from package](#import--from-package) + - [包内部相互引用](#包内部相互引用) # Python @@ -1155,3 +1162,193 @@ if __name__ == "__main__": 并且,在module被导入时,`sys`并不会被导入。 +### module search path +当module名为`spam`的module被导入时,interpreter会按照如下顺序来进行查找: +1. 首先,interpreter会从built-in module中查找`spam` +2. 如果步骤1没有查询到,其会在`sys.path`变量定义的路径中查找名为`spam.py`的文件 + +#### `sys.path`初始化 +在python启动时,其会初始化module search path,初始化后的module search path可以通过`sys.path`来进行访问。 + +在`sys.path`中,组成如下: +- `sys.path`中第一条entry是包含input script的目录(如果存在input script) + - 若未指定input script,如`运行交互式shell`、`运行-c command`、`运行-m module`时,`sys.path`的第一条entry则是当前目录 +- `PYTHONPATH`环境变量中定义的路径也会被添加到search path中 +- 包含`standard python modules及其依赖的拓展modules`的路径也会别添加到module search path中 + - 拓展modules在windows平台中后缀名为`.pyd`,在其他平台中后缀名为`.so` + - 其中,`standard python modules`是平台无关的,被称为`prefix` + - `extension modules`则是平台相关的,被称为`exec_prefix` + + +> python支持通过`-c`来直接运行python命令,示例如下 +> ```shell +> python -c 'print(1+22*33)' +> ``` +> +> python还支持通过`-m`来直接运行module,示例如下 +> ```bash +> echo '{"name":"John","age":30}' | python -m json.tool +> ``` + +> 部分系统支持symlinks,故而包含input script的目录路径会在input script的symlink被follow之后才进行计算。故而,`包含symlink`的目录并不会被添加到sys.path中 + +在`sys.path`被初始化之后,python程序可以对`sys.path`进行修改。 + +在`sys.path`中,包含被运行文件的目录路径被放在了`sys.path`中最开始的位置,代表如果运行文件路径中如果存在和`standard library module`相同名称的文件,那么运行文件路径下的同名文件将会覆盖`standard library module`。 + +### standard module +python附带了一个包含standard modules的library。`standard modules`中部分modules是内置在interpreter中的,built modules中的内容可能并不是语言核心操作的一部分,但是能够提供对操作系统的访问,例如系统调用等。 + +built-in modules中的module在不同平台是可选的,例如`winreg` module只存在于windows平台。但是,`sys`module在所有平台的python interpreter中都包含。 + +### dir function +内置的`dir()`方法会查看在module中定义了哪些名称,其返回了一个sorted string list: +```bash +>>>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()`方法传递参数时,`dir()`方法会列出当前已经定义的名称: +```python +>>> a = [1, 2, 3, 4, 5] +>>> import fibo +>>> fib = fibo.fib +>>> dir() +['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys'] +``` +其列出的名称中包含所有类型:变量、module、function等 + +`dir`方法并不会列出内置的方法和变量,如果想要查看那些,可以使用`dir(builtins)` + +```bash +import builtins +dir(builtins) +``` +### packages +packge是一种结构化python modules命名空间的方法,其使用了`dotted module names`。例如,module name为`A.B`其代表的是位于package A下的submodule B。 + +就像module可以使module的开发者们不用担心使用了和其他module中一样的变量/函数名一样,dotted module name可以令module的开发者不用担心使用了和其他module相同的module name。 + +如果,你要定义一系列的modules统一处理不同格式的sound files和sound data,可以采用如下的package结构: +``` +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 + ... +``` + +当对package进行导入时,python会从`sys.path`中查询package的子目录。 + +其中,`__init__.py`文件用于`让python将该目录看作是package`。`__init__.py`文件可以是空文件,但是`也可以包含对package进行初始化的代码`或`设置__all__变量`。 + +在使用package中,可以单独导入package中的module: +```py +import sound.effects.echo +``` +上述示例中导入了`sound.effects.echo`module,在对module进行使用时,必须采用如下方式指定mdoule的fullname: +```py +sound.effects.echo.echofilter(input, output, delay=0.7, atten=4) +``` +另一种可选的导入方式如下: +```py +from sound.effects import echo +``` +在使用module时,只需要指定echo即可 +```py +echo.echofilter(input, output, delay=0.7, atten=4) +``` +同时,也可以直接导入module中的方法: +```py +from sound.effects.echo import echofilter + +echofilter(input, output, delay=0.7, atten=4) +``` + +在使用`import item.subitem.subsubitem`这类语法时,除了最后的item外,其余item必须都要是package,最后的item可以是package或module,但不能是module中的内容。 + +#### import * from package +在对package执行`import *`的语法时,其导入行为准许如下规范: +- 如果package的`__init__.py`文件中定义了`__all__`变量,其将认为`__all__`中定义了所有应该被`import *`所导入的module name + +故而,package的开发者应当负责在package版本迭代时将`__all__`进行更新;当然,开发者页可以决定不对`import *`进行支持,不定义`__all__`。 + +示例如下,`sound/effects/__init__.py`中可能包含如下内容: +```py +__all__ = ["echo", "surround", "reverse"] +``` +其代表`from sound.effect import *`将会导入`echo, surround, reverse`三个module。 + +注意,本地定义的名称可能会遮挡submodules。例如,如果在`sound/effects/__init__.py`中定义了一个reverse函数,那么`from sound.effects import *`将只会导入`echo, surround`两个module。 +```py +__all__ = [ + "echo", # refers to the 'echo.py' file + "surround", # refers to the 'surround.py' file + "reverse", # !!! refers to the 'reverse' function now !!! +] + +def reverse(msg: str): # <-- this name shadows the 'reverse.py' submodule + return msg[::-1] # in the case of a 'from sound.effects import *' +``` + +如果在`__init__.py`中没有定义`__all__`,那么`from sound.effects import *`只会导入`__init__.py`中的其他定义内容,示例如下: +```py +import sound.effects.echo +import sound.effects.surround +from sound.effects import * +``` + +### 包内部相互引用 +在同一个包中,不同subpackage中的module可以对彼此进行引用。引用支持绝对路径和相对路径,例如,`sound.filters.vocoder`在对`sound.effects`中定义的包进行import时,可以采用如下方式: +- 绝对路径:`from sound.effects import echo` +- 相对路径:`from ..effects import echo` + +在使用相对路径的导入时,示例如下: +当从`surround`执行相对路径导入时,可以执行如下形式的导入 +```py +from . import echo # 位于相同的subpackage中 +from .. import formats # 访问../formats +from ..filters import equalizer # 访问../filters中的equalizer +``` + +