近期比较空闲,也想更好的使用python,所以决定整理一下基础知识,代码来自源码,解析来自官方文档。
"""
函数定义:定义用户定义的函数对象(请参见"标准类型层次结构"一节):
funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite
decorators ::= decorator+
decorator ::= "@" assignment_expression newline def(a = 1,/ *a,**a
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:装饰器
parameter_list:参数列表a,b:1,c=1 / a,b:1,c=1,*args,**kwargs
expression:表达方式
decorator:装饰器表达式
assignment_expression:赋值表达式
newline:换行字符
identifier:标识符
parameter:参数
parameter_list_no_posonly:没有限制的参数列表a,b:1,c = 1,*args,**kwargs
parameter_list_starargs:起始参数的参数列表*args,**kwargs
("," x)*:表示x出现0次或多次
["," [x]] | x:表示x至少出现一次
/:或者,二选一
函数定义是一个可执行语句.它的执行将当前本地命名空间中的函数名绑定到函数对象(围绕函数的可执行代码的包
装器).此函数对象包含对当前全局命名空间的引用,作为调用函数时要使用的全局命名空间.
函数定义不执行函数体;仅在调用函数时执行.
函数定义可以由一个或多个*decorator*表达式包装.定义函数时,将在包含函数定义的范围内计算装饰器表达式.
结果必须是一个可调用的,它是以函数对象作为唯一参数调用的.返回值绑定到函数名而不是函数对象.多个装饰器
以嵌套方式应用.例如,下面的代码
@f1(arg)
@f2
def func(): pass
大致相当于
def func(): pass
func = f1(arg)(f2(func))
在版本3.9中更改:函数可以用任何有效的"assignment_expression(赋值表达式)"修饰.以前,语法的限制性要大
得多;详见**PEP 614**.
当一个或多个*parameters*的形式为*parameter* "="*expression*时,该函数被称为具有"default parameter
values.".对于具有默认值的参数,可以从调用中省略相应的*argument*,在这种情况下,参数的默认值被替换.如果
一个参数有一个默认值,则在"*"之前的所有后续参数都必须有一个默认值-这是一个语法未表达的语法限制.
**在执行函数定义时,默认参数值从左到右求值.**这意味着在定义函数时表达式求值一次,并且每次调用都使用相同的
"precomputed(预计算)"值.当默认参数是可变对象(如列表或字典)时,了解这一点尤为重要:如果函数修改对象(例如,
通过向列表中添加项),则默认值实际上已修改.这通常不是我们的初衷.解决此问题的一种方法是使用“None”作为默认
值,并在函数体中显式测试它,例如:
def whats_on_the_telly(penguin=None):
if penguin is None:
penguin = []
penguin.append("property of the zoo")
return penguin
函数调用语义在"section Calls"一节中有更详细的描述.函数调用始终为参数列表中提到的所有参数赋值,可以是位置
参数、关键字参数,也可以是默认值.如果存在格式"*identifier",则将其初始化为接收任何多余位置参数的元组,默认
为空元组.如果存在格式"**identifier",则会将其初始化为接收任何多余关键字参数的新有序映射,默认为相同类型的
新空映射."*"或"*identifier"后的参数是仅限关键字的参数,只能通过关键字参数传递."/"之前的参数仅为位置参数,
只能由位置参数传递.
在版本3.8中更改:"/"函数参数语法可用于指示仅位置参数.详见**PEP 570**.
参数名称后面可能有一个格式为": expression"的*annotation(注释)*.任何参数都可以有注释,即使是形式为"*identifier"
或"**identifier"的参数.函数在参数列表后可能有格式为"-> expression"的"return"注释.这些注释可以是任何有效的Python
表达式.注释的存在不会改变函数的语义.注释值可作为字典值使用,字典值由函数对象的"__annotations__"属性中的参数名称键入.
如果使用从"__future__"导入的"annotation(注释)",则注释将在运行时保留为字符串,从而启用延迟计算.否则,将在执行函数定义
时对其求值.在这种情况下,注释的计算顺序可能与它们在源代码中出现的顺序不同.
还可以创建匿名函数(未绑定到名称的函数),以便在表达式中立即使用.这使用Lambda表达式,如Lambdas一节所述.请注意,Lambda表
达式只是简化函数定义的简写;"def"语句中定义的函数可以传递或分配给另一个名称,就像lambda表达式定义的函数一样."def"表单
实际上更强大,因为它允许执行多个语句和注释.
**程序员须知:**函数是一级对象.在函数定义内执行的"def"语句定义了可以返回或传递的本地函数.嵌套函数中使用的自由变量可以访
问包含def的函数的局部变量.有关详细信息,可参阅Naming and binding部分.
另见:
**PEP 3107** - 函数注解
函数注释的原始规范。
**PEP 484** - 类型提示
注释标准含义的定义:类型提示。
**PEP 526** - 变量注释的语法
能够键入提示变量声明,包括类变量和实例变量
**PEP 563** - 推迟对注释的评价
通过在运行时以字符串形式保留注释,而不是在即时计算中,支持注释内的正向引用。
"""
参考文档:Python 教程 — Python 3.10.0 文档
待完善...



