zoukankan      html  css  js  c++  java
  • python教程(三)·函数进阶(上)

    在介绍了函数定义的方法后,再来介绍一些进阶知识

    参数收集

    有时候我们需要参数的数量是任意的,比如print函数的参数的数量是任意的,print函数的内部实现我们不探究,但是单单是参数数量可变这一方面实现起来不难,我们只需像下面这样定义函数:

    >>> def print_params(*params):
    ...     print(params)
    ... 
    >>> print_params()
    ()
    >>> print_params(1)
    (1,)
    >>> print_params(1,2)
    (1, 2)
    >>> print_params(1,2,3)
    (1, 2, 3)
    >>> print_params(1,2,3,4)
    (1, 2, 3, 4)
    >>> 
    

    可以看到,我们在函数的定义时,只定义了一个参数,但参数前面带有一个星号*,并且调用函数时,输出的结果显示,这个参数是一个元组,这个元组有我们调用时的所有参数。

    实际上,参数前的星号的作用是,将剩下的值收集起来做为元组一个整体,给这个参数,何谓”剩下“?我们再来一段代码:

    >>> def print_params(p1, *params):
    ...     print(p1)
    ...     print(params)
    ... 
    >>> print_params(1,2)
    1
    (2,)
    >>> print_params(1,2,3,4)
    1
    (2, 3, 4)
    >>> 
    

    可见,所谓“剩下”,就是除了开头的p1位置参数外,剩下的所有位置参数。

    没错!是剩下的位置参数,收集剩下的关键字参数需要两个星号:**

    >>> def print_params(p1, *params, **kwparams):
    ...     print(p1)
    ...     print(params)
    ...     print(kwparams)
    ... 
    >>> print_params('hello', 'feather','Lee', x=1,y=2,z=3)
    hello
    ('feather', 'Lee')
    {'x': 1, 'y': 2, 'z': 3}
    >>> 
    

    这样看来很显而易见了,收集关键字参数的是元组,而收集关键字参数的是字典

    注意咯,在一个函数中只能定义一个*前缀参数和一个**前缀参数,为什么?可以想想python解释器怎么识别

    参数收集的逆过程

    使用***在函数的定义时用于收集参数,而在调用时使用就是用于分配参数了

    在元组前加上一个星号*,就会对元组(列表也可以)进行展开

    >>> def add(x, y):
    ...     return x+y
    ... 
    >>> params = (1,2)
    >>> add(*params)
    3
    >>> 
    

    上面的add(*params)中的*params会被展开成add(1,2),这不正是把收集起来的位置参数再分配出来吗?

    正如你所想,字典{'x':1,'y':2,'z':3},可以使用两个星号即**,展开成关键字参数调用的方式x=1,y=2,z=3,比如下面这段代码:

    >>> def printzyx(z, y, x):
    ...     print(z)
    ...     print(y)
    ...     print(x)
    ... 
    >>> keys = {'x':1, 'y':2, 'z':3}
    >>> printzyx(**keys)
    3
    2
    1
    

    上面的printzyx(**keys)相当于printzyx(x=1,y=2,z=3)

    递归

    函数里可以调用其他函数,这是必然的,然而,函数还可以调用自身,上面说到,每次调用函数时都会生成一个新的命名空间,所以函数调用自身,实际上运行了两个不同的函数,这也是为什么函数可以调用“自身”了,这种现象称为递归

    递归这个词的意思简单说就是自己引用自己,递归有一个幽默的定义:

    递归[名词]:参见递归

    像这样自己解释自己,自己引用自己的都可以称为递归,像上面那样的递归,这是一个无穷递归,永远没有停止,如果定义一个函数像下面这样:

    def func():
        func()
    

    这个函数也是个无穷递归,运行不一会,程序就会崩溃,理论上,它应该永远运行下去,然而,每次调用函数都会用掉一点内存,这点内存要在函数结束时才会回收,递归达到一定深度后,python解释器提供的内存不够了,就会抛出错误信息结束程序。

    显然,无穷递归做不了任何事情,如果想要做一些有用的事情,就要用到有穷递归,就好像循环语句中的使用break一样,在特定的条件下退出递归,当然啦,结束递归可不是用break,下面来个经典的递归函数

    计算阶乘

    n的阶乘定义为n * (n-1) * (n-2) * ... * 1,就是从n一直乘到1或者从1一直乘到n,我也不清楚它的用途,但是它的计算可以作为经典的递归例子

    我们可以用循环来计算:

    def factorial(n):
        result = n
        for i in range(1, n):
            result *= i
        return result
    

    那么递归怎么用?阶乘的定义用递归来说就是:

    • 1的阶乘是1
    • 大于1的数n的结成是n乘上n-1的阶乘

    定义中的第一点就是决定阶乘结束的条件了,理解了定义后,实现起来不难,如下:

    def factorial(n):
        if n == 1:
            return 1
        else:
            return n * factorial(n-1)
    

    这是定义的直接实现,这并不难,可就是困扰了大部分计算机入门的同学

    递归大部分情况下是可以用循环代替的,而且使用循环效率更高,但有些时候递归更加易读,尤其是懂得递归函数的定义的时候。

    尽管可以避免编写使用递归的程序,但理解递归仍是一个非常重要的基本功,希望读者重视


    可以看到这篇文章的标题中带有(上),也就是说还有下半部分,突然发现,写的文章太长了,就把这一节分成了上下两个部分,又延迟了后面的小实例的发布,是在不好意思,不过不用担心,下半部分马上就发布!

  • 相关阅读:
    百度地图中循环输出坐标点信息是重复的问题解决方法
    质问微软 WP8.1开发HTTPS 真费劲
    WebService 页面重定向错误
    Oracle 错误 maximum number of processes(150) exceeded 解决办法
    spring quartz定时任务 配置
    centos 7安装完后出现please make your choice from '1' to e
    centos单机安装Hadoop2.6
    centos 关闭防火墙
    CentOS 7 系统下安装gnome图形界面
    CentOS 7 ifconfig: command not found
  • 原文地址:https://www.cnblogs.com/featherl/p/10344337.html
Copyright © 2011-2022 走看看