VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > temp > python入门教程 >
  • Elements-of-Python_04_Function

(内容包括函数、递归、Lambda、作用域等)

1. 函数

1.1 函数概述

函数是对程序逻辑进行结构化和过程化的一种编程方法,用于封装一个特定的功能,表示一个功能或者行为。函数是可以重复执行的语句块,是为了满足高重用和低冗余的最基本的程序结构,一次编写可以多次调用。【高重用、低冗余】
可以简单将函数分为内置函数和自定义函数。内置函数是python或已经导入模块中已经写好了的功能,自定义函数是将一段有规律、可重复使用的代码定义出的一个功能,是程序中一个可管理的部件。【流程分解】

1.2 常用内置函数

python中集成了许多方便的功能,以函数的形式供给使用。官方文档

1.3 自定义函数

自定义函数,也就是自己创建一个函数,带有某些用途,可以使用的一个代码块。自定义函数使用起来和内置函数一样:通过表达式进行调用,输入一些参数,得到一个结果。
定义函数遵循以下规则:

  1. 函数有0个输入、有1个或多个输出。
  2. 使用def关键字定义函数;用return或yield进行返回,无返回默认return None;函数体中实现功能。
  3. 具体形式是: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 VS 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顺序在不同作用域查找该名字。
顺序:locals


相关教程