Python官方语法学习

通读了Python官网的语法说明文档。原文来自:Python 语言参考(3.8.2版本)。在此,将原文的要点进行记录与分享。


1 概述


2 词法分析

Python 程序由一个解析器读取。输入到解析器的是一个由词法分析器所生成的形符流。Python 会将读取的程序文本转为 Unicode 码点;源文件的文本编码可由编码声明指定,默认为 UTF-8。

2.1 行结构

  1. 逻辑行NEWLINE形符表示。
    • 语句不能跨逻辑行。
    • 逻辑行可由多个物理行按规则拼接
  2. 物理行以换行字符终止,如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

特殊的标识符

  1. _*:以下划线字符_开始的标识符不会被import语句from module import *导入。
  2. __*__:以双下划线字符开始并结尾的标识符为系统定义的名称,特殊方法对于的名称
  3. __*:以双下划线开始的标识符是类的私有名称,会被类定义隐式的转换。

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      ::=  

注:

  1. ! 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 标准类型层级

  1. None

  2. NotImplemented
    逻辑值为真

  3. Ellipsis
    逻辑值为真

  4. numbers.Number

    • numbers.Integeral
      • 整形(int)
      • 布尔型(bool)
    • numbers.Real(float)
    • numbers.Complex(complex)
  5. 序列: 有限有序集,支持len(),切片a[i:j],扩展切片a[i:j:k]

    • 不可变序列:
      • 字符串str
      • 元组
      • 字节串bytes
    • 可变序列:
      • 列表
      • 字节数值bytearray
      • 扩展模块arraycollections
  6. 集合类型:无序有限集,支持迭代,支持len()

    • 集合set()
    • 冻结集合frozenset()
  7. 映射:任意索引类型的有限集合,支持下标a[k]用于赋值或del语句,支持len()

    • 字典
  8. 可调用类型

    • 用户定义函数,特殊属性:

      1. __doc__ 可写
      2. __name__ 可写
      3. __qualname__ 可写,函数限定名称,显式从模块开始的层级
      4. __module__ 可写,函数所述模块的名称
      5. __defaults__ 可写,默认参数值构成的元组
      6. __code__ 可写,变异后的函数体代码
      7. __globals__ 只读,函数所属模块的全局命名空间字典引用
      8. __dict__ 可写,命名空间支持的函数属性
      9. __closure__ 只读
      10. __annotations__ 可写,包含参数标注的自定
      11. __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__()使类实例可调

  9. 模块

    • 具有字典对象实现的命名空间,也是模块中函数__globals__所引用的字典
    • 可写属性:__name____doc____annotations____file__
    • 只读属性__dict__
  10. 自定义类

    • 每个类都通过字典实现独立的命名空间,类属性在字典中查找
    • 特别属性:__name____module__类所在模块,__dict____bases__包含基类的元组,__doc____annotations__
  11. 类实例

    • 通过调用类对象创建,每个类实例通过字典实现独立的命名空间。
    • 若为找到类属性,而对象对应的类具有__getattr__()方法则会调用该方法。
    • 属性赋值与删除会更新实例字典,但不更新类字典。若类具有__setattr__()__delattr()__则调用方法而不直接更新实例字典
    • 特殊属性:__dict____class__
  12. I/0对象

  13. 内部类型(定义可能在未来解释器版本中变化)

    • 代码对象
      • 编译为字节的可执行Python代码,或称bytecode
      • vs函数对象,函数对象具有全局对象的引用,代码对象不包含上下文
    • 帧对象:表示执行帧
    • 回溯对象:表示异常的栈跟踪记录。
    • 切片对象:表示__getitem__()方法得到的切片,
    • 静态方法对象:
      • 为对任意其它对象的封装,静态方法对象自身是不可调用的。
      • 从类或类实例中获得的静态方法对象时,获得的是被封装的对象。
      • 可由staticmethod()构造器创建
    • 类方法对象:
      • 对其他对象的封装。
      • 可由classmethod()构造器创建。

3.3 特殊方法

3.3.1 基本定制Basic customization

  1. object.__new__(cls[,...])
    • 创建cls类的新实例,__new__()总是一个静态方法。返回值应为新对象(通常为cls)实例
    • 典型的实现总有super().__new__(cls[, ...])调用。
    • 如果__new__()发返回了一个cls的实例或者子类,则新实例将调用__init__(self[, ...])进行初始化
    • __new__()没有返回cls的实例,则不会有__init__()调用
    • 用以对int,str或tuple等子类的自定义;用以创建唯一对象singleton
  2. object.__init__(self[, ...])
    • 其参数与传递给构造表达器的参数相同。
    • 应确保基类正确初始化super().__init__([args...])
    • 返回值为None
  3. object.__del__(self)
    • 在实例被销毁时调用
    • 派生类需确保基类的__del__()正确被调用
    • 注:del xx的引用计数减一;当引用计数为零时,才可能执行x.__del__()
  4. object.__repr__(self)
    • 若可能,使用输出的字符串能重建相同取值的对象;若不可能则返回形如<...一些有用信息...>的字符串
  5. object.__str__(self):一种非正式或格式良好的字符串
  6. object.__bytes__(self):返回bytes对象
  7. object.__format__(self, format_spec):对象的格式化字符串显示
  8. 比较方法
    • object.__lt__(self, other)
    • object.__le__(self, other)
    • object.__eq__(self, other)
    • object.__ne__(self, other)
    • object.__gt__(self, other)
    • object.__ge__(self, other)
    • 注:当比较操作的左操作数未实现相关函数,而右操作数有实现,则调用右操作数的方法;当右操作数是左操作数的子类时,优先有操作数的方法
  9. object.__hash__(self)
    • 用于对哈希集setfrozensetdict执行哈希函数hash()。建议将参与比较的对象组件打包为元组整体进行hash计算
    • __eq__()
      • 用户定义类默认有__eq__()__hash__()方法,确保当x==y时意味着x is yhash(x)==hash(y)
      • 若仅定义__eq__()时,则将__hash__()隐式设置为None;若须保留父类的__hash__()实现,须在类中明确__hash__ = .__hash__
      • 若未定义__eq__()则不应定义__hash__();若定义__eq__()同时定义了可变对象也不应定义__hash__(),否则对象可能至于错误的哈希桶中。
      • 若未定义__eq__()时也不需要默认的__hash__(),则应在类中明确__hash__ = None
    • 注: 在str与bytes对象的hash值由随机数加盐,在单独的python进程中是一致的。
  10. object.__bool__(self)
    • 若类未定义__bool__()也未定义__len__()则实例逻辑值为真

3.3.2 属性访问

  1. object.__getattr__(self, name)
    • 当默认属性访问失败时调用:
      • 可能由于__getattribute__()时 ,name非实例属性
      • 或者对于name特性调用__get__()
  2. object.__getattribute__(self, name)
    • 类实例属性访问调用。为避免方法的无限递归,总是调用相同名称的基类方法实现
  3. object.__setattr__(self, name, value)
    • 当实例属性被赋值时调用。正常实现是调用相同名称的基类方法
  4. object.__delattr__(self, name)
    • __setattr__()效果范围类似,仅在del obj.name时生效
  5. 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)的实例是其他所有类的成员时,这些特殊方法才有效

  1. object.__get__(self,instance,owner=None)
    • 实现所有者类属性/类实例属性的方法
  2. object.__set__(self,instance,value)
    • 设置instance指向的属性值为新值
    • 使用__set__()__delete__()将描述器变为数据描述器
  3. object.__delete__(self,instance)
  4. 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__

  1. object.__slots__
    • slots用以显示声明数据成员,禁止创建__dict__以及__weakref__除非显示声明或在父类中可用.
    • 继承一个未定义slots的类时,实例的__dict____weakref__总是可访问的。

3.3.3 类创建

classmethod object.__init_subclass__(cls)

  • 当一个类继承自其它类时,基类的init_subclass会被调用。
  • 基类控制子类的特性,相较于元类更加灵活
  • 隐式的classmethod

元类

默认情况,类是由type()构建type(name,bases,dict)。在类创建定义中传入metaclass关键字参数,控制类创建使用的元类。

  1. 解析MRO条目
  2. 确定适当的元类
    • 若没有基类且没有显示指定元类,使用type()
    • 若给出显示的元类且不是type()的实例,则直接用作元类
    • 若给出一个type()实例作为元类,或者定义了基类,则使用最近派生的元类
  3. 准备类命名空间
    • 若元类有__prepare__属性,则以namespace = metaclass.__prepare__(name,bases,**kwds)调用,namespace传递给元类的__new__
    • 元类的__prepare__须显式声明为classmethod
    • __prepare__返回的命名空间返回给__new__,但最终类对象创建时,命名空间拷贝至新的只读代理dict中,作为类对象的字典。
  4. 执行类主体
  5. 创建类对象
    • 执行元类__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() 应当迭代对象的键;对于序列,则应当迭代其中的值

  1. object.__len__(self)
  2. object.__length_hint__(self)(可选)
  3. object.__getitem__(self,key)
  4. object.__setitem__(self,key,value)
  5. object.__delitem__(self,key)
  6. object.__missing__(self,key)(在getitem找不到键时调用)
  7. object.__iter__(self)
  8. object.__reversed__(self)
  9. 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属性将指向返回值。
协程也具有下面列出的方法,它们类似于生成器的对应方法。但是,与生成器不同,协程并不直接支持迭代。

  1. coroutine.send(value)开始或恢复协程的执行.
  2. coroutine.throw(type[,value[,traceback]])在协程内引发指定的异常。
  3. coroutine.close()此方法会使得协程清理自身并退出

3.4.3 异步迭代器Asynchronous Iterators

异步迭代器可以在__anext__方法中调用异步代码。

  1. object.__aiter__(self)返回一个异步迭代器对象
  2. object.__anext__(self)返回一个可等待对象的下一个结果值,或StopAsyncIteration

3.4.4 异步上下文管理器

异步上下文管理器可在async with语句中使用,需要定义__aenter____aexit__方法。


4 执行模型

4.1 程序结构

代码块被作为一个单元来执行:模块、函数体、类定义。内置函数eval()exec()的字符串参数也是代码块。

代码块在执行帧中被执行,一个帧包含某些管理信息并决定代码块执行后将如何继续执行。

4.2 命名与绑定

4.2.1 名称绑定

  1. 名称用于指代对象,通过绑定操作引入:函数的形参,import语句,类与函数定义名称,被表达式赋值的目标,for循环开始,withexcept语句的as后。
  2. import语句from ... import *将模块定义的所有导入模块绑定,这种形式绑定仅可用于模块层级。
  3. del语句的目标是解除目标绑定。
  4. 每条赋值语句或导入语句均发生在类/函数内部定义的代码块中,或者在模块层级(最高层级的代码块)
  5. 名称绑定在代码块中,则为代码块的局部变量,除非声明nonlocalglobal。若名称绑定在模块层级,则为全局变量(模块代码块的变量即为局部变量又为全局变量。)如果变量在一个代码块中使用但是没有定义,则为自由变量

4.2.2 名称的解析

  1. 作用域定义了代码块中名称的可见性。如果代码块定义局部变量,其作用域包括该代码块。内部代码块会屏蔽外部代码块的相同名称绑定。
  2. 环境指对一个代码块可见的所有作用域的集合。当一个名称在代码块中使用时,由它最近的作用域解析。
  3. 一个代码块内任何位置的名称绑定导致整个代码块对该名称的引用均在此代码块内。
  4. global语句在代码块中表示,所有对该语句指定名称的使用都是最高层级命名空间对该名称的绑定引用。最高层级命名空间就是全局命名空间,包含:模块命名空间、内置命名空间。global语句必须位于所有指定名称使用之前
  5. nonlocal语句使名称指向之前的最近包含函数作用域中的绑定变量
  6. 模块的作用域在模块第一次被导入时自动创建,一个脚本的主模块总是被命名为__main__
  7. 类定义代码块以及exec()eval()参数的名称解析是特殊情况。未绑定的局部变量会在全局命名空间查找。?类代码块定义的名称的作用域限制在类代码块中,不会扩展到方法(包括推导式与生成器表达式)中。

4.2.3 内置命名空间与受限的执行

与代码块执行相关的内置命名空间是通过全局命名空间中的builtins来找到。在__main__模块中,builtins就是内置模块builtins;在其它模块中builtinsbuiltins模块字典的别名

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根据导入模块的完整限定名称开始所示。一个指向子模块的带点号路径将从父包开始依次导入。

  1. 模块缓存:
    • sys.modules缓存之前所有导入的模块。
    • sys.modules键值对应的值为需要导入的模块。删除键值会是模块缓存的条目无效。
  2. 查找器:
    • 查找器的任务是确定是否能使用其所知的策略找到该名称的模块。
    • Python包含多个默认的查找器:第一个负责定位内置模块;第二个负责定位冻结模块;第三个负载在import path(通常来自sys.path,子包还包含上级包__path__)中搜索模块。
    • 查找器返回一个模块的模块规格说明(module spec),以供后续加载过程使用
  3. 导入钩子(Import hooks):
    • 实现导入机制的可扩展性,包含两种钩子:元钩子(meta hooks)导入路径钩子(import path hooks)
    • 元钩子导入开始时被调用(除sys.modules缓存查找外,其它导入过程尚未发生)。能够重载查找器特性。元钩子注册通过向sys.meta_path添加查找器对象完成。(元钩子包含三个默认查找器BuiltinImporter,FrozenImporter,PathFinder实现上述Python默认查找器功能)
    • 导入路径钩子在遇到所关联的路径条目时被调用。通过向sys.path_hooks添加可调用对象完成。(通常被PathFinder在查找时使用)
  4. 元路径查找器:
    • sys.modules找不到模块时,Python接着搜索sys.meta_path元路径查找器。元路径查找器必须实现find_spec()方法。
    • sys.meta_path处理过程到达列表末尾仍未返回说明,则放弃导入过程。

5.4 加载

在加载器执行模块代码前,先将模块增加至sys.modules中。模块加载委托加载器执行exec_module()load_modules()进行。

  1. 子模块:当导入spam.foo之后,在spam中将有一个子模块foo的属性。
  2. 模块规格说明:作为模块对象的__spec__属性对外公开(参见importlib
  3. 模块属性:
    • 导入机制在加载期间根据模块规格说明填充以下属性,在加载器执行模块前完成
    • __name__完整限定名称,在导入系统中唯一标识模块
    • __loader__加载器
    • __package__可以与name取值相同,对于子模块应设为父包名
    • __spec__
    • __path__模块为包是必须设置,必须有字符串组成的可迭代对象,于子包导入期间使用。
    • __file__可选属性,文件位置
    • __cached__可选属性,编译缓存文件位置
  4. 模块的repr
  5. 缓存字节码:使用--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
  1. identifier标识符
  2. literal字面值
  3. enclosure附件

附件包括:

  1. parenth_form带括号的形式,by starred_expression
  2. comprehesion推导式,by assignment_expression
  3. list_display列表的显示,by starred_listcomprehension
  4. set_display集合的显示,by starred_listcomprehension
  5. dict_display字典的显示,by expression`
  6. generator_expression生成器表达式,by expression`
  7. yield_atomyield表达式,byexpression_listexpression

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表达式的结果
    • 返回生成器的下一个值
  • generator.throw(type[,value[,traceback]])
    • 在生成器暂停位置印发type类型异常
  • generator.close()
    • 在称长期函数暂停位置引发GeneratorExit

6.3 原型Primary

primary ::=  atom | attributeref | subscription | slicing | call

原型表示编程语言中最紧密的绑定操作。

  1. atributeref属性引用
  2. subscription下标抽取
  3. slicing切片
  4. 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 复合语句

复合语句是包含其它语句(语句组)的语句;它们会以某种方式影响或控制所包含其它语句的执行。

  • ifwhilefor语句用来实现传统的控制流程构造。
  • 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子句的子句体如果存在将会被执行,并终止循环。

  1. for循环子句头会对目标列表的变量进行赋值,将覆盖变量的赋值(包括循环体内的赋值)
  2. 目标列表的名称在循环结束时不会被删除,但是如果迭代序列为空,名称将不会被赋值。

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指定异常清理程序,如果在tryexceptelse子句中发生未处理的异常,先暂时保存,至 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

参数说明:

  1. decorators装饰器组:由多个装饰器组成
  2. decorator装饰器
    • 以点号(属性)名称标识装饰器
    • 可以调用形式输入argument_list,即包括位置参数、关键字参数等
    • NEWLINE结尾
  3. parameter_list形参列表:
    • 多个函数形参组成的列表
    • *参数**参数 构成的参数列表。在**identifier后的函数形参仅接受关键字参数。
    • 参数列表中的斜杠字符/参数用于分隔位置形参与关键字形参,位于/前的形参不能接受关键字参数。
  4. defparameter形参:
    • 形参 = 表达式设置默认形参值

特别注意:

  1. 函数定义是一条可执行语句。将函数名称绑定至一个函数对象
  2. 函数定义不会执行函数体,只有当函数调用时才会执行。
  3. 装饰器以函数对象作为输入,求值结果绑定至函数名称。
  4. 如果一个形参具有默认值,则后续所有在*之前的形参也必须具有默认值。
  5. 默认形参在执行函数定义时按照从左至右的顺序被求值,注意默认形参为可变对象的情况时,通常与预期不一致。
  6. 形参可以带有标注: 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
  1. 协程函数:可以在多个位置上挂起与恢复执行。awaitasync forasync with只能在协程函数体内部使用。
  2. async for语句
  3. async with语句

9 最高层级组件

9.1 完整的Python程序

Python程序会在最小初始化环境中被执行:所有内置模块和标准模块均可用但均处于未初始化状态;仅有sysbuiltins__main__初始化;__main__模块提供局部、全局命名空间。

一个完整程序可通过三种形式被传递给解释器:

  1. 使用 -c 字符串 命令行选项,
  2. 使用一个文件作为第一个命令行参数,
  3. 使用标准输入。

如果文件或标准输入是一个 tty 设置,解释器会进入交互模式;否则的话,它会将文件当作一个完整程序来执行。

10 完整语法

原文来自:Python官网的Python 语言参考(3.8.2版本)。
若侵权请联系删除

你可能感兴趣的:(Python官方语法学习)