第九弹 python函数

简介

是对程序逻辑进行结构化或过程化的一种编程方法。将大量重复代码放到函数中,即可以节省空间,又有助于保持一致性;

函数关键字def定义,def关键字后跟一个函数的标识符名称,然后跟一对圆括号。圆括号之中可以包含一些变量名,该行以冒号结尾。接下来就是函数体;

函数在执行时,使用函数局部变量符号表,所有函数变量赋值都存在局部符号表中;引用变量时,首先从局部符号表中查找,然后从外层函数局部符号表中查找,再从全局符号表,最后是内置符号表。因此,尽管可以引用全局变量和外层函数变量,但是最好不要在函数内直接赋值,除非是global语句定义的全局变量,或nonlocal语句定义的外层函数变量

在调用函数时,会将实际参数引入到被调用函数的局部符号表中;因此,实参是使用按值调用来传递的;当一个函数调用另一个函数时,会为该调用创建一个新的全局符号表;

函数定义在当前符号表中把函数名与函数对象关联在一起,解释器把函数名指向的对象作为用户自定义函数。还可以使用其他名称指向一个函数对象,并访问该函数;

参数

参数在函数定义的圆括号中指定,以逗号分隔;函数中的参数名称为形参,调用函数时传入的参数为实参;

默认值参数

调用函数时,可以使用比定义时更少的参数;极大的提升了程序的健壮性和灵活性;

def f(arg1, arg2='2'):
    pass

默认值只计算一次。会在执行函数定义时按从左至右的顺序被求值;当为列表、字典或类实例等可变对象时,会产生与该规则不同的结果;

如:

def f(a, l=[]):
    l.append(a)
    return l

print(f(1))   # [1]
print(f(2))   # [1, 2]
print(f(3))   # [1, 2, 3]

关键字参数

key/value形式的参数;在函数调用时,关键字参数必须跟在位置参数后面。所有传递的关键字参数都必须匹配一个函数接收的参数;关键字参数的顺序并不重要;如果最后一位形参为**kw形式,该字典包含除了函数中已经定义的形参之外的所有关键字参数;

可以通过**dct形式,接收一个字典,该字典包含与函数中已定义形参对应之外的所有关键字参数;

特殊参数

参数可以按照位置或关键字传递给python函数;为了让代码易读、高效,最好限制参数的传递方式,这样让开发者查看函数定义,即可确定参数项是仅按位置、按位置或关键字、仅限关键字传递;可以通过 / * 来定义

如:

def f(pos1, pos2, /, pos_or_kw, *, k1,  k2):
     ------------    ---------     -------
           |            |           |
       仅按位置参数   按位置或关键字  仅按关键字参数
    pass

/  * 是可选的;这些符号表明形参如何把参数值传递给函数;仅限位置、按位置或关键字、仅限关键字;

仅限位置参数

仅限位置参数时,形参的顺序很重要,且这些形参不能使用关键字传递。仅限位置形参必须放在 / 之前;/ 在逻辑上分隔仅限位置形参;如果函数定义中没有  / ,则表示没有仅限位置参数; / 后可以是位置或关键字或仅限关键字形参;

仅限关键字参数

形参标记为仅限关键字,则表明必须以关键字参数形式传递形参,应该在参数列表中第一个仅限关键字形参前添加 *

def standard_arg(arg):
    pass

def pos_only_arg(arg, /):
    pass

def kwd_only_arg(*, arg):
    pass

def combined_example(pos_only, /, standard, *, kwd_only):
    pass

第一个函数:是最常见的形式;对于调用方式没有任何限制,可以按位置也可以按照关键字传递

>>> standard_arg(2)
>>> standard_arg(arg=2)

第二个函数:定义中存在 /,那么仅限位置参数

>>> pos_only_arg(1)

第三个函数:定义中存在 ,表明仅限关键字参数

>>> kwd_only_arg(arg=1)

第四个函数:使用全部三种惯例

>>> combined_example(1, 2, kwd_only=3)

任意实参列表

调用函数时,使用任意数量的实参是最少见的选项;这些实参包含在元组中;

*args用于接收传递给函数的所有剩余位置参数;因此*args之后不允许出现位置参数;

def f(file, *args):
    pass

解包实参列表

函数调用要求独立的位置参数,但实参在列表或元组里时,需要通过 操作符把实参从列表或元组中解包处理啊;

同样也可以通过  ** 操作符把实参从字典中解包;

list(range(*[2, 6]))

f(**{'k1': v1, 'k2': v2})

lambda

lambda用于创建匿名函数。也可用于任何需要函数对象的地方。在语法上,匿名函数只能是单个表达式。在语义上,它只是常规函数定义的语法糖。与嵌套函数一样,lambda也可以引用包含作用于中的变量;

lambda  x, b: a + b

函数注解

函数注解是可选的;只是一种在编译阶段将python表达式与函数的各个部分建立关联的方式,python本身不会为注解关联任何特定的含义或意义;注解表达式是独立存在的,python只是让这些表达式可供使用,仅当第三方库解释时,注解才能发挥作用;

参数注解

格式:

def f(a: expression, b: expression = 5):
    pass

参数注解始终位于参数默认值之前,注解和默认值都是可选的。用冒号把注解标出来。在函数定义得以运行时,将会对所有注解表达式进行求值;

*args**kwargs可变长参数的注解

def f(*args: expression, **kwargs: expression)

嵌套参数的注解:

总跟在参数名的后面

def f((x1, y1: expression), (x2: expression, y2: expression) = (None, None)):
    pass

返回值注解

格式:

def f() -> expression:
    pass

参数列表后面跟一个 -> 和python表达式。和参数注解一样,函数定义得以运行时将会对该表达式求值;

lambda

不支持注解。当然也可以改为支持注解的格式,需要在参数列表两侧加上括号;

有以下原因,决定不再改动:

  • 该改动不具有兼容性
  • lambda已经式微
  • lambda表达式一定能变成函数

函数注解的读取

只要经过编译,函数注解就可以通过函数的__annotations__属性访问;该属性是一个可变的字典,将参数名称映射一个代表已求值注解表达式的对象;

__annotations__映射中有一个特殊键return,仅当提供了函数返回值的注解时才有效;选择return是因为为了避免参数名称发生冲突,任何时候把return作为参数名称,都会引发SyntaxError

如果函数没有注解或由lambda表达式生成的,则__annotations__将是一个空字典;

如:

def f(a: 'x', b: 5+6, c: list) -> max(2, 9):
    pass

# __annotations__映射为:
{'a': 'x', 'b': 11, 'c': list, 'return': 9}

文档字符串

第一行应该为函数用途的简短摘要。为了保持简洁,不要在这里显示说明对象名或类型,因为可通过其它方式获取这些信息;这一行应该为大写字母开头,以句点结尾
文档字符串为多行时,第二行应为空白行,在视觉上将摘要与其描述分开。后面的行可包含若干段落,描述对象的调用约定、副作用等等;
python解析器不会删除python中多行字符串字面值的缩紧,因此,文档处理工具应在必要时删除缩进。

def f():
    """Do nothing, but  document it.
    
    No, really, it doesn't do anything.
    """
    pass

return

return跳出函数。如果函数没有返回值return语句,那么等价于return None

嵌套函数

内部函数整个函数题都在外部函数作用于,如果没有任何对内部函数的引用,那么,1除了在函数体内,任何地方都不能对其进行调用;

如果内部函数的定义包含了外部函数里面定义的对象引用,内部函数就会变成闭包

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值