From e2fe983467d3aab42b48a695947586537233a10f Mon Sep 17 00:00:00 2001 From: asahi Date: Mon, 18 Aug 2025 02:34:42 +0800 Subject: [PATCH] =?UTF-8?q?doc:=20=E9=98=85=E8=AF=BBpython=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- python/py.md | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/python/py.md b/python/py.md index a99d183..36bd6af 100644 --- a/python/py.md +++ b/python/py.md @@ -94,6 +94,15 @@ - [packages](#packages) - [import \* from package](#import--from-package) - [包内部相互引用](#包内部相互引用) + - [class](#class) + - [python scope and namespaces](#python-scope-and-namespaces) + - [namespace](#namespace) + - [lifetime](#lifetime) + - [LGEB](#lgeb) + - [scope](#scope) + - [global](#global) + - [nonlocal](#nonlocal) + - [global namespace](#global-namespace) # Python @@ -1055,6 +1064,8 @@ except* OSError as e: except* SystemError as e: print("There were SystemErrors") ``` +当使用`except*`语法时,即使指定了`except* OSError as e`,`e`的类型仍然是`ExceptionGroup`而不是`OSError`,因为try中抛出的`ConditionGroup`中可能含有多个`OSError`类型的异常,故而,实际的`OSError`异常对象需要通过`e.exceptions`来进行访问。 + ### enriching exceptions with notes 当创建异常时,可以通过`add_note(note)`方法来为异常补充信息,标准的traceback会按照其被添加的顺序渲染所有的note信息,note信息在异常信息之后 ```py @@ -1570,4 +1581,113 @@ from .. import formats # 访问../formats from ..filters import equalizer # 访问../filters中的equalizer ``` +## class +python在对对象进行传递时,只支持引用传递(传递指向对象的指针),而不支持类似c++的值传递(对象拷贝)。故而,在python中,如果对方法的入参对象进行了修改,那么该修改对调用方可见。 +### python scope and namespaces +#### namespace +namespace代表name到object的映射。 + +常见的namespace有: +- 包含built-in names的namespace(built-in names包含类似`abs`之类的built-in函数,以及built-in exception names等) +- 包含module global names的module namespace +- 在函数调用时包含`local names`的local namespace + +从某种意义上说,对象中的attributes也构成了一个namespace。 + +对于`module.name`的访问,其实际也是针对`module object`中`attribute`的访问:module中的global name和module attribute都是位于同一namespace中。 + +`attribute`分为`read-only`和`writable`的。对于`writable`的attribute,可以对其进行赋值,示例如下: +```py +modname.the_answer = 42 +``` +同样的,`writable`的attribute也可以通过`del`来进行删除,删除后该attribute将会从对象中被移除 +```py +del modname.the_answer +``` + +##### lifetime +在不同时机创建的namespace拥有不同的生命周期: +- `built-in namespace`: 在python interpreter启动时被创建,并且该namespace永远不会被删除 +- `module namespace`: 当module的定义被读入时,会创建module namespace,并且module namespace会持续到interpreter退出时 +- 对于被interpreter执行的top-level statements(通过交互式输入或从script中读取),其被视作`__main__`module的一部分,其拥有属于自己的namespace +- `local namespace of function`:在函数被调用时创建,在函数执行完成/抛出未处理异常时namespace被删除(对于递归调用,每次调用都拥有其自己的namespace) + +##### LGEB +在python中,LEGB规则决定了命名空间搜索的顺序: +- `local`: 定义在函数/类内部 +- `enclosed`:定义在闭包函数内 +- `global`:定义在全局/最上层 +- `built-in`:python中内置的保留名称 + + + + + +##### scope +scope代表python程序中的一个文本范围,在该范围内可以对某个namespace中的name进行直接访问,而无需前缀`x.y.`之类的限定名。 + +在程序执行的某个时间点,都会存在3/4个nested scopes可以直接访问: +- 最内层的scope,包含local names,最先查找 +- scope of enclosing function,查找时会从nearest neclosing scope开始,包含`non-local and non-global names` +- `next-to-last scope`,包含global names +- 最外层scope,最后查找,包含built-in names + +##### global +如果使用`global var_name`的方式来声明变量,那么针对该变量的引用和复制都会直接指向global namespace中的变量。 + +##### nonlocal +如果想要在local namespace中访问enclosing namespace中的name,可以通过`nonlocal var_name`形式来声明变量,示例如下: +```py +def main(): + s = "fuck" + def s_change(p): + nonlocal s + s=p + s_change("shit") + print(s) +``` + +如果没有通过`nonlocal`进行声明,那么对于s的赋值将会看作是`在innermost scope中创建了一个同名变量并进行赋值`,外部的变量值并不会改变。 + +通常来说,在函数定义内,scope为innermost scope,而在函数外则是global namespace,`类定义会新开一个namespace`。 + +##### global namespace +对于module中定义的function,其global namespace即是module namespace,无论函数在哪里被调用。 + + +在python中,如果没有使用`global`或`nonlocal`,那么变量是只读的,对name的赋值永远会在innermost scope中。`del`语句则是从local scope对应的namespace中移除变量的绑定。 + +> 当在innermost scope中,如果只对外层变量进行读操作,那么无需使用`global`或是`nonlocal`;但是,如果想要修改外层变量,则需要使用`global`或者`nonlocal`,否则外层变量是只读的。 + +```py +def scope_test(): + def do_local(): + spam = "local spam" + + def do_nonlocal(): + nonlocal spam + spam = "nonlocal spam" + + def do_global(): + global spam + spam = "global spam" + + spam = "test spam" + do_local() + print("After local assignment:", spam) + do_nonlocal() + print("After nonlocal assignment:", spam) + do_global() + print("After global assignment:", spam) + +scope_test() +print("In global scope:", spam) +``` +在上述示例中,返回结果如下: +``` +After local assignment: test spam +After nonlocal assignment: nonlocal spam +After global assignment: nonlocal spam +In global scope: global spam +```