函数,作用域,递归

函数的5种参数类型

POSITIONAL_OR_KEYWORD(位置参数或关键字参数)

VAR_POSITIONAL(可变参数)

KEYWORD_ONLY(关键字参数)

VAR_KEYWORD(可变关键字参数)

POSITIONAL_ONLY(位置参数)

POSITIONAL_OR_KEYWORD如其名所见,既可以用位置传参,也可以用关键字传参

def foo(name):
    print(name)
foo('a')  # a
foo(name='a')  # a

VAR_POSITIONAL是可变参数,通过*来声明,它会把接收到的值存入一个元组

def foo(*args):
    print(args)
foo(1, 2, 3)  # (1,2,3)

KEYWORD_ONLY只能通过关键字传参,这种参数会在VAR_POSITIONAL参数类型的后面,只能通过指定关键字来传参,不可以用位置传参

def f(name, *, val):
    print(name, val)
f('a', val=1)  # a 1

VAR_KEYWORD是可变关键字参数,通过前缀**来声明,这种参数类型可以接收0个或多个参数,并存入一个字典

def foo(**kw):
    for key, value in kw.items():
        print('%s=%s' % (key, value), end=' ')
foo(a=1, b=2, c=3)  # a=1 b=2 c=3

高版本的Python无法创建一个POSITIONAL_ONLY类型的参数,但是有些使用C语言实现且不接收关键字参数的函数(如divmod)支持

默认参数

  1. VAR系列的两个参数(可变参数、可变的关键词参数)不允许设置默认参数,而另外两个参数(位置和关键词参数、关键词参数)可以设置默认参数。 因为VAR_POSITIONAL的默认参数是tuple()空元祖,而VAR_KEYWORD的默认参数是dict()空字典。
  2. 默认参数的位置POSITIONAL_OR_KEYWORD类型的默认参数一定要放在后面,否则会报错。
  3. KEYWORD_ONLY虽然没有强制要求,因为都是用关键字传参,谁先谁后无所谓,但最好还是放在后面。
  4. 默认参数最好不要设置为可变类型(如dict、list、set)。 如果把默认参数设置为可变类型,并在函数中改变了该参数的值,下次再调用它就不再是默认值了。

return

return作用:

  1. 结束函数
  2. 返回对象

不写return语句会默认返回None

高阶函数

  1. python一切皆对象,函数也是对象。
  2. 函数本身可以赋值给变量,即变量可以指向函数对象。
  3. 函数名其实就是指向函数对象的变量。
  4. 因为变量可以指向函数对象,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数称之为高阶函数。
  5. 函数对象也可以作为函数的返回值。
  6. 内置的高阶函数有filter,map,reduce。

匿名函数

python 使用 lambda 来创建匿名函数。

  1. lambda只是一个表达式,函数体比def简单很多。
  2. lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
  3. lambda函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。
  4. 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。

语法

lambda [arg1 [,arg2,.....argn]]:expression

变量作用域

L:local 函数内部作用域 

E:enclosing 外部嵌套函数的作用域

G:global 全局作用域 

B:build-in 内置作用域

要修改global作用域中变量的值,要用global关键字对变量进行声明

num = 1
def foo():
    global num  # 需要使用 global 关键字声明
    print(num)  # 1
    num = 123
    print(num)  # 123
foo()
print(num)  # 123

内部函数要修改外部函数的变量的值,用nonlocal关键字声明变量

def outer():
    num = 10
    def inner():
        nonlocal num  # nonlocal关键字声明
        num = 100
        print(num)  # 100
    inner()
    print(num)  # 100
outer()

递归

递归条件:

  1. 需要调用自身函数
  2. 要有递归出口,也就是结束条件

递归调用实际上是函数自己在调用自己,而函数的调用开销是很大的,系统要为每次函数调用分配存储空间,并将调用点压栈予以记录。而在函数调用结束后,还要释放空间,弹栈恢复断点。所以说,函数调用不仅浪费空间,还浪费时间。同一个问题,如果递归解决方案的复杂度不明显优于其它解决方案的话,那么使用递归是不划算的。方式有些问题使用迭代算法是很难甚至无法解决的(比如汉诺塔问题)。这时递归的作用就显示出来了。

猜你喜欢

转载自blog.csdn.net/xingjingb/article/details/81335114
今日推荐