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 --& ... 
随机推荐
- PHP代码审计入门(敏感函数回溯参数过程)
			最近开始啃<代码审计企业级web代码安全架构>这本书,这一章内容看了2天很多内容都理解最主要的是对PHP不熟练所以现在理解了大概 然后进行实地环境搭建最主要的是源码百度真不好找 最后找到一 ... 
- phpstudy搭建网站只能访问首页,其他路由访问404
			今天博主遇到了一个很奇葩的问题,电脑下载了一个phpstudy搭建网站,框架用的是tp,但是除了输入域名能访问,其他页面都访问不了 经过博主的疯狂问大佬,以及百度,终于解决了这个问题 这次出现问题的原 ... 
- php 数据转储Excel文件
			1.下载PHPExcel文件 下载地址:https://www.php.cn/xiazai/leiku/1491 2.在php写入以下代码,执行即可 $arr = Db::name('user')-& ... 
- 上周我面了个三年 Javaer,这几个问题都没答出来
			身为 Java Web 开发我发现很多人一些 Web 基础问题都答不上来. 上周我面试了一个三年经验的小伙子,一开始我问他 HTTP/1.HTTP/2相关的他到是能答点东西出来. 后来我问他:你知道 ... 
- Guitar Pro吉他指弹入门——双手泛音
			曾经有一段时间在琴行里经常遇到有人来试琴,很多人试弹得曲子就是郑成河的<Flaming>,直译过来就是热情的意思.这首曲子里面有很多泛音存在,吉他泛音类似于钟鸣或者摇铃的声音,是一种令人耳 ... 
- TCP接收窗口为什么变大了?
			今天用wireshark抓取TCP连接时的报文发现客户端的Win变大了,这里是使用了Window Scale来扩张TCP接收窗口,使得接收窗口可以大于65535字节. 首先1号包是TCP第一次握手连接 ... 
- JavaSE 学习笔记03丨继承、接口、多态、内部类
			Chapter. 5 继承 继承作为面向对象的三大特征之一,它是多态的前提.它主要解决的问题是共性抽取. Java中的继承,是单继承.多级继承的. 已存在的类,被称为超类.基类.父类(parent c ... 
- 区块链V1版本实现之三
			部分程序代码(区块链的定义及遍历打印): 1 //创建区块链,使用Block数组模拟 2 type BlockChain struct { 3 Blocks []*Block 4 } 5 6 //实现 ... 
- 我劝!这位年轻人不讲MVCC,耗子尾汁!
			目录 一.事物的隔离级别与MVCC? 二.Repeatable Read是如何实现的 本文是MySQL专题第15篇,全文近100篇(公众号首发) 三.Read Commited是如何实现的: 本文是M ... 
- 速刷git<一> 常用命令记录
			git config --list 列出配置 --local 对某个仓库有效 --global 对当前用户的所有仓库有效 --system 对系统所有登录用户有效git reset --ha ... 
