夜阑卧听风吹雨

铁马冰河入梦来

Loading

Python-2 函数、参数

函数

  1. help(abs):查看函数 abs 的帮助信息。

  2. pass:占位符,还没想好怎么写,先 pass,让程序跑起来看一下。

    • 比如在 if 语句下,定义函数如下。
    def my_abs(x):
        if not isinstance(x, (int, float)):
            raise TypeError('bad operand type')
        if x >= 0:
            return x
        else:
            return -x
    
  3. 定义函数下,第一行使用:"函数的说明注释"

  4. Python 可以返回多个值,return x, y

  5. 接收:x, y = testFunc(xxx)

  • 返回的其实是一个元组,多个变量接收一个元组,则元组将元素按顺序赋值给变量。
  1. isinstance(x, (int, float))x 是否为 int 或 float 类型。
    raise TypeError('错误提示文本')抛出指定提示语的类型错误。

默认参数

不同于 java ,Python 可以有默认参数,可写成 def power(x, n=2),此时调用 power(5),相当于 power(5, 2)

默认参数为可变类型的误区

有一函数 def add_end(L[]):多次调用 add_end()(不传参数,使用默认参数),则会发现这个默认参数被存下来了。

def add_end(L=[]):
    L.append('END')
return L
>>> add_end()
['END']

>>> add_end()
['END', 'END']

>>> add_end()
['END', 'END', 'END']
  • def 中,默认参数被定义了,只计算一次,拥有了一个内存地址。直接调用默认参数的话(没给参数),会对该地址进行操作。如果是列表、字典或类实例等可变对象时,将会导致该默认参数发生改变。

所以应该尽量使默认参数为不可变参数。

def add_end(L=None):
    if L is None:
        L = []
    L.append('END')
return L
  • 这里,def 中的参数是固定不变的。在函数里每次都新建了一个列表,多次调用函数使用默认参数,都会独自生成。

位置参数

函数的不加任何东西的参数默认是位置参数(必需参数),不可缺少。

函数内可以再定义函数,并且这个内部函数可以访问外部函数的参数和局部变量。

  • 位置参数在定义里必须是在开头位置的。

  • (此点学习关键字参数后可懂)多种类型参数调用函数时,位置参数必须要也在开头对应位置。除非也将位置参数,使用其关键字传入。

    比如函数 def test(a, b=100, c=100)

    test(b=2, 1) 是错误的。而 test(b=2, a=1) 是可以的。

    一般的常用方式是 test(1, 2),即位置参数一般不用关键字。而关键字参数在有多个关键字可选、要区分的话,常使用关键字传入:test(1,b=2, c=3)

可变参数

定义可变参数的函数(java 里的 ...):

def calc(*numbers)
  • 可变参数 numbers 在函数里被合并为一个元组 numbers,在外面调用函数直接传进来多个值即可。
  • 调用函数时,也可以使用:calc(*tuple1),直接将一个元组/列表作为参数(类似于解构)。
def computed(x, y, *z):
    print("可变参数:", z)
    print("两个位置参数:", x, y)


x = [1, 1, 2, 2]
computed(*x)
可变参数: (2, 2)
两个位置参数: 1 1

关键字参数

关键字参数 **kw 相当于可变参数 *args 的变种,也是一种可选的,但是它是键值对形式。

主要是可以让我们在使用函数的时候,不需要顾及参数的位置,直接将对应关键字传入即可。

注意到关键字参数与默认参数实际上是一样的。

def person(name, age, **kw):
  1. kw字典,键值对;nameage 为位置参数。
  2. nameage 位置参数是必要的,而关键字参数是次要的,扩展的。
  3. 调用:person('Bob', 18, city='Xiamen', job='ceo')必须传入参数名,否则会被识别为位置参数,出现错误。
  4. 同样,调用函数时使用 person('Bob', 18, **extra),将一个名为 extra 的字典做为参数传入。
  • 值得注意的是,这里的 **extra 只是 extra 的一个浅拷贝,函数内的对不可变元素的操作不会影响外部的 extra,但操作可变元素有影响。
  1. 位置参数可以使用关键字参数传入。此时不需要考虑他们的顺序问题。

命名关键字参数/仅限关键字参数:限制关键字参数的名字

def person(name, age, *, city='Beijing', job):  # 在星号后面写上关键字参数应有的键名

这里除必须参数外,还限制必须【要有且仅有】名为 cityjob 的参数传进来。

  • 如果有可变参数,可变参数后面的关键字参数可以不再用 * 分隔了,后面默认是命名关键字参数def person(name, age, *args, city, job)
  • 如果关键字参数有默认值,则可以不用必须传入
    • 比如这样可以调用上面小标题下的函数:person('Jack', 24, job='Engineer')

强制位置参数/仅限位置参数

在上面的参数中的,调用时:

  • f(10) 使用的是位置参数,没有,是没有带名字的参数
  • f(a=10) 使用的是关键字参数/命名关键字参数,带有名字

Python 3.8 新增了一种参数 /,使得前面的参数调用必须使用位置参数:

def f(a, b, /, c, d, *, e, f)
  print(a, b, c, d, e, f)

以下使用方法是正确的:

f(10, 20, 30, d=40, e=50, f=60)

以下使用方法会发生错误:

f(10, b=20, c=30, d=40, e=50, f=60)  # b不能使用关键字参数的形式
f(10, 20, 30, 40, 50, f=60)  # e必须使用关键字参数的形式

仅限位置参数应放在 / (正斜杠)前。/ 用于在逻辑上分割仅限位置形参与其它形参。

仅限关键字参数放在 * 之后。

参数组合

有多种参数的话,按照逻辑以及要求,必须按顺序来:必选参数(位置参数)、默认参数、可变参数、命名关键字参数和关键字参数。

def f(a, b, c=0, *, d, **kw):
#     必 必  默    命名  关键
# f函数要有a,b,可选c参数,还必须要有d=value
# 因为有**kw,所以还可有其他带名字的键值对传入
# 这里没有演示可变参数:def f(a, b, c=0, *args, d, **kw)

对于任意函数,都可以通过类似 func(*args, **kw) 的形式调用它,无论它的参数是如何定义的

  • *args 包括必选参数、可变参数。
  • **kw 包括默认参数、关键字参数、命名关键字参数。

递归函数

解决递归调用栈溢出的方法:尾递归
大多数编程语言没有针对尾递归做优化,Python 解释器也没有做优化,所以,即使把阶乘的 fact(n) 自定义函数改成尾递归方式,也会导致栈溢出。

匿名函数

lambda 表达式,它是一个表达式,只包含一个语句,而不是一个代码块。仅能在 lambda 表达式中封装有限的逻辑进去。

lambda [arg1[, arg2,.....argn]]:expression
# 冒号前参数,冒号后表达式

示例:

sum = lambda arg1, arg2: arg1 + arg2
# 调用sum函数
print("相加后的值为: ", sum(10, 20))
print("相加后的值为: ", sum(20, 20))
posted @ 2020-12-04 21:31  二次蓝  阅读(182)  评论(0编辑  收藏  举报