六.python函数基础
1.什么是函数
- 定义:函数是对程序逻辑进行结构化或过程化的一种编程方法。
- 特点:
1.能将整块代码巧妙地隔离成易于管理的小块
2.很多重复性的代码放到函数中能节省大量的空间
- 函数的定义方法
1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 # @Author : All is well 4 # @Software: PyCharm 5 6 7 def pingfang(x): 8 "定义一个计算平方函数" 9 result = x * x 10 return result 11 12 13 # def :定义函数的关键字 14 # pingfang:函数名 15 # ():内可定义形参 16 # "":文档描述(非必要,但是强烈建议为你的函数添加描述信息) 17 # result = x * x :指代码块或程序处理逻辑 18 # return:定义返回值 19 20 # 调用运行:可以带参数也可以不带(指定默认参数可以不带,后面会有介绍) 21 # 函数名() 22 23 #这里计算3的平方 24 print(pingfang(3)) 25 # 结果: 26 9
2.为什么要使用函数
身边的例子
一般公司都会监控服务器的硬件信息,是否有异常,就用平常监控的,cpu,内存,硬盘举例。
如果在我们没有函数的时候,我们会像以下这样写脚本。
1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 while True: 4 if cpu利用率 > 80 %: 5 # 发送邮件提醒 6 连接邮箱服务器 7 发送邮件 8 关闭连接 9 10 if 硬盘使用空间 > 80 %: 11 # 发送邮件提醒 12 连接邮箱服务器 13 发送邮件 14 关闭连接 15 16 if 内存占用 > 80 %: 17 # 发送邮件提醒 18 连接邮箱服务器 19 发送邮件 20 关闭连接
这样写是没有问题,但是有些时候需求变了,部门总监也要收到监控
1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 4 while True: 5 if cpu利用率 > 80 %: 6 # 发送邮件提醒 7 连接邮箱服务器 8 发送邮件 9 发送邮件给总监 10 关闭连接 11 12 if 硬盘使用空间 > 80 %: 13 # 发送邮件提醒 14 连接邮箱服务器 15 发送邮件 16 发送邮件给总监 17 关闭连接 18 19 if 内存占用 > 80 %: 20 # 发送邮件提醒 21 连接邮箱服务器 22 发送邮件 23 发送邮件给总监 24 关闭连接
但是某一天,需求又增加了,我们不同项目的报警要给不同的人看,这个时候我们还得继续在每个判断里面加各种人员
目前就有两个问题:
1.代码纯复制粘贴,改判断,不易于维护
2.很多重复性的代码,可读性较低
3.需求一变,我们不好应对,甚至会改整个脚本。
这几点恰好是函数的特点。这时候我们就用函数来试一试。
因为代码有重复性,我们可以提取重复的部分,就比如发送邮件这部分。
1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 4 def 发送邮件(内容) 5 #发送邮件提醒 6 连接邮箱服务器 7 发送邮件 8 发送邮件给领导 #以后发送邮件报警,只在这里添加即可 9 关闭连接 10 11 while True: 12 13 if cpu利用率 > 80%: 14 发送邮件('CPU报警') 15 16 if 硬盘使用空间 > 80%: 17 发送邮件('硬盘报警') 18 19 if 内存占用 > 80%: 20 发送邮件('内存报警')
用了函数,这里的代码大概节省了一半的空间,而且可读性也非常高。
这个例子,总结函数的好处(这就是我们为什么要使用函数)
1.代码重用
2.保持一致性,可扩展,易维护
3.函数的参数
- 形参介绍:
形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量
- 实参介绍:
实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值
3.1参数的分类
3.1.1 位置参数
- 调用时输入参数的值,且与函数声明时的参数名称位置保持一致。
1 # 函数定义 2 def foo(x, y): 3 print 'x is %s' % x 4 print 'y is %s' % y 5 6 7 # 位置参数调用(1为x,2为y,位置一一对应) 8 foo(1, 2)
3.1.2 默认参数
- 在函数声明时,指定形参的默认值,调用时可不传入参数(不传入会使用默认值)。
1 # 函数定义 2 def foo(x, y=2): #y=2为默认参数定义方式 3 print 'x is %s' % x 4 print 'y is %s' % y 5 6 #默认参数调用(这里不指定y,默认y=2) 7 foo(1)
3.1.3 关键字参数
- 调用时指定参数的名称,且与函数声明时的参数名称一致。使用关键字参数允许函数调用时参数的顺序与声明时不一致,仅根据参数的指定进行赋值。
1 # 函数定义
2 def foo(x, y):
3 print 'x is %s' % x
4 print 'y is %s' % y
5
6 # 关键字调用(顺序无所谓,仅仅和参数的赋值有关)
7 foo(y = 1, x = 2)
3.1.4 可变参数(非关键字)
- 可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个,这些可变参数在函数调用时自动组装为一个tuple。
1 #比如需求是我们要打印所有的参数,我们可以这样定义 2 >>> def testprint(args): 3 ... for i in args: 4 ... print(i) 5 ... 6 >>> 7 >>> 8 #调用的时候要组成一个tuple或list,而且不能为空,否则会报错 9 >>> testprint([1,2,3,4]) 10 1 11 2 12 3 13 4 14 >>> testprint((1,2,3,4)) 15 1 16 2 17 3 18 4 19 #错误调用 20 >>> testprint() 21 Traceback (most recent call last): 22 File "<stdin>", line 1, in <module> 23 TypeError: testprint() missing 1 required positional argument: 'args' 24 >>> 25 26 #以下用可变参数实现(可以变长变短,输入几个参数都会一一对应向后排列) 27 28 >>> def testprint(*args): 29 ... for i in args: 30 ... print(i) 31 ... 32 >>> testprint(1,2,3) #可以直接调用, 33 1 34 2 35 3 36 >>> testprint('test1','test2','test3') 37 test1 38 test2 39 test3 40 >>> testprint() #调用值也可以为空 41 >>> 42 43 #如果有一个list或者tuple也要传入到可变参数,怎么办呢,我们一般会这样实现 44 >>> a = [1,2,3] 45 >>> testprint(a[0],a[1],a[2]) 46 1 47 2 48 3 49 >>> 50 51 #但是学过可变参数之后,我们可以这么做 52 >>> a = [1,2,3] 53 >>> testprint(*a) #*a 会把列表内的所有元素作为可变参数传入(重点*****) 54 1 55 2 56 3 57 >>>
3.1.5 可变参数(关键字)
- 关键字参数也是可变参数的一种,它允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。
上面说过关键字参数,但是不可变,形参定义几个关键字,调用就得有对应的关键字,比如下面获取用户信息的例子
1 >>> def person(name, age): 2 ... print 'name is %s' % name 3 ... print 'age is %s' % age 4 ... 5 >>> person(name = 'All is well', age = 23) 6 name is All is well 7 age is 23 8 >>>
以上例子只能输入姓名和年龄,如果有其他信息还得添加参数,每次都需要修改参数和调用,很麻烦,这个时候我们就用到了关键字的可变参数。如下示例
1 >>> def person(name, age,**kwargs): 2 ... print 'name is %s' % name 3 ... print 'age is %s' % age 4 ... print 'other is %s' %kwargs 5 ... 6 >>> person(name='all is well',age='23',city='beijing',Gender='M') 7 name is all is well 8 age is 23 9 other is {'city': 'beijing', 'Gender': 'M'} 10 >>> 11 #因为关键字参数可以为0个关键字,我们不需要的时候也可以不输入 12 >>> person(name='all is well',age='23') 13 name is all is well 14 age is 23 15 other is {} 16 >>>
3.1.6 可变参数(命名关键字)
- 可变命名关键字其实就是可变关键字的一种,唯一的区别就是可变命名关键字可以定制都可以命哪些名字,而不是随意变长。(目前测试只在python3中可以使用******)
以下还按照用户信息来举例
1 >>> def person(name, age,**kwargs): 2 ... print 'name is %s' % name 3 ... print 'age is %s' % age 4 ... print 'other is %s' %kwargs 5 ... 6 7 >>> person(name='all is well',age='23',city='beijing',Gender='M')
可变关键字参数这里的other可以无限的增加,有时候我们要将other里定义好一些参数,其他不存在的条件不允许添加,比如我们只能输入城市和性别,其他的不允许输入,我们可以这样做。
1 >>> def person(name, age,*,city,Gender): #这里定义只能定义city和Gender参数 2 ... print('name is %s' %name) 3 ... print('age is %s' %age) 4 ... print('other is %s,%s' %(city,Gender)) 5 ... 6 7 >>> person(name='all is well',age='23',city='beijing',Gender='M') 8 name is all is well 9 age is 23 10 other is beijing,M 11 12 #错误示例,这里输入没有定制的work参数会报错 13 >>> person(name='all is well',age='23',city='beijing',Gender='M',work='IT') 14 Traceback (most recent call last): 15 File "<stdin>", line 1, in <module> 16 TypeError: person() got an unexpected keyword argument 'work' 17 >>>
4.局部变量和全局变量
- 局部变量:
在子程序中定义的变量称为局部变量,它们与程序外具有相同名称的其他变量没有任何关系。 - 全局变量:
在整个程序外定义的变量称为全局变量,如果你想要为一个定义在程序外的变量赋值,可以使用global语句完成这个功能,没有global语句,是不可能为定义在函数外的变量赋值的。 - 注意:当全局变量与局部变量重名的时候,在程序的内部定义局部变量的局部变量起作用,在其他地方,全局变量起作用。
示例如下:
1 #当没有局部变量的时候,程序会引用全局变量 2 name='All is well' 3 4 def my_name(): 5 print('my name is',name) 6 7 my_name() 8 9 #结果: 10 my name is All is well 11 #################################### 12 #当程序内部定义好局部变量的时候,程序会优先引用局部变量 13 name='All is well' 14 15 def my_name(): 16 name='zhangsan' 17 print('local variable is',name) 18 19 my_name() 20 print('global variable is',name) 21 #结果: 22 >>> my_name() 23 local variable is zhangsan 24 >>> print('global variable is',name) 25 global variable is All is well 26 #################################### 27 #想要引用或者为程序外的全局变量赋值的时候,这时候用global 28 name='All is well' 29 def my_name(): 30 global name #引用全局变量 31 name='zhangsan' #修改全局变量 32 print('Changed global to',name) 33 34 print('global variable is',name) 35 my_name() 36 print('global variable is',name) 37 #结果: 38 >>> print('global variable is',name) 39 global variable is All is well 40 >>> my_name() 41 Changed global to zhangsan 42 >>> print('global variable is',name) 43 global variable is zhangsan
5.递归函数
- 定义:如果一个函数在内部调用自身本身,这个函数就是递归函数。
- 递归的特点:大大缩短程序的代码,可以用较短的代码解决一些复杂的问题
- 递归算法的基本思想是:把规模大的、较难解决的问题变成规模较小的、易解决的同一问题。规模较小的问题又变成规模更小的问题,并且小到一定程度可以直接得出它的解,从而得到原来问题的解。
- 一个问题要采用递归方法来解决时,必须符合以下三个条件:
- 解决问题时,可以把一个问题转化为一个新的问题,而这个新的问题的解决方法仍与原问题的解法相同,只是所处理的对象有所不同,这些被处理的对象之间是有规律的递增或递减。
- 可以通过转化过程使问题得到解决。
- 必定要有一个明确的结束递归的条件,否则递归将会无止境地进行下去,直到耗尽系统资源。也就是说必须要写终止递归的条件。
- 递归与循环做对比
递归算法:
- 优点:代码简洁、清晰,并且容易验证正确性。
- 缺点:它的运行需要较多次数的函数调用,如果调用层数比较深,每次都要创建新的变量,需要增加额外的堆栈处理,会对执行效率有一定影响,占用过多的内存资源。
循环算法:
- 优点:速度快,结构简单。
- 缺点:并不能解决所有的问题。有的问题适合使用递归而不是循环。如果使用循环并不困难的话,最好使用循环。
注:不要认为递归和循环是一个道理,递归与循环是两种不同的解决问题的典型思路。
一个阶乘的例子:
计算阶乘n! = 1 x 2 x 3 x ... x n
,用函数fact(n)
表示,可以看出:
fact(n) = n! = 1 x 2 x 3 x ... x (n-1) x n = (n-1)! x n = fact(n-1) x n
所以,fact(n)
可以表示为n x fact(n-1)
,只有n=1时需要特殊处理。
于是,fact(n)
用递归的方式写出来就是:
1 #!/usr/bin/env python 2 #--*--conding:utf-8--*-- 3 4 def fact(n): 5 if n==1: 6 return 1 7 return n * fact(n - 1)
执行如下:
1 >>> fact(1) 2 1 3 >>> fact(2) 4 2 5 >>> fact(3) 6 6 7 >>> fact(4) 8 24 9 >>> fact(5) 10 120 11 >>>
计算过程如下:
1 ===> fact(5) 2 ===> 5 * fact(4) 3 ===> 5 * (4 * fact(3)) 4 ===> 5 * (4 * (3 * fact(2))) 5 ===> 5 * (4 * (3 * (2 * fact(1)))) 6 ===> 5 * (4 * (3 * (2 * 1))) 7 ===> 5 * (4 * (3 * 2)) 8 ===> 5 * (4 * 6) 9 ===> 5 * 24 10 ===> 120
递归的缺点:由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。如下:
>>> fact(999) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 4, in fact ... File "<stdin>", line 4, in fact RuntimeError: maximum recursion depth exceeded in comparison
栈溢出的优化方法,利用尾递归的方法,尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。
#!/usr/bin/env python #--*--coding:utf-8--*-- def fact(n): return fact_iter(n, 1) def fact_iter(num, product): if num == 1: return product return fact_iter(num - 1, num * product)
可以看到,return fact_iter(num - 1, num * product)
仅返回递归函数本身,num - 1
和num * product
在函数调用前就会被计算,不影响函数调用。
fact(5)
对应的fact_iter(5, 1)
的调用如下:
1 ===> fact_iter(5, 1) 2 ===> fact_iter(4, 5) 3 ===> fact_iter(3, 20) 4 ===> fact_iter(2, 60) 5 ===> fact_iter(1, 120) 6 ===> 120
尾递归调用时,如果做了优化,栈不会增长,因此,无论多少次调用也不会导致栈溢出。
遗憾的是,大多数编程语言没有针对尾递归做优化,Python解释器也没有做优化,所以,即使把上面的fact(n)
函数改成尾递归方式,也会导致栈溢出。
注:Python标准的解释器没有针对尾递归做优化,任何递归函数都存在栈溢出的问题。
6.匿名函数
- 定义:顾名思义,没有函数名的函数称为匿名函数
- 基本语法:lambda [arg1[,arg2,...argN]]: expression
- 匿名函数的好处:因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数
1 #普通函数 2 >>> def run(x): 3 ... return x * x 4 ... 5 >>> run(10) 6 100 7 >>> 8 9 #匿名函数可以这么定义 10 11 >>> run = lambda x: x * x 12 >>> 13 >>> run(10) 14 100 15 >>>
注:匿名函数常和一些内置函数配合使用,一是定义起来方便,二是代码简洁,不需要从新写个函数。
7.高阶函数
-
高阶函数必须满足以下两个需求
-
函数的传入参数是一个函数名
-
函数的返回值是一个函数名
1 #函数接收的参数是一个函数名 2 3 def foo(n): 4 print(n) 5 6 def bar(name): 7 print("my name is %s" %name) 8 9 foo(bar('All is well')) 10 11 #返回值中包含函数 12 13 def bar(): 14 print("from bar") 15 def foo(): 16 print("from foo") 17 return bar 18 19 res=foo() 20 res()
8.内置函数
8.1 python3.6.2版本的内置函数
8.2 内置函数进行分类
8.2.1 数学运算类
abs(x) | 求绝对值 1、参数可以是整型,也可以是复数 2、若参数是负数,则返回负数的模 |
complex([real[, imag]]) | 创建一个复数 |
divmod(a, b) | 分别取商和余数 注意:整型、浮点型都可以 |
float([x]) | 将一个字符串或数转换为浮点数。如果无参数将返回0.0 |
int([x[, base]]) | 将一个字符转换为int类型,base表示进制 |
long([x[, base]]) | 将一个字符转换为long类型 |
pow(x, y[, z]) | 返回x的y次幂 |
range([start], stop[, step]) | 产生一个序列,默认从0开始 |
round(x[, n]) | 四舍五入 |
sum(iterable[, start]) | 对集合求和 |
oct(x) | 将一个数字转化为8进制 |
hex(x) | 将整数x转换为16进制字符串 |
chr(i) | 返回整数i对应的ASCII字符 |
bin(x) |
将整数x转换为二进制字符串 |
bool([x]) | 将x转换为Boolean类型 |
8.2.2 集合类操作
basestring() | str和unicode的超类 不能直接调用,可以用作isinstance判断 |
format(value [, format_spec]) | 格式化输出字符串 格式化的参数顺序从0开始,如“I am {0},I like {1}” |
unichr(i) | 返回给定int类型的unicode |
enumerate(sequence [, start = 0]) | 返回一个可枚举的对象,该对象的next()方法将返回一个tuple |
iter(o[, sentinel]) | 生成一个对象的迭代器,第二个参数表示分隔符 |
max(iterable[, args...][key]) | 返回集合中的最大值 |
min(iterable[, args...][key]) | 返回集合中的最小值 |
dict([arg]) | 创建数据字典 |
list([iterable]) | 将一个集合类转换为另外一个集合类 |
set() | set对象实例化 |
frozenset([iterable]) | 产生一个不可变的set |
str([object]) | 转换为string类型 |
sorted(iterable[, cmp[, key[, reverse]]]) | 队集合排序 |
tuple([iterable]) | 生成一个tuple类型 |
xrange([start], stop[, step]) | xrange()函数与range()类似,但xrnage()并不创建列表,而是返回一个xrange对象,它的行为与列表相似,但是只在需要时才计算列表值,当列表很大时,这个特性能为我们节省内存 |
8.2.3 逻辑判断操作
all(iterable) | 1、集合中的元素都为真的时候为真 2、特别的,若为空串返回为True |
any(iterable) | 1、集合中的元素有一个为真的时候为真 2、特别的,若为空串返回为False |
cmp(x, y) | 如果x < y ,返回负数;x == y, 返回0;x > y,返回正数 |
8.2.4 反射操作
callable(object) | 检查对象object是否可调用 1、类是可以被调用的 2、实例是不可以被调用的,除非类中声明了__call__方法 |
classmethod() | 1、注解,用来说明这个方式是个类方法 2、类方法即可被类调用,也可以被实例调用 3、类方法类似于Java中的static方法 4、类方法中不需要有self参数 |
compile(source, filename, mode[, flags[, dont_inherit]]) | 将source编译为代码或者AST对象。代码对象能够通过exec语句来执行或者eval()进行求值。 1、参数source:字符串或者AST(Abstract Syntax Trees)对象。 2、参数 filename:代码文件名称,如果不是从文件读取代码则传递一些可辨认的值。 3、参数model:指定编译代码的种类。可以指定为 ‘exec’,’eval’,’single’。 4、参数flag和dont_inherit:这两个参数暂不介绍 |
dir([object]) | 1、不带参数时,返回当前范围内的变量、方法和定义的类型列表; 2、带参数时,返回参数的属性、方法列表。 3、如果参数包含方法__dir__(),该方法将被调用。当参数为实例时。 4、如果参数不包含__dir__(),该方法将最大限度地收集参数信息 |
delattr(object, name) | 删除object对象名为name的属性 |
eval(expression [, globals [, locals]]) | 计算表达式expression的值 |
execfile(filename [, globals [, locals]]) | 用法类似exec(),不同的是execfile的参数filename为文件名,而exec的参数为字符串。 |
filter(function, iterable) | 构造一个序列,等价于[ item for item in iterable if function(item)] 1、参数function:返回值为True或False的函数,可以为None 2、参数iterable:序列或可迭代对象 |
getattr(object, name [, defalut]) | 获取一个类的属性 |
globals() | 返回一个描述当前全局符号表的字典 |
hasattr(object, name) | 判断对象object是否包含名为name的特性 |
hash(object) | 如果对象object为哈希表类型,返回对象object的哈希值 |
id(object) | 返回对象的唯一标识 |
isinstance(object, classinfo) | 判断object是否是class的实例 |
issubclass(class, classinfo) | 判断是否是子类 |
len(s) | 返回集合长度 |
locals() | 返回当前的变量列表 |
map(function, iterable, ...) | 遍历每个元素,执行function操作 |
memoryview(obj) | 返回一个内存镜像类型的对象 |
next(iterator[, default]) | 类似于iterator.next() |
object() | 基类 |
property([fget[, fset[, fdel[, doc]]]]) | 属性访问的包装类,设置后可以通过c.x=value等来访问setter和getter |
reduce(function, iterable[, initializer]) | 合并操作,从第一个开始是前两个参数,然后是前两个的结果与第三个合并进行处理,以此类推 |
reload(module) | 重新加载模块 |
setattr(object, name, value) | 设置属性值 |
repr(object) | 将一个对象变幻为可打印的格式 |
slice() | |
staticmethod | 声明静态方法,是个注解 |
super(type[, object-or-type]) | 引用父类 |
type(object) | 返回该object的类型 |
vars([object]) | 返回对象的变量,若无参数与dict()方法类似 |
bytearray([source [, encoding [, errors]]]) | 返回一个byte数组 1、如果source为整数,则返回一个长度为source的初始化数组; 2、如果source为字符串,则按照指定的encoding将字符串转换为字节序列; 3、如果source为可迭代类型,则元素必须为[0 ,255]中的整数; 4、如果source为与buffer接口一致的对象,则此对象也可以被用于初始化bytearray. |
zip([iterable, ...]) | 实在是没有看懂,只是看到了矩阵的变幻方面 |
8.2.5 IO操作
file(filename [, mode [, bufsize]]) | file类型的构造函数,作用为打开一个文件,如果文件不存在且mode为写或追加时,文件将被创建。添加‘b’到mode参数中,将对文件以二进制形式操作。添加‘+’到mode参数中,将允许对文件同时进行读写操作 1、参数filename:文件名称。 2、参数mode:'r'(读)、'w'(写)、'a'(追加)。 3、参数bufsize:如果为0表示不进行缓冲,如果为1表示进行行缓冲,如果是一个大于1的数表示缓冲区的大小 。 |
input([prompt]) | 获取用户输入 推荐使用raw_input,因为该函数将不会捕获用户的错误输入 |
open(name[, mode[, buffering]]) | 打开文件 与file有什么不同?推荐使用open |
打印函数 | |
raw_input([prompt]) | 设置输入,输入都是作为字符串处理 |
8.3 重点掌握内置函数
- map函数
1 #有个需求,想把列表里的每个元素进行操作,并返回每个元素操作后的值,例如求每个元素平方的操作 2 3 #一般方法,我们可以这样做 4 li = [1,2,3,4,5] 5 ret = [] 6 for i in li: 7 ret.append(i*i) 8 print(ret) 9 #但是又想,这仅仅是一个列表,要是有很多列表,我们就得写很多循环,像这种实现一个特定的功能我们可以用函数试试~~~ 10 li = [1,2,3,4,5] 11 def map_test(args): 12 ret = [] 13 for i in args: 14 ret.append(i*i) 15 return ret 16 print map_test(li) 17 18 #这样就实现了多个列表,每次传一个值就行了,但是又有问题了,需求不是把每个元素都平方,我们要把每个函数加1怎么办呢,我们又得写多个函数。 19 #这种我们可以用多个参数试试,一个参数是传入的函数,一个参数是传入的列表。 20 li = [1,2,3,4,5] 21 def add(x): 22 return x + 1 23 24 def map_test(func,li): 25 ret = [] 26 for i in li: 27 ret.append(func(i)) 28 return ret 29 print map_test(add,li) 30 31 #这样就完成了,每次传入一个函数和列表就可以计算。这时可以优化下函数,尽量减少代码,我们可以用匿名函数lambda。 32 33 li = [1,2,3,4,5] 34 35 def map_test(func,li): 36 ret = [] 37 for i in li: 38 ret.append(func(i)) 39 return ret 40 41 print map_test(lambda x:x+1,li) 42 43 # 这样就大大缩减了代码。 44 # 但是有个好消息,就是python中有一个内置的map函数,用来处理序列中的每个元素,得到的结果是一个"列表",该"列表"元素个数及位置与原来一样 45 li = [1,2,3,4,5] 46 47 print map(lambda x:x+1,li)
- reduce函数
1 #有个需求,相对一个序列里面的数值求和,例如对以下列表求和 2 #一般方法,我们可以这样做 3 num = [1,2,3,4,5] 4 n = 0 5 for i in num: 6 n+=i 7 print n 8 9 #利用学习map的知识,我们知道,这里可以用两个参数传入的函数,一个参数是传入的函数。另一个是传入的列表。 10 num = [1,2,3,4,5] 11 def add(x,y): 12 return x+y 13 14 def reduce_test(func,args): 15 res = num.pop(0) 16 for i in args: 17 res = func(res,i) 18 return res 19 20 print reduce_test(add,num) 21 22 #这里有个问题,我们计算的是1到5的和,有些时候用户会指定初始值,这里优化下。并把函数用匿名函数lambda优化。 23 num = [1,2,3,4,5] 24 def reduce_test(func,num,init=None): 25 if init is None: 26 res = num.pop(0) 27 else: 28 res = init 29 for i in num: 30 res=func(res,i) 31 return res 32 print(reduce_test(lambda x,y: x+y,num,100)) #这里的100是初始值,结果为115 33 34 #大功告成。 35 36 #但是有个好消息,就是python2.x中有一个内置的reduce函数,作用是处理一个序列,把序列进行合并操作。 37 num = [1,2,3,4,5] 38 print(reduce(lambda x,y: x+y,num,100)) 39 40 #注意:python3里面reduce被移除内置函数,我们可以用 from functools import reduce导入即可。 41 42 reduce函数
- filter函数
1 #有个需求,我们要把列表以'z'开头的元素过滤掉 2 people = ['zhangsan','lisi','wangwu','zhaoliu'] 3 # 一般方法,我们可以这样做 4 for i in people: 5 if not i.startswith('z'): 6 print i 7 8 #利用学习map的知识,我们知道,这里可以用两个参数传入的函数,一个参数是传入的函数。另一个是传入的列表。 9 people = ['zhangsan','lisi','wangwu','zhaoliu'] 10 def guolv(x): 11 return x.startswith('z') 12 13 def test_filter(func,args): 14 ret = [] 15 for i in args: 16 if not func(i): 17 ret.append(i) 18 return ret 19 20 print test_filter(guolv,people) 21 22 #匿名函数优化 23 people = ['zhangsan','lisi','wangwu','zhaoliu'] 24 def test_filter(func,args): 25 ret = [] 26 for i in args: 27 if not func(i): 28 ret.append(i) 29 return ret 30 print test_filter(lambda x:x.startswith('z'),people) 31 32 # 但是有个好消息,就是python中有一个内置的filter函数,遍历序列中的每个元素,判断每个元素得到的布尔值,如果是True则保留下来. 33 people = ['zhangsan','lisi','wangwu','zhaoliu'] 34 print filter(lambda x:not x.startswith('z'),people)
8.4 常用内置函数举例介绍
1 abs(-5) # 取绝对值,也就是5
2 round(2.6) # 四舍五入取整,也就是3.0
3 pow(2, 3) # 相当于2**3,如果是pow(2, 3, 5),相当于2**3 % 5
4 cmp(2.3, 3.2) # 比较两个数的大小
5 divmod(9,2) # 返回除法结果和余数
6 max([1,5,2,9]) # 求最大值
7 min([9,2,-4,2]) # 求最小值
8 sum([2,-1,9,12]) # 求和
1 int("5") # 转换为整数 integer
2 float(2) # 转换为浮点数 float
3 long("23") # 转换为长整数 long integer
4 str(2.3) # 转换为字符串 string
5 complex(3, 9) # 返回复数 3 + 9i
6 ord("A") # "A"字符对应的数值
7 chr(65) # 数值65对应的字符
8 unichr(65) # 数值65对应的unicode字符
1 进制转换
2 bin(56) # 返回一个字符串,表示56的二进制数
3 hex(56) # 返回一个字符串,表示56的十六进制数
4 oct(56) # 返回一个字符串,表示56的八进制数
5
6 真假性判断,在Python中,下列对象都相当于False: [], (), {}, 0, None, 0.0, ''
7 bool(0) # 转换为相应的真假值,在Python中,0相当于False
1 list((1,2,3)) # 转换为表 list 2 tuple([2,3,4]) # 转换为定值表 tuple 3 slice(5,2,-1) # 构建下标对象 slice 4 dict(a=1,b="hello",c=[1,2,3]) # 构建词典 dictionary
1 all([True, 1, "hello!"]) # 是否所有的元素都相当于True值 2 any(["", 0, False, [], None]) # 是否有任意一个元素相当于True值 3 sorted([1,5,3]) # 返回正序的序列,也就是[1,3,5] 4 reversed([1,5,3]) # 返回反序的序列,也就是[3,5,1]