通读了Python官网的语法说明文档。原文来自:Python 语言参考(3.8.2版本)。在此,将原文的要点进行记录与分享。
1 概述
2 词法分析
Python 程序由一个解析器读取。输入到解析器的是一个由词法分析器所生成的形符流。Python 会将读取的程序文本转为 Unicode 码点;源文件的文本编码可由编码声明指定,默认为 UTF-8。
2.1 行结构
- 逻辑行以
NEWLINE
形符表示。- 语句不能跨逻辑行。
- 逻辑行可由多个物理行按规则拼接
- 物理行以换行字符终止,如LF,CR LF,CR等
2.2 其它形符
2.3 标识符和关键字
Python关键字
False await else import pass
None break except in raise
True class finally is return
and continue for lambda try
as def from nonlocal while
assert del global not with
async elif if or yield
特殊的标识符
-
_*
:以下划线字符_
开始的标识符不会被import语句from module import *
导入。 -
__*__
:以双下划线字符开始并结尾的标识符为系统定义的名称,特殊方法对于的名称 -
__*
:以双下划线开始的标识符是类的私有名称,会被类定义隐式的转换。
2.4 字面值
字面值直接表示一些内置类型的常量
- 字符串、字节串字面值
- 格式化字符串字面值
- 数字字面值:整数、浮点数、虚数
格式化字符串字面值
以'f'
或'F'
前缀开始的字符串为格式化字符串。其中以花括号{}
标识的是可替换字段。
f_string ::= (literal_char | "{{" | "}}" | replacement_field)*
replacement_field ::= "{" f_expression ["!" conversion] [":" format_spec] "}"
f_expression ::= (conditional_expression | "*" or_expr)
("," conditional_expression | "," "*" or_expr)* [","]
| yield_expression
conversion ::= "s" | "r" | "a"
format_spec ::= (literal_char | NULL | replacement_field)*
literal_char ::=
注:
-
! conversion
转换符,表达式f_expression
将先转换在格式化:-
!s
:以str()
转换 -
!r
:以repr()
转换 -
!a
:以ascii()
转换
-
2.5 运算符
2.6 分隔符
3 数据模型
3.1 对象、值与类型
每个对象有各自的编号、类型和值。编号:id()
函数返回代表编号的整数值,在CPython中即为内存地址,编号是不可变的。类型:type()
返回对象的类型,类型也是不可变的。值:有些对象的值是是否可变分为可变的(mutable)与不可变的(immutable)。对象的可变性是由类型决定的。
注:当不可变容器包含可变对象的引用时,后者的数值改变也造成容器数值的改变。不过,容器包含的内容未变,所以依然称该容器是不可变的。也就是说,不可变并非是值不改变。
对象绝不会显示被销毁,当无法访问时被垃圾回收。一些对象包含对外部资源的引用,当对象被垃圾回收时这些资源得到释放。未明确的释放外部资源,这些对象通常有close()
方法,在程序中以try...finally
语句和with
语句提供的操作更便捷。
3.2 标准类型层级
None
NotImplemented
逻辑值为真Ellipsis
逻辑值为真-
numbers.Number
- numbers.Integeral
- 整形(int)
- 布尔型(bool)
- numbers.Real(float)
- numbers.Complex(complex)
- numbers.Integeral
-
序列: 有限有序集,支持
len()
,切片a[i:j]
,扩展切片a[i:j:k]
- 不可变序列:
- 字符串
str
- 元组
- 字节串
bytes
- 字符串
- 可变序列:
- 列表
- 字节数值
bytearray
- 扩展模块
array
与collections
- 不可变序列:
-
集合类型:无序有限集,支持迭代,支持
len()
- 集合
set()
- 冻结集合
frozenset()
- 集合
-
映射:任意索引类型的有限集合,支持下标
a[k]
用于赋值或del
语句,支持len()
- 字典
-
可调用类型
-
用户定义函数,特殊属性:
-
__doc__
可写 -
__name__
可写 -
__qualname__
可写,函数限定名称,显式从模块开始的层级 -
__module__
可写,函数所述模块的名称 -
__defaults__
可写,默认参数值构成的元组 -
__code__
可写,变异后的函数体代码 -
__globals__
只读,函数所属模块的全局命名空间字典引用 -
__dict__
可写,命名空间支持的函数属性 -
__closure__
只读 -
__annotations__
可写,包含参数标注的自定 -
__kwdefaults__
可写,仅包含关键字参数默认值的字典
-
-
实例方法,结合类、类实例与可调对象。
- 特殊只读属性:
__self__
为类实例,__func__
为函数对象,__doc__
为方法文档(即__func__.__doc__
)__name__
即__func__.__name__
,__module__
方法所在模块名称。 - 注:实例方法的
__self__
参数指代实例对象; 类方法的__self__
参数指代类型。 - 注:从函数对象到实例方法的转换在每一次实例获取方法时发生,一种优化方法时将实例方法属性在本地保存,每次使用时调用本地对象。
- 特殊只读属性:
生成器函数:使用
yield
语句的函数/方法。函数被调用时返回迭代器对象。协程函数: 使用
async def
定义的函数/方法。异步生成器函数:使用
async def
定义的含有yeild
语句的函数/方法。-
内置函数:对于C函数的外部封装。
- 特殊只读属性:
__doc__
,__name__
,__self__
为None
,__module__
,
- 特殊只读属性:
内置方法:相比内置函数,多了一个传入C函数的对象作为隐式的额外参数
__self__
。类:
__new__()
,__init__()
类实例:定义
__call__()
使类实例可调
-
-
模块
- 具有字典对象实现的命名空间,也是模块中函数
__globals__
所引用的字典 - 可写属性:
__name__
,__doc__
,__annotations__
,__file__
- 只读属性
__dict__
- 具有字典对象实现的命名空间,也是模块中函数
-
自定义类
- 每个类都通过字典实现独立的命名空间,类属性在字典中查找
- 特别属性:
__name__
,__module__
类所在模块,__dict__
,__bases__
包含基类的元组,__doc__
,__annotations__
-
类实例
- 通过调用类对象创建,每个类实例通过字典实现独立的命名空间。
- 若为找到类属性,而对象对应的类具有
__getattr__()
方法则会调用该方法。 - 属性赋值与删除会更新实例字典,但不更新类字典。若类具有
__setattr__()
与__delattr()__
则调用方法而不直接更新实例字典 - 特殊属性:
__dict__
,__class__
I/0对象
-
内部类型(定义可能在未来解释器版本中变化)
- 代码对象
- 编译为字节的可执行Python代码,或称
bytecode
- vs函数对象,函数对象具有全局对象的引用,代码对象不包含上下文
- 编译为字节的可执行Python代码,或称
- 帧对象:表示执行帧
- 回溯对象:表示异常的栈跟踪记录。
- 切片对象:表示
__getitem__()
方法得到的切片, - 静态方法对象:
- 为对任意其它对象的封装,静态方法对象自身是不可调用的。
- 从类或类实例中获得的静态方法对象时,获得的是被封装的对象。
- 可由
staticmethod()
构造器创建
- 类方法对象:
- 对其他对象的封装。
- 可由
classmethod()
构造器创建。
- 代码对象
3.3 特殊方法
3.3.1 基本定制Basic customization
-
object.__new__(cls[,...])
- 创建cls类的新实例,
__new__()
总是一个静态方法。返回值应为新对象(通常为cls)实例 - 典型的实现总有
super().__new__(cls[, ...])
调用。 - 如果
__new__()
发返回了一个cls的实例或者子类,则新实例将调用__init__(self[, ...])
进行初始化 - 若
__new__()
没有返回cls的实例,则不会有__init__()
调用 - 用以对int,str或tuple等子类的自定义;用以创建唯一对象singleton
- 创建cls类的新实例,
-
object.__init__(self[, ...])
- 其参数与传递给构造表达器的参数相同。
- 应确保基类正确初始化
super().__init__([args...])
- 返回值为
None
-
object.__del__(self)
- 在实例被销毁时调用
- 派生类需确保基类的
__del__()
正确被调用 - 注:
del x
将x
的引用计数减一;当引用计数为零时,才可能执行x.__del__()
-
object.__repr__(self)
:- 若可能,使用输出的字符串能重建相同取值的对象;若不可能则返回形如
<...一些有用信息...>
的字符串
- 若可能,使用输出的字符串能重建相同取值的对象;若不可能则返回形如
-
object.__str__(self)
:一种非正式或格式良好的字符串 -
object.__bytes__(self)
:返回bytes
对象 -
object.__format__(self, format_spec)
:对象的格式化字符串显示 - 比较方法
object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other)
- 注:当比较操作的左操作数未实现相关函数,而右操作数有实现,则调用右操作数的方法;当右操作数是左操作数的子类时,优先有操作数的方法
-
object.__hash__(self)
- 用于对哈希集
set
,frozenset
,dict
执行哈希函数hash()
。建议将参与比较的对象组件打包为元组整体进行hash计算 - 与
__eq__()
- 用户定义类默认有
__eq__()
与__hash__()
方法,确保当x==y
时意味着x is y
且hash(x)==hash(y)
- 若仅定义
__eq__()
时,则将__hash__()
隐式设置为None
;若须保留父类的__hash__()
实现,须在类中明确__hash__ =
.__hash__ - 若未定义
__eq__()
则不应定义__hash__()
;若定义__eq__()
同时定义了可变对象也不应定义__hash__()
,否则对象可能至于错误的哈希桶中。 - 若未定义
__eq__()
时也不需要默认的__hash__()
,则应在类中明确__hash__ = None
- 用户定义类默认有
- 注: 在str与bytes对象的hash值由随机数加盐,在单独的python进程中是一致的。
- 用于对哈希集
-
object.__bool__(self)
- 若类未定义
__bool__()
也未定义__len__()
则实例逻辑值为真
- 若类未定义
3.3.2 属性访问
-
object.__getattr__(self, name)
- 当默认属性访问失败时调用:
- 可能由于
__getattribute__()
时 ,name
非实例属性 - 或者对于
name
特性调用__get__()
时
- 可能由于
- 当默认属性访问失败时调用:
-
object.__getattribute__(self, name)
- 类实例属性访问调用。为避免方法的无限递归,总是调用相同名称的基类方法实现
-
object.__setattr__(self, name, value)
- 当实例属性被赋值时调用。正常实现是调用相同名称的基类方法
-
object.__delattr__(self, name)
- 与
__setattr__()
效果范围类似,仅在del obj.name
时生效
- 与
-
object.__dir__(self)
- 对象调用
dir()
时调用,返回值为一个序列,
- 对象调用
3.3.2.1 自定义模块属性访问
特殊名称__getattr_
与__dir__
可用来自定义对模块属性的访问
自定义模块的行为,可以将模块对象的__class__
属性设置为types.ModuleType
的子类:
sys.modules[__name__].__class__ = ***Module
3.3.2.2 实现描述器
当含有如下__get__
,__set__
,__delete__
,__set_name__
特殊方法的类(称为描述器descriptor)的实例是其他所有类的成员时,这些特殊方法才有效
-
object.__get__(self,instance,owner=None)
- 实现所有者类属性/类实例属性的方法
-
object.__set__(self,instance,value)
- 设置instance指向的属性值为新值
- 使用
__set__()
或__delete__()
将描述器变为数据描述器
object.__delete__(self,instance)
-
object.__set_name__(self,owner,name)
- 在所有者创建是被调用,描述器赋值给name
3.3.2.3 调用描述器
描述器就是具有绑定行为的对象属性,属性方位被描述器的方法重载。
若没有定义__get__()
,属性访问将返回描述器自身
若定义了__set__()
/__delele__()
则为数据描述器,否则为非数据描述器;通常数据描述器定义__get__()
与__set__()
而非数据描述器仅定义__get__()
方法。数据描述器总是重载字典中实例定义。而非数据描述器可以被实例重载。
Python方法(包括staticmethod()
和 classmethod()
) 都是作为非描述器来实现的。因此实例可以重定义并重载方法。这允许单个实例获得与相同类的其他实例不一样的行为。
property()
函数是作为数据描述器来实现的。因此实例不能重载特性属性的行为。
3.3.2.4 __slots__
-
object.__slots__
- slots用以显示声明数据成员,禁止创建
__dict__
以及__weakref__
除非显示声明或在父类中可用. - 继承一个未定义slots的类时,实例的
__dict__
与__weakref__
总是可访问的。
- slots用以显示声明数据成员,禁止创建
3.3.3 类创建
classmethod object.__init_subclass__(cls)
- 当一个类继承自其它类时,基类的init_subclass会被调用。
- 基类控制子类的特性,相较于元类更加灵活
- 隐式的
classmethod
元类
默认情况,类是由type()
构建type(name,bases,dict)
。在类创建定义中传入metaclass
关键字参数,控制类创建使用的元类。
- 解析MRO条目
- 确定适当的元类
- 若没有基类且没有显示指定元类,使用
type()
- 若给出显示的元类且不是
type()
的实例,则直接用作元类 - 若给出一个
type()
实例作为元类,或者定义了基类,则使用最近派生的元类
- 若没有基类且没有显示指定元类,使用
- 准备类命名空间
- 若元类有
__prepare__
属性,则以namespace = metaclass.__prepare__(name,bases,**kwds)
调用,namespace
传递给元类的__new__
- 元类的
__prepare__
须显式声明为classmethod -
__prepare__
返回的命名空间返回给__new__
,但最终类对象创建时,命名空间拷贝至新的只读代理dict中,作为类对象的字典。
- 若元类有
- 执行类主体
- 创建类对象
- 执行元类
__new__
与__init__
- 执行元类
3.3.4 实例与子类检查
用以重载isinstance()
与issubclass()
内置函数行为,这样可以通过元类实现抽象基类ABC功能:
-class.__instancecheck__(self, instance)
class.__subclasscheck__(self, instance)
3.3.5 模拟泛型类型
classmethod object.__class_getitem_(cls, key)
。按照key参数指定的类型返回一个表示泛型类的专门化对象
3.3.6 模拟可调多项
object.__call__(self[, args...])
3.3.7 模拟容器类型
可以定义下列方法来实现容器对象。 容器通常属于序列(如列表或元组)或映射(如字典),但也存在其他形式的容器。 前几个方法集被用于模拟序列或是模拟映射;两者的不同之处在于序列允许的键应为整数 k 且 0 <= k < N 其中 N 是序列或定义指定区间的项的切片对象的长度。 此外还建议让映射提供 keys(), values(), items(), get(), clear(), setdefault(), pop(), popitem(), copy() 以及 update() 等方法,它们的行为应与 Python 标准字典对象的相应方法类似。 此外 collections.abc 模块提供了一个 MutableMapping 抽象基类以便根据由 getitem(), setitem(), delitem(), 和 keys() 组成的基本集来创建所需的方法。 可变序列还应像 Python 标准列表对象那样提供 append(), count(), index(), extend(), insert(), pop(), remove(), reverse() 和 sort() 等方法。 最后,序列类型还应通过定义下文描述的 add(), radd(), iadd(), mul(), rmul() 和 imul() 等方法来实现加法(指拼接)和乘法(指重复);它们不应定义其他数值运算符。 此外还建议映射和序列都实现 contains() 方法以允许高效地使用 in 运算符;对于映射,in 应该搜索映射的键;对于序列,则应搜索其中的值。 另外还建议映射和序列都实现 iter() 方法以允许高效地迭代容器中的条目;对于映射,iter() 应当迭代对象的键;对于序列,则应当迭代其中的值
object.__len__(self)
-
object.__length_hint__(self)
(可选) object.__getitem__(self,key)
object.__setitem__(self,key,value)
object.__delitem__(self,key)
-
object.__missing__(self,key)
(在getitem找不到键时调用) object.__iter__(self)
object.__reversed__(self)
object.__contains__(self,item)
3.3.8 模拟数字类型
运算 | 基本 | 反射 | 扩展 | |
---|---|---|---|---|
+ |
__add__ |
__radd__ |
__iadd__ |
|
- |
__sub__ |
|||
* |
__mul__ |
|||
@ |
__matmul__ |
|||
/ |
__truediv__ |
|||
// |
__floordiv__ |
|||
% |
__mod__ |
|||
divmod() |
__divmod__ |
None | ||
pow() /** |
__pow__ |
|||
<< |
__lshift__ |
|||
>> |
__rshift__ |
|||
& |
__and__ |
|||
^ |
__xor__ |
|||
` | ` | __or__ |
-
__neg__
,__pos__
,__abs__
(abs()
),__invert__
(~
) -
__complex__
,__int__
,__float__
__index__
-
__round__
,__trunc__
,__floor__
,__ceil__
3.3.9 with语句上下文管理器
上下文管理器是指执行with
语句时需要建立的实时上下文。上下文管理器负责处理进入、退出实时上下文时需要执行的代码块。通常使用with
语句,也可以直接调用
-
object.__enter__(self)
进入上下文。 -
object.__exit__(self,exc_type, exc_value, traceback)
退出上下文,三个参数描述了导致上下文退出时的异常;若上下文正常退出,三个参数均为None
3.4 协程Coroutines
3.4.1 可等待对象Awaitable Objects
awaitable
对象实现__await__()
方法,在await
语句中使用。从async def
函数返回的Coroutine
对象也属于可等待对象。
object.__await__(self)
必须返回一个iterator
3.4.2 协程对象Coroutine Objects
Coroutine
对象属于可等待对象。 协程的执行可通过调用__await__()
并迭代其结果来进行控制。当协程结束执行并返回时,迭代器会引发StopIteration
,该异常的value属性将指向返回值。
协程也具有下面列出的方法,它们类似于生成器的对应方法。但是,与生成器不同,协程并不直接支持迭代。
-
coroutine.send(value)
开始或恢复协程的执行. -
coroutine.throw(type[,value[,traceback]])
在协程内引发指定的异常。 -
coroutine.close()
此方法会使得协程清理自身并退出
3.4.3 异步迭代器Asynchronous Iterators
异步迭代器可以在__anext__
方法中调用异步代码。
-
object.__aiter__(self)
返回一个异步迭代器对象 -
object.__anext__(self)
返回一个可等待对象的下一个结果值,或StopAsyncIteration
3.4.4 异步上下文管理器
异步上下文管理器可在async with
语句中使用,需要定义__aenter__
和__aexit__
方法。
4 执行模型
4.1 程序结构
代码块被作为一个单元来执行:模块、函数体、类定义。内置函数eval()
与exec()
的字符串参数也是代码块。
代码块在执行帧中被执行,一个帧包含某些管理信息并决定代码块执行后将如何继续执行。
4.2 命名与绑定
4.2.1 名称绑定
- 名称用于指代对象,通过绑定操作引入:函数的形参,
import
语句,类与函数定义名称,被表达式赋值的目标,for
循环开始,with
与except
语句的as
后。 - import语句
from ... import *
将模块定义的所有导入模块绑定,这种形式绑定仅可用于模块层级。 -
del
语句的目标是解除目标绑定。 - 每条赋值语句或导入语句均发生在类/函数内部定义的代码块中,或者在模块层级(最高层级的代码块)
- 名称绑定在代码块中,则为代码块的局部变量,除非声明
nonlocal
或global
。若名称绑定在模块层级,则为全局变量。(模块代码块的变量即为局部变量又为全局变量。)如果变量在一个代码块中使用但是没有定义,则为自由变量
4.2.2 名称的解析
- 作用域定义了代码块中名称的可见性。如果代码块定义局部变量,其作用域包括该代码块。内部代码块会屏蔽外部代码块的相同名称绑定。
- 环境指对一个代码块可见的所有作用域的集合。当一个名称在代码块中使用时,由它最近的作用域解析。
- 一个代码块内任何位置的名称绑定导致整个代码块对该名称的引用均在此代码块内。
-
global
语句在代码块中表示,所有对该语句指定名称的使用都是最高层级命名空间对该名称的绑定引用。最高层级命名空间就是全局命名空间,包含:模块命名空间、内置命名空间。global
语句必须位于所有指定名称使用之前 -
nonlocal
语句使名称指向之前的最近包含函数作用域中的绑定变量 - 模块的作用域在模块第一次被导入时自动创建,一个脚本的主模块总是被命名为
__main__
- 类定义代码块以及
exec()
与eval()
参数的名称解析是特殊情况。未绑定的局部变量会在全局命名空间查找。?类代码块定义的名称的作用域限制在类代码块中,不会扩展到方法(包括推导式与生成器表达式)中。
4.2.3 内置命名空间与受限的执行
与代码块执行相关的内置命名空间是通过全局命名空间中的builtins来找到。在__main__
模块中,builtins就是内置模块builtins
;在其它模块中builtins是builtins
模块字典的别名
4.2.4 与动态特性的交互
eval()
与exec()
函数没有对完整环境的访问权限以解析名称。名称可以在调用者的局部或者全局命名空间被解析。自由变量的解析不是在最近包含的命名空间,而是在全局命名空间中。
4.3 异常
pass
5 导入系统
import
语句是发起导入机制的常用方式。importlib.import_module()
以及__import__()
等函数也可以用来发起调用导入机制。
import
语句完成两个操作:搜索指定名称的模块,然后将搜索结果绑定至当前作用域名称。搜索操作为__import__()
函数调用,函数的返回值用于执行绑定操作。
对__import__()
的直接调用将仅执行模块搜索以及在找到时的模块创建操作,但可能产生一些副作用,例如导入父包以及更新缓存。
当一个模块首次被导入时,Python会搜索该模块,如果未找到就创建一个module对象并初始化它。
5.1 importlib
importlib
模块用来与导入系统进行交互。例如importlib.import_module()
提供了比内置import()更推荐的调用导入机制接口
5.2 包
包相当于将模块组织在一起的目录,任何具有path属性的模块都看作是包。
- 常规包:含有
__init__.py
文件的目录。当常规包被导入时,该__init__.py
文件被隐式执行。 - 命名空间包:由多个部分组成,每个部分为父包增加子包,没有
__init__.py
文件。
5.3 搜索
Python根据导入模块的完整限定名称开始所示。一个指向子模块的带点号路径将从父包开始依次导入。
- 模块缓存:
-
sys.modules
缓存之前所有导入的模块。 -
sys.modules
键值对应的值为需要导入的模块。删除键值会是模块缓存的条目无效。
-
- 查找器:
- 查找器的任务是确定是否能使用其所知的策略找到该名称的模块。
- Python包含多个默认的查找器:第一个负责定位内置模块;第二个负责定位冻结模块;第三个负载在import path(通常来自
sys.path
,子包还包含上级包__path__
)中搜索模块。 - 查找器返回一个模块的模块规格说明(module spec),以供后续加载过程使用
- 导入钩子(Import hooks):
- 实现导入机制的可扩展性,包含两种钩子:元钩子(meta hooks)与导入路径钩子(import path hooks)
- 元钩子导入开始时被调用(除
sys.modules
缓存查找外,其它导入过程尚未发生)。能够重载查找器特性。元钩子注册通过向sys.meta_path
添加查找器对象完成。(元钩子包含三个默认查找器BuiltinImporter,FrozenImporter,PathFinder实现上述Python默认查找器功能) - 导入路径钩子在遇到所关联的路径条目时被调用。通过向
sys.path_hooks
添加可调用对象完成。(通常被PathFinder在查找时使用)
- 元路径查找器:
- 在
sys.modules
找不到模块时,Python接着搜索sys.meta_path
元路径查找器。元路径查找器必须实现find_spec()
方法。 - 若
sys.meta_path
处理过程到达列表末尾仍未返回说明,则放弃导入过程。
- 在
5.4 加载
在加载器执行模块代码前,先将模块增加至sys.modules
中。模块加载委托加载器执行exec_module()
或load_modules()
进行。
- 子模块:当导入
spam.foo
之后,在spam
中将有一个子模块foo
的属性。 - 模块规格说明:作为模块对象的
__spec__
属性对外公开(参见importlib) - 模块属性:
- 导入机制在加载期间根据模块规格说明填充以下属性,在加载器执行模块前完成
-
__name__
完整限定名称,在导入系统中唯一标识模块 -
__loader__
加载器 -
__package__
可以与name取值相同,对于子模块应设为父包名 __spec__
-
__path__
模块为包是必须设置,必须有字符串组成的可迭代对象,于子包导入期间使用。 -
__file__
可选属性,文件位置 -
__cached__
可选属性,编译缓存文件位置
- 模块的repr
- 缓存字节码:使用
--check-hash-based-pycs
开启基于哈希的.pyc文件有效性检查。
5.5 基于路径的查找器
元路径查找器之一是基于路径的查找器(path based finder)PathFinder
,用以搜索import path
。基于路径的查找器只是遍历路径,具体的查找使用路径条目查找器(path entry finder)进行,并产生缓存查找器对象sys.path_importer_cache
以避免重复的费时查找。
如果路径条目不在缓存中,基于路径的查找器将在每个条目上迭代sys.path_hooks的可调用对象,若找到模块,则返回路径条目查找器对象。
5.6 替换标准导入系统
5.7 包相对导入
导入时使用前缀点号,一个前缀点号表示相对当前包,额外每一个点号代表向上一级
- 绝对导入可以使用
import ...
或from ... import ...
语法 - 相对导入只能使用
from ... import ...
语法形式
5.8 关于__main__
__main__
模块在解释器启动时直接初始化。__main__.__spec__
属性为None
。当在此导入时,__spec__
为模块规格说明
6 表达式
6.1 算术转换
6.2 原子Atom
原子指表达式的最基本构成元素。
atom ::= identifier | literal | enclosure
enclosure ::= parenth_form | list_display | dict_display | set_display
| generator_expression | yield_atom
-
identifier
标识符 -
literal
字面值 -
enclosure
附件
附件包括:
-
parenth_form
带括号的形式,bystarred_expression
-
comprehesion
推导式,byassignment_expression
-
list_display
列表的显示,bystarred_list
与comprehension
-
set_display
集合的显示,bystarred_list
与comprehension
-
dict_display
字典的显示,byexpression
` -
generator_expression
生成器表达式,byexpression
` -
yield_atom
yield表达式,byexpression_list
与expression
6.2.1 标识符identifier
6.2.2 字面值literal
literal ::= stringliteral | bytesliteral
| integer | floatnumber | imagnumber
6.2.3 带括号的形式parenth_form
parenth_form ::= "(" [starred_expression] ")"
6.2.4 推导式comprehension
comprehension ::= assignment_expression/*赋值表达式*/ comp_for
comp_for ::= ["async"] "for" target_list "in" or_test [comp_iter]
comp_iter ::= comp_for | comp_if
comp_if ::= "if" expression_nocond [comp_iter]
Python中,为了构建列表、集合与字典,采用两种方式:
- 第一种的显示的列出容器内容,
- 第二种是通过一组循环和筛选指令计算出来,称为推导式
comp_iter
是推导式结构的隐式作用域。最左侧/最外层的for语句在作用域中求职后,作为参数传入推导式内部的隐式作用域。
6.2.5 列表显示list_display
list_display ::= "[" [starred_list | comprehension] "]"
# 方括号、括号内可为空
6.2.6 集合显示set_display
set_display ::= "{" (starred_list | comprehension) "}"
# 花括号、括号内不为空,否则为字典
6.2.7 字典显示dict_display
dict_display ::= "{" [key_datum_list | dict_comprehension] "}"
key_datum_list ::= key_datum ("," key_datum)* [","]
key_datum ::= expression ":" expression | "**" or_expr
dict_comprehension ::= expression ":" expression comp_for
注:双星号**表示字典拆包,操作数必须是一个mapping
。
6.2.8 生成器表达式
generator_expression ::= "(" expression comp_for ")"
以圆括号括起来的推导式,将产生一个新的生成器对象。
6.2.9 yield表达式
yield_atom ::= "(" yield_expression ")"
yield_expression ::= "yield" [expression_list | "from" expression]
注:当yield表达式是赋值语句右侧的唯一表达式时,括号可以省略
生成器-迭代器Generator-iterator方法:
-
generator.__next__()
- 返回
yield
表达式的expression_list
值
- 返回
-
generator.send(value)
- value参数为
yield
表达式的结果 - 返回生成器的下一个值
- value参数为
-
generator.throw(type[,value[,traceback]])
- 在生成器暂停位置印发
type
类型异常
- 在生成器暂停位置印发
-
generator.close()
- 在称长期函数暂停位置引发
GeneratorExit
- 在称长期函数暂停位置引发
6.3 原型Primary
primary ::= atom | attributeref | subscription | slicing | call
原型表示编程语言中最紧密的绑定操作。
-
atributeref
属性引用 -
subscription
下标抽取 -
slicing
切片 -
call
调用
6.3.1 属性引用
attributeref ::= primary "." identifier
注:此处原型应支持属性引用,否则将产生AttributeError
6.3.2下标抽取
subscription ::= primary "[" expression_list "]"
抽取是在序列或映射中进行。
注:如果原型为映射,表达式列表必须求值为一个以该映射的键为值的对象,值/元组;如果原型为序列,表达式列表必须求值为一个整数或一个切片
6.3.3 切片
slicing ::= primary "[" slice_list "]"
slice_list ::= slice_item ("," slice_item)* [","]
slice_item ::= expression | proper_slice
proper_slice ::= [lower_bound] ":" [upper_bound] [ ":" [stride] ]
lower_bound ::= expression
upper_bound ::= expression
stride ::= expression
注: 如果切片列表包含至少一个逗号,则键将是一个包含切片项转换的元组;否则的话,键将是单个切片项的转换
6.3.4 调用
call ::= primary "(" [argument_list [","] | comprehension] ")"
argument_list ::= positional_arguments ["," starred_and_keywords]
["," keywords_arguments]
| starred_and_keywords ["," keywords_arguments]
| keywords_arguments
positional_arguments ::= positional_item ("," positional_item)*
positional_item ::= assignment_expression | "*" expression
starred_and_keywords ::= ("*" expression | keyword_item)
("," "*" expression | "," keyword_item)*
keywords_arguments ::= (keyword_item | "**" expression)
("," keyword_item | "," "**" expression)*
keyword_item ::= identifier "=" expression
-
poisitional_arguments
位置参数:赋值表达式
or*表达式
-
starred_and_keywords
:混用*表达式
(位置参数)or关键字项
(关键字参数) -
keyword_item
关键字参数:关键字项
or**表达式
若存在关键字参数,首先为正式参数创建一个未填充的空列表,将所有位置参数从前至后依次填入;然后对于每个关键字参数,使用标识符填充相应参数,若空位已被填充则TypeError
;填充完后的空位使用函数的默认值填充,若没有默认值则TypeError
6.4 await表达式
只能在coroutine function
内部使用
await_expr ::= "await" primary
6.5 幂运算符
power ::= (await_expr | primary) ["**" u_expr]
注:幂运算符的绑定比在其左侧的一元运算符更紧密;但绑定紧密程度不及在其右侧的一元运算符
6.6 一元算术和位运算
u_expr ::= power | "-" u_expr | "+" u_expr | "~" u_expr
6.7 二元算术运算
m_expr ::= u_expr | m_expr "*" u_expr | m_expr "@" m_expr |
m_expr "//" u_expr | m_expr "/" u_expr |
m_expr "%" u_expr
a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr
6.8 移位运算
shift_expr ::= a_expr | shift_expr ("<<" | ">>") a_expr
6.9 二元位运算
and_expr ::= shift_expr | and_expr "&" shift_expr
xor_expr ::= and_expr | xor_expr "^" and_expr
or_expr ::= xor_expr | or_expr "|" xor_expr
6.10 比较运算
comparison ::= or_expr (comp_operator or_expr)*
comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="
| "is" ["not"] | ["not"] "in"
6.11 布尔运算
not_test ::= comparison | "not" not_test
and_test ::= not_test | and_test "and" not_test
or_test ::= and_test | or_test "or" and_test
6.12 赋值表达式
assignment_expression ::= [identifier ":="] expression
注:赋值表达式可用于定义:1)列表、集合与字典中的推导式;2)调用中的位置参数;3)作为列表显示、集合显示的表达式列表。
6.13 条件表达式、表达式、lambda表达式
conditional_expression ::= or_test ["if" or_test "else" expression]
注:表达式x if C else y
首先对C求值,结果为真再对x求值,否则对y求值
expression ::= conditional_expression | lambda_expr
lambda_expr ::= "lambda" [parameter_list] ":" expression
expression_nocond ::= or_test | lambda_expr_nocond
lambda_expr_nocond ::= "lambda" [parameter_list] ":" expression_nocond
6.14 lambda表达式
表达式lambda parameters: expression
会产生一个函数对象,该未命名对象类似如下定义
def (parameters):
return expression
6.15 表达式列表
expression_list ::= expression ("," expression)* [","]
starred_item ::= assignment_expression | "*" or_expr
starred_expression ::= expression | (starred_item ",")* [starred_item]
starred_list ::= starred_item ("," starred_item)* [","]
注:starred_list
相比较于expression_list
增加了星号表达式* ...
与赋值表达式... := ...
,用于列表显示、集合显示表达
6.16 求值顺序
6.17 运算符优先级
7 简单语句
简单语句由一个单独的逻辑行构成。 多条简单语句可以存在于同一行内并以分号分隔
simple_stmt ::= expression_stmt
| assert_stmt
| assignment_stmt
| augmented_assignment_stmt
| annotated_assignment_stmt
| pass_stmt
| del_stmt
| return_stmt
| yield_stmt
| raise_stmt
| break_stmt
| continue_stmt
| import_stmt
| future_stmt
| global_stmt
| nonlocal_stmt
7.1 表达式语句
expression_stmt ::= starred_expression
7.2 赋值语句
assignment_stmt ::= (target_list "=")+ (starred_expression | yield_expression)
target_list ::= target ("," target)* [","]
target ::= identifier
| "(" [target_list] ")"
| "[" [target_list] "]"
| attributeref
| subscription
| slicing
| "*" target
7.3 assert语句
简单的assert expression1, expression2
相当于
if __debug__:
if not expression: raise AssertionError(expression2)
7.4 pass语句
7.5 del语句
7.6 return语句
7.7 yeild语句
7.8 raise语句
raise_stmt ::= "raise" [expression ["from" expression]]
如果不带表达式,raise
将重新引起当前作用域内的最后一个激活的异常,若没有异常则引发RuntimeError
。
raise
的首个表达式表异常对象,必须是BaseException
子类或实例。from
子句用于异常串联,若在异常处理器或finally
引发,串联机制隐式发挥作用,可通过在from
子句中指定None
来显示抑制
try:
print(1 / 0)
except:
raise RuntimeError("Something bad happened") from None
7.9 break语句
7.10 continue 语句
7.11 import语句
import_stmt ::= "import" module ["as" identifier] ("," module ["as" identifier])*
| "from" relative_module "import" identifier ["as" identifier]
("," identifier ["as" identifier])*
| "from" relative_module "import" "(" identifier ["as" identifier]
("," identifier ["as" identifier])* [","] ")"
| "from" module "import" "*"
module ::= (identifier ".")* identifier
relative_module ::= "."* module | "."+
7.12 global语句
7.13 nolocal语句
8 复合语句
复合语句是包含其它语句(语句组)的语句;它们会以某种方式影响或控制所包含其它语句的执行。
-
if
,while
和for
语句用来实现传统的控制流程构造。 -
try
语句为一组语句指定异常处理和/和清理代码。 -
with
语句允许在一个代码块周围执行初始化和终结化代码。 - 函数和类定义在语法上也属于复合语句。
一条复合语句由一个或多个子句组成。
- 子句头以一个作为唯一标识的关键字开始并以一个冒号结束。
- 子句体是由一个子句控制的一组语句。 子句体可以是在子句头的冒号之后与其同处一行的一条或由分号分隔的多条简单语句,或者也可以是在其之后缩进的一行或多行语句。但是,只有在缩进形式下才可以嵌套复合语句。
#复合语句
compound_stmt ::= if_stmt
| while_stmt
| for_stmt
| try_stmt
| with_stmt
| funcdef
| classdef
| async_with_stmt
| async_for_stmt
| async_funcdef
#子句体
suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT
statement ::= stmt_list NEWLINE | compound_stmt
stmt_list ::= simple_stmt (";" simple_stmt)* [";"]
8.1 if语句
8.2 while语句
while_stmt ::= "while" assignment_expression ":" suite
["else" ":" suite]
8.3 for语句
for_stmt ::= "for" target_list "in" expression_list ":" suite
["else" ":" suite]
注: 系统将为expression_list
的结果创建一个迭代器,然后将为迭代器所提供的每一项执行一次子句体,具体次序与迭代器的返回顺序一致
注:当所有项被耗尽时,else
子句的子句体如果存在将会被执行,并终止循环。
- for循环子句头会对目标列表的变量进行赋值,将覆盖变量的赋值(包括循环体内的赋值)
- 目标列表的名称在循环结束时不会被删除,但是如果迭代序列为空,名称将不会被赋值。
8.4 try语句
try_stmt ::= try1_stmt | try2_stmt
try1_stmt ::= "try" ":" suite
("except" [expression ["as" identifier]] ":" suite)+
["else" ":" suite]
["finally" ":" suite]
try2_stmt ::= "try" ":" suite
"finally" ":" suite
- 如果在对
except
子句头中的表达式求值时引发了异常,则原来对异常处理器的搜索会被取消,启动对新的异常的搜索 - 当找到一个匹配的
except
子句时,该异常将被赋值给该except
子句在as
关键字之后指定的目标,并在except
子句体执行。 - 当使用
as
将目标赋值为一个异常时,它将在except
子句结束时被清除。 -
else
语句的异常不会由之前的except
子句处理 -
finally
指定异常清理程序,如果在try
,except
和else
子句中发生未处理的异常,先暂时保存,至finally
子句末尾重新引发;若finally
子句产生新的异常,被保存的异常被设置为新异常的上下文。
8.5 with语句
with_stmt ::= "with" with_item ("," with_item)* ":" suite
with_item ::= expression ["as" target]
注:with
语句会保证如果__enter__()
方法返回时未发生错误,则__exit__()
将总是被调用。
8.6 函数定义
funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")"
["->" expression] ":" suite
decorators ::= decorator+
decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE
dotted_name ::= identifier ("." identifier)*
parameter_list ::= defparameter ("," defparameter)* "," "/" ["," [parameter_list_no_posonly]]
| parameter_list_no_posonly
parameter_list_no_posonly ::= defparameter ("," defparameter)* ["," [parameter_list_starargs]]
| parameter_list_starargs
parameter_list_starargs ::= "*" [parameter] ("," defparameter)* ["," ["**" parameter [","]]]
| "**" parameter [","]
parameter ::= identifier [":" expression]
defparameter ::= parameter ["=" expression]
funcname ::= identifier
参数说明:
-
decorators
装饰器组:由多个装饰器组成 -
decorator
装饰器- 以点号(属性)名称标识装饰器
- 可以调用形式输入
argument_list
,即包括位置参数、关键字参数等 - 以
NEWLINE
结尾
-
parameter_list
形参列表:- 多个函数形参组成的列表
- 由
*参数
,**参数
构成的参数列表。在*
或*identifier
后的函数形参仅接受关键字参数。 - 参数列表中的斜杠字符
/
参数用于分隔位置形参与关键字形参,位于/
前的形参不能接受关键字参数。
-
defparameter
形参:- 以形参 = 表达式设置默认形参值
特别注意:
- 函数定义是一条可执行语句。将函数名称绑定至一个函数对象
- 函数定义不会执行函数体,只有当函数调用时才会执行。
- 装饰器以函数对象作为输入,求值结果绑定至函数名称。
- 如果一个形参具有默认值,则后续所有在
*
之前的形参也必须具有默认值。 - 默认形参在执行函数定义时按照从左至右的顺序被求值,注意默认形参为可变对象的情况时,通常与预期不一致。
- 形参可以带有标注
: expression
;函数可以带有返回标注-> expression
。标注的存在不改变函数语义。 标注值可以作为函数对象的__annotations__
属性中以对应形参名称为键的字典值被访问。
8.7 类定义
classdef ::= [decorators] "class" classname [inheritance] ":" suite
inheritance ::= "(" [argument_list] ")"
classname ::= identifier
8.8 协程
async_funcdef ::= [decorators] "async" "def" funcname "(" [parameter_list] ")"
["->" expression] ":" suite
async_for_stmt ::= "async" for_stmt
async_with_stmt ::= "async" with_stmt
- 协程函数:可以在多个位置上挂起与恢复执行。
await
、async for
与async with
只能在协程函数体内部使用。 - async for语句
- async with语句
9 最高层级组件
9.1 完整的Python程序
Python程序会在最小初始化环境中被执行:所有内置模块和标准模块均可用但均处于未初始化状态;仅有sys
,builtins
,__main__
初始化;__main__
模块提供局部、全局命名空间。
一个完整程序可通过三种形式被传递给解释器:
- 使用 -c 字符串 命令行选项,
- 使用一个文件作为第一个命令行参数,
- 使用标准输入。
如果文件或标准输入是一个 tty 设置,解释器会进入交互模式;否则的话,它会将文件当作一个完整程序来执行。
10 完整语法
原文来自:Python官网的Python 语言参考(3.8.2版本)。
若侵权请联系删除