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

参数收集

有时候我们需要参数的数量是任意的,比如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)

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

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

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


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

python教程(三)·函数进阶(上)的更多相关文章

  1. 简明python教程三-----函数

    函数通过def关键字定义.def关键字后跟一个函数的表标识符名称,然后跟一对圆括号. 圆括号之中可以包括一些变量名,该行以冒号结尾.接下来是一块语句,它们是函数体. def sayHello(): p ...

  2. 【python 3】 函数 进阶

    函数进阶 1.函数命名空间和作用域 命名空间一共分为三种: 全局命名空间 局部命名空间 内置命名空间 *内置命名空间中存放了python解释器为我们提供的名字:input , print , str ...

  3. python语法基础-函数-进阶-长期维护

    ###############    函数的命名空间和作用域    ############## """ # 函数进阶 命名空间和作用域 命名空间 全局命名空间——我们自 ...

  4. Python基础三. 函数、lambda、filter、map、reduce

    一.概述 函数, 就是用一些语句组织起来实现一组特定的功能, 用来重复调用. 函数的作用及意义:最大化的重用代码和最小化的代码冗余以及对流程的分解. Python中有哪些函数: 内建的函数 第三方模块 ...

  5. python学习总结(函数进阶)

    -------------------程序运行原理------------------- 1.模块的内建__name__属性,主模块其值为__main__,导入模块其值为模块名     1.创建时间, ...

  6. 周末班:Python基础之函数进阶

    迭代器和生成器 迭代和可迭代 什么是迭代(iteration)? 如果给定一个list或tuple,我们要想访问其中的某个元素,我们可以通过下标来,如果我们想要访问所有的元素,那我们可以用for循环来 ...

  7. Python学习之函数进阶

    函数的命名空间 著名的python之禅 Beautiful is better than ugly. Explicit is better than implicit. Simple is bette ...

  8. Python全栈开发之路 【第五篇】:Python基础之函数进阶(装饰器、生成器&迭代器)

    本节内容 一.名称空间 又名name space,就是存放名字的地方.举例说明,若变量x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的地方. 名称空间共3种,分别如下 ...

  9. python之路——函数进阶

    阅读目录   楔子 命名空间和作用域 函数嵌套及作用域链 函数名的本质 闭包 本章小结 楔子 假如有一个函数,实现返回两个数中的较大值: def my_max(x,y): m = x if x> ...

  10. python基础之函数进阶

    假如有一个函数,实现返回两个数中的较大值: def my_max(x,y): m = x if x>y else y return mbigger = my_max(10,20)print(bi ...

随机推荐

  1. 数组list操作,切片

    a=range(10) a[11:0:-1] #倒序输出 a[0:9:2] #输出2,4,6,8 a[-3:] #输出7,8,9 a.append(11) #追加一个元素 a.count(11) #统 ...

  2. codeforces 812E Sagheer and Apple Tree(思维、nim博弈)

    codeforces 812E Sagheer and Apple Tree 题意 一棵带点权有根树,保证所有叶子节点到根的距离同奇偶. 每次可以选择一个点,把它的点权删除x,它的某个儿子的点权增加x ...

  3. PyCharm最新2018激活码,最新方法

    内容:通过修改hosts文件,让pycharm不能够联网验证激活码的方式.我在kali和win10都成功了 1.修改hosts文件 Windows文件位置:C:\Windows\System32\dr ...

  4. angularJs中的模块化操作

    一.全局的写法 有可能会跟其他程序有冲突 <!DOCTYPE HTML> <html ng-app="myApp"> <head> <me ...

  5. 【OpenCV】【MFC】图片、视频、摄像头输入响应【详细图解】

    记住新建项目后,要配置OpenCV环境!参考链接http://blog.csdn.net/zy122121cs/article/details/49180541 做工程搭建框架什么的,基本的要熟练啊. ...

  6. Mongoose 利用实现HTTP服务

    嘛.... 注意:这里是使用mongoose实现HTTP服务,非数据库使用. 最近由于需要使用HTTP服务端,原先是使用的Qt框架实现的HTTP服务端,然后发现有些缺陷导致我不得不放弃这个框架,也不是 ...

  7. PostgreSQL 常用的命令

    连接数据库: psql -h ip -U usrname查看所有库: \l查看所有表: \dt查看某个表的结构: \d 表名查看数据库中所有的表: select * from pg_tables;查看 ...

  8. CF219D Choosing Capital for Treeland

    嘟嘟嘟 树形dp. 首先一个很常规的想法就是如果u到v有一条边,那么建立cost(u, v) = 0, cost(v, u) = 1的两条边. 可以两遍dfs. 先任选一个点作为根节点,第一遍从下往上 ...

  9. Spring(七)之基于注解配置

    基于注解的配置 从 Spring 2.5 开始就可以使用注解来配置依赖注入.而不是采用 XML 来描述一个 bean 连线,你可以使用相关类,方法或字段声明的注解,将 bean 配置移动到组件类本身. ...

  10. [转]VC++获取文件大小集锦

    方法一: WIN32_FIND_DATA fileInfo; HANDLE hFind; DWORD fileSize; const char *fileName = 文件的路径及名字; hFind ...