Elements-of-Python_04_Function
(内容包括函数、递归、Lambda、作用域等)
1. 函数
1.1 函数概述
函数是对程序逻辑进行结构化和过程化的一种编程方法,用于封装一个特定的功能,表示一个功能或者行为。函数是可以重复执行的语句块,是为了满足高重用和低冗余的最基本的程序结构,一次编写可以多次调用。【高重用、低冗余】
可以简单将函数分为内置函数和自定义函数。内置函数是python或已经导入模块中已经写好了的功能,自定义函数是将一段有规律、可重复使用的代码定义出的一个功能,是程序中一个可管理的部件。【流程分解】
1.2 常用内置函数
python中集成了许多方便的功能,以函数的形式供给使用。官方文档
1.3 自定义函数
自定义函数,也就是自己创建一个函数,带有某些用途,可以使用的一个代码块。自定义函数使用起来和内置函数一样:通过表达式进行调用,输入一些参数,得到一个结果。
定义函数遵循以下规则:
- 函数有0个输入、有1个或多个输出。
- 使用def关键字定义函数;用return或yield进行返回,无返回默认return None;函数体中实现功能。
- 具体形式是:def 加自定义函数名定义函数的名字,名字自己取,做到望文生义;之后加小括号,括号中先加普通参数,再加默认参数,最后加可变参数;在参数列表后加冒号,下一行缩进的就是函数主体,即每次调用时运行的部分;函数主体中需要有一个或多个返回值(如果没有默认返回None)。
1.3.1 自定义函数的定义
自定义函数利用关键字def(即简写的define)来进行定义,def后要写一个函数名,函数名要能做到望文生义,符合取名规则(字母开头,只含字母下划线和数字,非关键字),函数名后是你这个函数所需要的参数(普通参数、默认参数、变参)。接着就是冒号和下面缩进书写的函数体了,函数体中需要带有返回值(没有返回值默认return None),调用时一旦return,意味着调用结束。再说说返回值,返回值可以是任意类型,但只能返回一个对象。
#输入参数日月年,返回和今天差几天
import time
def isLeapYear(y):
if y%4==0 and y%100!=0 or y%400==0 :
return True
else :
return False
def daysGone(m,flag):
listGone1 = (365,0,31,59,90,120,151,181,212,243,273,304,334) #平年
listGone2 = (366,0,31,60,91,121,152,182,213,244,274,305,335) #闰年
if flag :
return listGone2[m]
else :
return listGone2[m]
def date_apart(d1,m1,y1):
lastest = [int(time.strftime("%d")),int(time.strftime("%m")),int(time.strftime("%Y"))]
daysofMonth = {1:31,2:28,3:31,4:30,5:31,6:30,7:31,8:31,9:30,10:31,11:30,12:31}
leap = total = 0
for i in range(y1+1,lastest[2],1):
total += 365
if i%4==0 and i%100!=0 or i%400==0 :
leap += 1
total += leap
total += daysGone(lastest[1],isLeapYear(lastest[2])) + lastest[0]
total += 365 + isLeapYear(y1) - daysGone(m1,isLeapYear(y1)) - d1
if y1==lastest[2] : total -= 365
return total
print(date_apart(17,8,1926))
从上面的函数里,可以看出:
①函数可以作为另一个函数的参数
②返回值的类型可以多样,但运行到return就会停下
③函数体中可以调用其他函数
1.3.2 关于函数参数
函数的参数可以分为实参(普通参数、默认参数)和变参(位置参数、命名参数)。定义时:实参必须在变参的前面,建议默认参数放在普通参数后面。得到的参数可以出现或不出现在函数体中(就是说,参数你要来了,用不用随你自己)。调用时:输入参数的时候,可以根据顺序一个一个输,也可以以【参数名=赋的值】的形式,不按顺序输。默认参数不赋值就按默认值输入。变参就是把不定个数的参数传入函数。
对于可变参数,可以用任意名字前加一个和两个*号,写在参数列表的最后,先单*后双*的顺序,常用【*args,**kargs】和【*vars,**kvars】这两组。*符号表示需要接收的多出来的list和tuple,用**符号表示需要接收的map和dictionary。换而言之,①参数列表中的形如a=b形式(键值对)的命名参数,就传入**kargs;②参数列表中形如a,b,c这种形式(元组)的位置参数,就传入*args。
如果实参不够,会向位置参数(单个*号的变参)借参数;等位置参数借没了,再问命名参数(两个*号的变参)借参数(键值对),但是键必须等于实参的名字,才会把值传进实参。另一方面,如果实参的位置多了参数,键值对就会填进命名参数,成为字典,其他的会按顺序填进位置参数,成为元组。 另外,在参数列表中的变参,位置参数必须在命名参数前被赋值。
在调用函数时,即使定义的都是实参,也可以用*和**号。*号的作用是展开多个元素的类型,区别:*号只显示键keys(),**号显示键值对items()。
关于默认参数:
默认参数一旦生成,用户不去手动改变,默认参数就不会变。比如def add(a,b,c=[]), 那一旦第一次调用时对c传入非空列表[1],则c就会被赋值为[1],之后再调用的时候就默认是c=[1]而不是[]。 同样的,如果默认参数传入随机数,第一次会随机,后面就一直取第一次的随机值。因此,参数中需要随机值,一定要用实参去传入,不能用默认参数。
def tt(a,b,z,*c,**d):
print(a)
print(b)
print(z)
print(c)
print(d)
tt(*range(1,15,3)) #实参不够,位置参数加入实参
print("---------------------------")
tt(1,*range(2,3),**{"z":20,"bbb":23}) #实参和位置参数不够,命名参数加入
print("---------------------------")
tt(1,3,5,7,9,11,13,15,f=10,x=16,k="ppp") #实参位置多了,放进变参
1.3.3 函数体
函数定义中,缩进的部分就是函数体,函数体是主要负责实现函数功能并返回值的地方。函数体以冒号起始,且缩进。第一行如果用文档字符串(三个冒号),就会被认作是在写函数的说明文档。在函数体中可以写几乎所有语句,甚至再定义一个函数。如果只是写一个函数名,函数体还没有决定,可以用pass关键字先做占位。 函数体中需含有返回值,用return或yield关键字返回。如果没有返回值,或只写了return没跟变量,默认返回空值None。函数体中(包括返回值)可以调用其他函数或自己。
1.3.4 返回值
为什么有了print语句直接输出,还要return呢?这是因为,函数只帮我们解决了一个问题,而不是这整件事。举上面的例子,我想知道是不是闰年,输出是不是没有用,但是返回一个True,却可以作为后续函数的实参输入。
用return和yield两个关键词可以将需要的变量进行返回。返回值在调用函数的时候,作为函数运行后的输出。
同样可以返回值,return和yield两个关键词的区别是什么呢?return一次全部输出,输出后结束;yield配合next或send一起使用,每次输出一步,下次调用再输出下一步。简单的说,return从一而终,yield阻塞在yield这一句,用next调用从这句yield开始,到yield再阻塞。
从上图的结果可以看出,return直接在第一次循环中输出了第一次循环值,就结束了;而next+yield则第一次运行到yield就不再运行,被下一个next激活后,从上一次yield开始运行,循环后到下一个yield又不运行了,这就是yield。
1.4 函数的调用
在自定义函数定义完以后,可以进行调用。只有调用的时候,才会检查自定义函数写的是不是正确。调用的时候,你将自定义函数需要的参数写到函数名后面的参数列表中,可以用位置参数和命名参数的方法,需要注意个数,位置参数需要注意位置。另外,对于帮助文档,用help(NAME)即可(不加参数名)。 函数的结果就是函数运行后的返回值。
1.5 递归 Recursion
在函数定义中,也可以在函数体中调用其他函数。简单地说,如果被调用的是自己或者几个函数相互调用,就叫做递归。严格地说, 适合用递归的是:【能把问题分解成为规模更小的、具有与原问题有着相同解法的问题。】 递归成功有一些先决条件:①随着递归深度的加深(次数变多),问题应该越来越简单;②递归中应该有一个判断(递归出口),在问题最简单的时候返回不再需要调用的返回值;③递归的次数不是无限制的,不做设置递归1000次左右就会栈溢出。【在一定次数中,深度增加规模减小,最后会结束】
递归的特点:写起来简单,容易让人理解,没有复杂嵌套,容易栈溢出,多次调用费时效率低。
数据、数据结构、问题描述是递归形式的,应该想起递归。
递归的两种思路:①执行下一次用到上一次的结果(递推);终止时需要上一层的条件(回溯)。
1.6 Lambda表达式
Lambda表达式是用来简化编程者工作量的一种匿名函数。特点是:允许你快速定义一个单行的最小函数。它的唯一语法形式是:
在式中,冒号前的变量就是函数中的参数列表,冒号后就是函数中的返回值的表达式。Lambda表达式看起来和用起来简单,更pythonic,但内部逻辑和定义一个函数是一样的,且不支持多分支语言和异常处理程序。用法上,它的输入就是参数列表,输出就是返回值的结果。它可以配合filter、sorted、map、reduce等函数一同使用。
1.7 帮助文档
在使用一个函数的时候,就算起名已经望文生义了,但是你还是需要一些更多的支持,比如说帮助文档或说明书。在自定义函数中,只要利用文档字符串,就可以方便的进行帮助文档的书写。
具体来说,想写一个函数的帮助文档,你需要在定义函数后,函数体的第一行利用字符串(一行用普通引号,多行用三个引号)进行输入,整个文档字符串都会被视作帮助文档。调用时,用help(NAME)函数进行查看,只需要写函数名,不要写参数列表。
1.8 作用域
先说说赋值,赋值是将你取的变量名和这个对象建立连接。也就是说,赋值是名字指向新的对象,而不是通过名字直接改变对象。
如果在自己的函数中和脚本主函数中的变量重名了,怎么办呢? 如果仅仅是引用外部变量,那么按LEGB顺序在不同作用域查找该名字。
顺序:localsenclosing functionglobals__builtins__,(即:内部嵌套函数包含内部嵌套函数的函数自身全局作用域内置作用域),作用域的优先级从高到低,作用域的范围由小到大。 其中:
- locals:函数内部名字空间,包括局部变量和形参
- enclosing function: 外部嵌套函数的名字空间
- globals: 函数定义所在模块的名字空间
- __builtins__: 内置模块的名字空间
内置作用域是预先定义好的,在__builtins__模块中。这些名称主要是一些关键字,例如open、range、quit等;全局作用域是文件/模块级别的,每个.py文件中处于顶层的变量都是全局作用域范围内的变量;本地作用域是函数内部属于本函数的作用范围,因为函数可以嵌套函数,嵌套的内层函数有自身的内层范围;嵌套函数的本地作用域是属于内层函数的范围,不属于外层。
当一条命令需要用到某个对象时,他会按照LEGB顺序,先找本层函数中有没有。
从上面图中可以看出,在1,4两次print中,打印的是全局变量x,在调用了k以后,打印的是k中的函数内部名字空间,而m无法被脚本读取。 解释一下,参数列表和函数中定义的变量叫做局部变量,只能在这个局部调用,而且不能改变更大一级的变量的值。更大一级也只能调用自己同级定义的函数,不能调用在函数中定义的函数。
既然参数列表中传进参数的改变不能使全局变量改变,那这样是不是说,函数只能通过返回值改变全局变量呢? 并不是,引入global关键字,就可以从函数中改变全局变量的值。如图:
1.9 函数设计理念
函数应力求独立于外部,输入尽量用参数,输出用return ; 只有在真正需要的时候,才去用全局变量;函数的目标应该单一、统一; 每个函数应该相对地小;尽量不去改变其他模块文件中的变量。
1.10 函数类型检查
Python3.5以后,加入了函数类型检查功能。在定义函数的参数列表所列举的参数后加入冒号和类型规定参数列表中形参的输入类型,在参数列表后用->符号规定返回值类型。
def sum(a:int,b:[int])->float:
for i in b:
c += i
return a*1.0+c
在上面的代码定义中,要求了参数a的类型必须是int型, 参数b的类型必须是list类型,且b中的每个元素必须是整数,返回值的类型必须是浮点型小数。 如果调用函数时,输入的实参和形参类型不相同,在IDE中就会进行警告,但是不影响函数的正常运行。
1.11方法命名
在Pyhton中,不仅可以对属性进行命名,如a=b
对于方法也可以进行命名,如c=math.sqrt
,这样,c就和math.sqrt等效,print(c(4))
会输出2.0。
Elements-of-Python_04_Function的更多相关文章
- js Form.elements[i]的使用实例
function pdf(){ //一个html里面可能存在多个form,所以document.form[0]指的是第一个form,document.form[1]返回就是第二个form,如果没 ...
- View and Data API Tips: Hide elements in viewer completely
By Daniel Du With View and Data API, you can hide some elements in viewer by calling "viewer.hi ...
- [LeetCode] Minimum Moves to Equal Array Elements II 最少移动次数使数组元素相等之二
Given a non-empty integer array, find the minimum number of moves required to make all array element ...
- [LeetCode] Minimum Moves to Equal Array Elements 最少移动次数使数组元素相等
Given a non-empty integer array of size n, find the minimum number of moves required to make all arr ...
- [LeetCode] Top K Frequent Elements 前K个高频元素
Given a non-empty array of integers, return the k most frequent elements. For example,Given [1,1,1,2 ...
- [LeetCode] Remove Linked List Elements 移除链表元素
Remove all elements from a linked list of integers that have value val. Example Given: 1 --> 2 -- ...
- Chrome 开发工具之Elements
友情提示:全文图片高能,如使用手机阅读,请确保在wifi情况下或者流量充足.图片有点渣,也算辛苦做出来的,请别嫌弃- Elements面板主要展示当前页面的组织结构,在如今的应用程序中,HTML页面初 ...
- T-SQL Recipes之Separating elements
Separating elements Separating elements is a classic T-SQL challenge. It involves a table called Arr ...
- POJ2167Irrelevant Elements[唯一分解定理 组合数 杨辉三角]
Irrelevant Elements Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 2407 Accepted: 59 ...
- [LeetCode] Remove Linked List Elements
Remove all elements from a linked list of integers that have value val. ExampleGiven: 1 --> 2 --& ...
随机推荐
- 微信公众号获取openid(php实例)
微信公众号获取openid 公众号获取openid的方法跟小程序获取openid其实是一样的,只是code获取的方式不一样 小程序获取code: 用户授权登录时调用wx.login即可获取到code ...
- vue的html2canvas将dom转化为图片时踩得坑
一.html2canvas中图片涉及跨域图片 应用场景:做个投票活动,将参赛者的信息转化成图片截图分享.用户上传图片上传到腾讯云cos桶中,html2canvas只能转换本地资源的图片,涉及跨域的图片 ...
- 面试官:小伙子,你给我讲一下java类加载机制和内存模型吧
类加载机制 虚拟机把描述类的数据从 Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型,这就是虚拟机的类加载机制. 类的生命周期 加载(Loadi ...
- Boom 3D快捷方式,让3D音效应用更便捷
快捷方式是一种快速启动程序.打开程序功能的方法,巧妙地利用快捷键,可以大大加快我们使用Boom 3D的速度,可以让我们更好地享受3D音效. 接下来,就让小编演示一下怎么在不打开Boom 3D的情况下使 ...
- 关于GoldWave为Vegas制作音频交叉淡化特效的教程分享
在Vegas里对音频交叉淡化的处理,是通过将两段音频交叠.调整交叠部分的音量.选取交叉淡化类型这三步来实现的,许多步骤是在音频轨道拖动音量线来实现的,操作上不够灵敏精细.其实,单就音频的交叉淡化处理, ...
- git学习与应用
git是什么 Git是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目:同类的有svn,如果知道svn是干嘛的(上篇),那么git是啥就不多解释了. Git 与常用的版本控制工具 C ...
- Linux(CentOS 7下httpd的安装)
Linux(CentOS 7下httpd的安装) 自己是个linux小白.最近几天在学linux,看到视频教程中安装源码包httpd所以自己想试一试,安装过程中有很多的错误,在网上找了很久也没找到,要 ...
- C++基础知识篇:C++ 变量作用域
作用域是程序的一个区域,一般来说有三个地方可以定义变量: 在函数或一个代码块内部声明的变量,称为局部变量. 在函数参数的定义中声明的变量,称为形式参数. 在所有函数外部声明的变量,称为全局变量. 我们 ...
- 【mq读书笔记】客户端处理消息(回调提交到异步业务线程池,pullRequest重新入队)
看一下客户端收到消息后的处理: MQClientAPIImpl#processPullResponse private PullResult processPullResponse( final Re ...
- (1)Consul在linux环境的集群部署
1.Consul概念 1.1什么是Consul? Consul是一种服务网格解决方案,是HashiCorp公司推出的开源组件,由Go语言开发,部署起来很容易,只需要极少的可执行程序和配置.同时Cons ...