九、递归函数、匿名函数、日期时间函数、随机函数、闭包、装饰器

一、递归函数

  • 定义:如果一个函数在内部,不调用其他的函数,而是调用自身的话,这个函数就是递归函数。
    程序实例如下所示:
def func(count): if count == 1: result = 1 else: result = func(count-1)*count return result number = int(input('请输入一个正整数:')) print(func(number))

  • 执行原理如下
    九、递归函数、匿名函数、日期时间函数、随机函数、闭包、装饰器
    文章图片
二、匿名函数
  • 含义:没有名称的函数,如需声明匿名函数需要,使用关键字lambda
  • 语法:lambda [arg1 [,arg2,…argn]]:expression
  • [ arg 1 [,arg2,… .ar gn]]" 表示的是函数的参数。
  • expression" 表示的是函数的表达式。
  • 注意:
    (1)Lambda函数能接收任何数量的参数但只能返回一个表达式的值
    (2)匿名函数不能直接调用print,因为lambda需要一个表达式
  • 应用场合:函数作为参数传递
(1)自己定义的函数
>>> def fun(a, b, opt): ...print("a = " % a) ...print("b = " % b) ...print("result =" % opt(a, b)) ... >>> fun(1, 2, lambda x,y:x+y) a = 1 b = 2 result = 3

(2)作为内置函数的参数
  • 语法:列表.sort(key=lambda 临时变量名:临时变量名[key])
  • 默认是升序,使用reverse=True改为降序。
stus = [ {"name": "zhangsan", "age": 18}, {"name": "lisi", "age": 19}, {"name": "wangwu", "age": 17} ]stus.sort(key=lambda dict:dict["age"], reverse=True) print(stus)stus.sort(key=lambda d:d["name"]) print(stus)# 列表嵌套 new_list = [[-100, 30, 10], [29, 31, 5], [10, 20, 6]] # 想利用列表的小列表中的第三个元素进行排序 # [[29, 31, 5], [10, 20, 6], [-100, 30, 10]] new_list.sort(key=lambda l:l[2]) print(new_list)

def 定义的函数和lambda 定义的函数的不同的地方:
  • def 定义的函数是有名称的,而 lambda 定义的函数没有函数名称,这是最明显的区 别之一。
  • lambda 定义的函数通常会返回一个对象或者一个表达式,它不会将返回结采赋给一个 变量,而 def定义的函数则可以。
  • lambda 定义的函数中只有一个表达式,函数体比 def定义的函数简单很多,而 def定义 的函数的函数体是一个语句。
  • lambda 表达式的冒号后面只能有一个表达式, def 定义的函数则可以有多个。
  • 像 if或 for 等语句不能用于 lambda 定义的函数中,而 def定义的函数则可以使用。
  • lambda 一般用来定义简单的函数,而 def可以定义复杂的函数。
  • == lambda 定义的函数不能共享给别的程序调用==,而 def 定义的函数则可以被调用 。
三、日期时间函数
3.1 时间函数 在 Python 中,通常有如下几种方式表示时间:
  • 时间戳 ;
  • 格式化的时间字符串
  • 时间元组( struct_time )
3.1.1 时间戳
??时间戳表示的是从 1970 年 1 月 1 日 00:00:00 开始按秒计算的偏移量。返回时间戳的函数主要有 time()、 clock()等
import time a = time.time() print("当前时间戳为:", a) #------- #当前时间戳为: 1546056474.8554897

3.1.2 格式化的时间字符串
import time# 格式化为 2018-12-29 12:18:18 print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))# 格式化为 Sat Dec 29 12:18:18 2018 print(time.strftime("%a %b %d %H:%M:%S %Y", time.localtime()))# 将格式字符串转换为时间戳 time_word = 'Sat Mar 28 22:24:24 2018' print(time.mktime(time.strptime(time_word, "%a %b %d %H:%M:%S %Y")))

python中时间日期格式化符号:
符号 含义
%y 两位数的年份表示(00-99)
%Y 四位数的年份表示(000-9999)
%m 月份(01-12)
%d 月内中的一天(0-31)
%H 24小时制小时数(0-23)
%I 12小时制小时数(01-12)
%M 分钟数(00=59)
%S 秒(00-59)
%a 本地简化星期名称
%A 本地完整星期名称
%b 本地简化的月份名称
%B 本地完整的月份名称
%c 本地相应的日期表示和时间表示
%j 年内的一天(001-366)
%p 本地A.M.或P.M.的等价符
%U 一年中的星期数(00-53)星期天为星期的开始
%w 星期(0-6),星期天为星期的开始
%W 一年中的星期数(00-53)星期一为星期的开始
%x 本地相应的日期表示
%X 本地相应的时间表示
%Z 当前时区的名称
%% %号本身
3.1.3 时间元组 ??返回 struct_time 的函数主要有 gmtime()、 localtime()和 strptime(), struct_time 元组共有九 个元素,我们通过一张表来列出元组中的这些元素。
字段
tm_year 2008
tm_mon 1 到 12
tm_mday 1 到 31
tm_hour 0 到 23
tm_min 0 到 59
tm_sec 0 到 61 (60或61 是闰秒)
tm_wday 0到6 (0是周一)
tm_yday 一年中的第几天,1 到 366
tm_isdst 是否为夏令时,值有:1(夏令时)、0(不是夏令时)、-1(未知),默认 -1
#!/usr/bin/python3 import timelocaltime = time.localtime(time.time()) print ("本地时间为 :", localtime)

以上实例输出结果:
本地时间为 : time.struct_time(tm_year=2016, tm_mon=4, tm_mday=7, tm_hour=10, tm_min=28, tm_sec=49, tm_wday=3, tm_yday=98, tm_isdst=0)

3.1.4 time模块的函数
??星期一是默认的每周第一天,星期天是默认的最后一天。更改设置需调用calendar.setfirstweekday()函数。模块包含了以下内置函数:
calendar.calendar(year,w=2,l=1,c=6)

返回一个多行字符串格式的year年年历,3个月一行,间隔距离为c。 每日宽度间隔为w字符。每行长度为21* W+18+2* C。l是每星期行数。
calendar.firstweekday( )

返回当前每周起始日期的设置。默认情况下,首次载入caendar模块时返回0,即星期一。
calendar.isleap(year)

是闰年返回 True,否则为 false。
calendar.leapdays(y1,y2)

返回在Y1,Y2两年之间的闰年总数。
calendar.month(year,month,w=2,l=1)

返回一个多行字符串格式的year年month月日历,两行标题,一周一行。每日宽度间隔为w字符。每行的长度为7* w+6。l是每星期的行数。
calendar.monthcalendar(year,month)

返回一个整数的单层嵌套列表。每个子列表装载代表一个星期的整数。Year年month月外的日期都设为0; 范围内的日子都由该月第几日表示,从1开始。
calendar.monthrange(year,month)

返回两个整数。第一个是该月的星期几,第二个是该月有几天。星期几是从0(星期一)到 6(星期日)。
>>> import calendar >>> calendar.monthrange(2014, 11) (5, 30)

(5, 30)解释:5 表示 2014 年 11 月份的第一天是周六,30 表示 2014 年 11 月份总共有 30 天。
calendar.prcal(year,w=2,l=1,c=6)

相当于 print calendar.calendar(year,w,l,c).
calendar.prmonth(year,month,w=2,l=1)

相当于 print calendar.calendar(year,w,l,c)。
calendar.setfirstweekday(weekday)

设置每周的起始日期码。0(星期一)到6(星期日)。
calendar.timegm(tupletime)

和time.gmtime相反:接受一个时间元组形式,返回该时刻的时间戳(1970纪元后经过的浮点秒数)。
calendar.weekday(year,month,day)

返回给定日期的日期码。0(星期一)到6(星期日)。月份为 1(一月) 到 12(12月)。
四、随机函数
random.random()

返回 0与1之间的随机浮点数 N ,范围为 0<= N < 1 .0。
random.uniform(a,b)

返回 a 与 b 之间的随机浮点数 N ,范围为[a, b]。 如果 a 的值小于 b 的值,贝IJ生成的随机浮 点数 N 的取值范围为 a <= N <= b; 如果 a 的值大于 b 的值,则生成的随机浮点数 N 的取值范 围为 b <= N <= a。
random.randint(a,b)

返回一个随机的整数 N , N 的取值范围为 a <= N <= b。需要注意的是, a 和 b 的取值必须 为整数,并且 a 的值一定要小于 b 的值。
random.randrange([start], stop[, step])

返回指定递增基数集合中的一个随机数,基数默认值为 1。其中, start 参数用于指定范围内的开 始值,其包含在范围内; end 参数用于指定范围内的结束值,其不包含在范围内; step 表示递增基数。 上述这些参数必须为整数。例如 , random.randrange (10, 100, 2)相当于从[10, 12, 14, 16, … 96, 98]序列中获取一个随机数。
random.choice(sequence)

从 sequence 中返回一个随机的元素。其中, sequence 参数可以是列表、元组或字符串。 需要注意的是,若 sequence 为空,则会引发 IndexError 异常。
random.shuffle (x[,random])

用于将列表中的元素打乱l顺序,俗称为洗牌
random.sample(sequence,k)

从指定序列中随机获取 k 个元素作为一个片段返回, sample 函数不会修改原有序列。
五、闭包 闭包需要满足如下三个条件:
  • 存在于嵌套关系的函数中。
  • 嵌套的内部函数引用了外部函数的变量。
  • 嵌套的外部函数会将内部函数名作为返回值返回。
def outer(start=0): count = start# 内部函数 def inner(): nonlocal count count += 1 # 引用外部函数的变量 returncount # 返回内部函数的名称 return innerquote = outer(5) print(quote()) #--------结果--------- # 6

从变量的生命周期的角度来讲,在 outer 函数执行结束以后,变量 count 已经被销毁了。当 outer 函数执行完后,会再执行内部的 Inner 函数,由于 Inner 函数中使用了 count 变量,所以程 序应该出现运行时错误。然而,程序仍能正常运行,这是为什么呢?
究其原因,主要在于函数的 闭包会记得外层函数的作用域,在 Inner 函数(闭包)中引用了外部函数的 count 变量,所以程序是不会释放这个变量的。
六、装饰器
  • 装饰器的含义:装饰器本质是一个 Python 函数,它可以在不改动其他函数的前提下,对函数的功能进行扩 充。
  • 装饰器用于下列场景:
  • 引入曰志;
  • 函数执行时间统计;
  • 执行函数前预备处理;
  • 执行函数后清理功能;
  • 权限校验;
  • 缓存。
def wrap_one(func): print('正在装饰1')def inner(): print('正在权限认证1') func() return innerdef wrap_two (func): print('正在装饰2')def inner(): print('正在权限认证2') func() return inner@wrap_one @wrap_two def test(): print('--------test----------')test() # -------结果----------- # 正在装饰2 # 正在装饰1 # 正在权限认证1 # 正在权限认证2 # --------test----------

多个装饰器可以应用在一个函数上,它们的调用顺序是自下而上的。
6.1 装饰器对有参数函数进行装饰 【九、递归函数、匿名函数、日期时间函数、随机函数、闭包、装饰器】如果无法确定函数的参数个数以及参数类 型,我们可以使用不定长参数来传递,示例代码如下:
def wrap_one(func): print('正在装饰1')def inner(*args, **kwargs): print('正在权限认证1') func(*args, **kwargs) return inner@wrap_one def test(*args, **kwargs): print('--------test----------') a = args print(a) b = kwargs print(b) test(1,2,3, a= 6)

6.2 装饰器对带有返回值的函数进行装饰
需要使用 return 语句将调用后的结果返回,示例代码如下:
def wrap_one(func): print('正在装饰1')def inner(*args, **kwargs): print('正在权限认证1') return func(*args, **kwargs) return inner@wrap_one def test(*args, **kwargs): print('--------test----------') a = args b = kwargs return a, b result = test(1,2,3, a= 6) print(result)

6.3 带有参数的装饰器(工厂函数) 如果我们给 装饰器添加参数,那么需要增加一层封装, 先传递参数,然后再传递函数名。 下面看一段代码:
def wrap_args(*args, **kwargs):def wrap_one(func): print('正在装饰1')def inner(): print('正在权限认证1')return func(*args, **kwargs) return inner return wrap_one@wrap_args(1, 2, a=4) def test(*args, **kwargs): print('--------test----------') a = args b = kwargs return a, b result = test() print(result)

七、python常见的内置函数
7.1 map函数
  • map 函数会根据提供的函数对指定的序列做映射。
map(function, iterable,...)

(1)第一个参数 function 表示的是一个函数名,第二个参数 iterable 可以是序列、 支持迭代的容器或迭代器。当调用 map 函数时, iterable 中的每个元素都会调用 function 函数, 所有元素调用 function 函数返回的结果会保存到一个迭代器对象中
(2)这里说明一下,在 Python 2 中, map 函数的返回值是到表 list 类型。 如果希望将迭代器对象转为列表,则可以通过 list 函数进行转换。 此外,还可以使用 for 循 环直接遍历迭代器对象,从而取出其内部的每个元素。
(3)在 Python3 以前,如果调用 map 函数时传入的 function 参数为 None,那么相当于合并参 数为元组。
(4)在 Python 3 以后,当 map 传入的函数为 None 时,就等同于 zip 函数(用于将可迭代的对 象作为参数, 将对象中对应的元素打包成一个个元组, 然后返回由这些元组组成的列表 ) 的功能, 并且已经被 zip 函数取代了。另外, map 函数无法处理两个序列长度不一致、对应位置操作数类 型不一致的情况,它们都会报类型错误
result = map(lambda x,y: x+y, [1,2,3], [4, 5, 6]) print(list(result)) #-----结果------- # [5, 7, 9]

7.2 filter函数
  • filter 函数会对指定序列执行过滤操作。
filter(function, iterable,..)

(1)第一个参数 function 可以是函数名称或者 None ,第二个参数 iterable 可以 是序列、支持迭代的容器或迭代器。返回值为迭代器对象( Python2 中, map 函数的返回值是列 表类型)。其中,== function 函数只能接收一个参数, 而且该函数的返回值为布尔值==。
(2)filter 函数的作用是以参数迭代器中的每个元素分别调用 function 函数,最后返回的迭代器包含调用结果为 True 的元素。示例代码如下 :
result = filter(lambda x: x**2, [0,2,3]) print(list(result)) # --------结果---------------- # [2, 3]

7.3 reduce函数
  • reduce 函数会对参数迭代器中的元素进行累积。
functools.reduce(function, iterable[,initializer])

(1)function 是一个带有两个参数的函数; 第 2 个参数 iterable 是一个迭代器对 象; initializer 表示固定的初始值。 reduce 函数会依次从迭代器对象中取出每个元素,和上一次 调用 function 的结果做为参数再次调用 function 函数。
import functoolsfunction = lambda x,y : x+y iterable = [1, 2, 3] result = functools.reduce(function, iterable, 0) print(result) # ----------结果------------- # 6

    推荐阅读