函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
函数能提高应用的模块性,和代码的重复利用率。
任何一个比较牛逼的程序均由多个函数封装而成。
你可以定义一个由自己想要功能的函数,以下是简单的规则:
Python 定义函数使用 def 关键字,一般格式如下:
def 函数名(参数列表):
函数体
例如:
def helloworld()
print("hello world")
helloworld()
输出:
hello world
再来个实例:
def fun(a, *hehe, **hahaha):
print("{0}--{1}--{2}".format(a, hehe, hahaha))
fun(1,2,3,4,5,x=1,y=2)
输出:
1--(2, 3, 4, 5)--{'x': 1, 'y': 2}
分析:
我使用了–来分割,可以看出来其中的赋值如下:
a = 1
hehe = 2, 3, 4, 5 tuple 一一对应过来
hahaha ={"x": 1, "y": 2} dict 一一对应过来
也就是:
*xxx 一个 * 代表 → tuple
**xxx 两个 ** 代表 → dict
def plus(a,b,c):
return a+b+c
print(plus(1,2,3))
## 匿名函数
aa = lambda x,y,z:x+y+z
print(aa(3,3,3))
输出:
6
9
注意观察上面的Python示例代码,f = lambda x,y,z:x+y+z 中的关键字lambda表示匿名函数,
# 冒号:之前的x,y,z表示它们是这个函数的参数。
# 匿名函数不需要return来返回值,表达式本身结果就是返回值。
t = lambda : True
print (t)
输出:
True
lambda x,y=3: x*y #允许参数存在默认值
a = lambda *z:z #*z返回的是一个元祖
print(a('Testing1','Testing2'))
输出:
('Testing1', 'Testing2')
再次反过来看下之前的阶乘题目:
def jc(n):
sum = 1
if n == 1:
return sum
else:
for i in range(1, int(n)+1):
sum *= i
return sum
def main():
sumt = 0
number = input("pls input a number: ")
for i in range(0, int(number)+1):
sumt += jc(i)
print(sumt)
if __name__ == '__main__':
main()
分析一下:
main()主函数调用 main()函数,main()函数再次调用jc()
def f(x,l=[]):
for i in range(x):
l.append(i*i)
print (l)
f(2)
f(3,[3,2,1])
f(3)
分析如上程序的输出结果是?
分析:
##申明一个函数,第一个参数是整形,第二个参数是list
##l的默认值是空
也就是说当传入的参数为2的时候此时的l值为空,输出的值为
[0, 1]
但是当x传入3,l传入[3,2,1]的时候,输出为:
[3,2,1,0,1,2]
当x传入3的时候,输出按照我们直接的想法是:
[0,1,2]
但是这个值是错误的,当我们传入x的值的时候,其中在上层循环中l的值也没有消失,也还在内存当中,所以也会再次传入这个循环当中:
[0,1,0,1,4]
函数的几个关键字:
def 定义函数
return 返回值
pass 略过此句,继续执行pass下面的任何语句
exit(1) 直接退出,并返回状态码 1
实例:
def f(x):
return x*x
aa = map(f,[0,1,2,3])
print(aa)
输出:
<map object at 0x04EB22D0>
输出的是一个map类型
如何直接将结果打印出来?
def f(x):
return x*x
aa = map(f,[0,1,2,3])
print(list(aa))
输出:
[0, 1, 4, 9]
强制的将输出结果转化为list结构。
Python 2.x 返回列表。
Python 3.x 返回迭代器。
实例展示了 map() 的使用方法:
实例1:
def squar(x):
return x ** 2
print(list(map(squar, [1, 2, 3, 4, 5])))
实例2:
print(list(map(lambda x: x ** 2, [1, 2, 3, 4, 5])))
不难看出,两个程序其实是一个意思,输出结果均为:
[1, 4, 9, 16, 25]
[1, 4, 9, 16, 25]
map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])
输出:
[3, 7, 11, 15, 19]
map()作为高阶函数,事实上它把运算规则抽象了,因此,我们不但可以计算简单的f(x)=x2,还可以计算任意复杂的函数,比如,把这个list所有数字转为字符串:
只需要一行代码:
list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
['1', '2', '3', '4', '5', '6', '7', '8', '9']
reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
实例一、
from functools import reduce
def add(x, y):
return x + y
print(reduce(add, [1, 2, 3, 4]))
输出:
10
当然求和运算可以直接用Python内建函数sum(),没必要动用reduce。
但是如果要把序列[1, 3, 5, 7, 9]变换成整数13579,reduce就可以派上用场:
from functools import reduce
def add(x, y):
return x * 10 + y
print(reduce(add, [1, 3, 5, 7, 9]))
输出:
13579
再次根据如上的操作,利用map函数把str转换为int:
from functools import reduce
def num(y, z):
return y * 10 + z
def charac(x):
digits = {'0':0, '1':1, '2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8, '9':9}
return digits[x]
print(reduce(num, map(charac, '13579')))
输出:
13579
Python内建的filter()函数用于过滤序列。
和map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
例如,在一个list中,删掉奇数,只保留偶数,可以这么写:
def isos(x):
return x % 2 == 0
print(list(filter(isos, [1, 2, 3, 5, 7, 8, 10])))
输出:
[2, 8, 10]
去空格:
def isos(x):
return x and x.strip()
print(list(filter(isos, ['A', ' ', 'B', ' ', 'BC', 'AS'])))
输出:
['A', 'B', 'BC', 'AS']
可见用filter()这个高阶函数,关键在于正确实现一个“筛选”函数。
注意到filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list。
排序是在程序中经常用到的算法。无论使用冒泡排序还是快速排序,排序的核心是比较两个元素的大小。如果是数字,我们可以直接比较,但如果是字符串或者两个dict呢?直接比较数学上的大小是没有意义的,因此,比较的过程必须通过函数抽象出来。
Python内置的sorted()函数就可以对list进行排序:
>>> sorted([36, 5, -12, 9, -21])
[-21, -12, 5, 9, 36]
此外,sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序:
>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]
key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序。对比原始的list和经过key=abs处理过的list:
list = [36, 5, -12, 9, -21]
keys = [36, 5, 12, 9, 21]
然后sorted()函数按照keys进行排序,并按照对应关系返回list相应的元素:
keys排序结果 => [5, 9, 12, 21, 36]
| | | | |
最终结果 => [5, 9, -12, -21, 36]
我们再看一个字符串排序的例子:
>>> sorted(['bob', 'about', 'Zoo', 'Credit'])
['Credit', 'Zoo', 'about', 'bob']
默认情况下,对字符串排序,是按照ASCII的大小比较的,由于’Z’ < ‘a’,结果,大写字母Z会排在小写字母a的前面。
现在,我们提出排序应该忽略大小写,按照字母序排序。要实现这个算法,不必对现有代码大加改动,只要我们能用一个key函数把字符串映射为忽略大小写排序即可。忽略大小写来比较两个字符串,实际上就是先把字符串都变成大写(或者都变成小写),再比较。
这样,我们给sorted传入key函数,即可实现忽略大小写的排序:
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
['about', 'bob', 'Credit', 'Zoo']
要进行反向排序,不必改动key函数,可以传入第三个参数reverse=True:
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
['Zoo', 'Credit', 'bob', 'about']
对列表中的元素按名字排序排序:
L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
aa = sorted(L, key=lambda x:x[0])
print(aa)
输出:
[('Adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88)]
再按成绩从高到低排序:
L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
aa = sorted(L, key=lambda x:x[1])
print(aa)
输出:
[('Bart', 66), ('Bob', 75), ('Lisa', 88), ('Adam', 92)]
实例2:
对字典dict(a=10, c=22, d=33, b=11)进行排序:
m = dict(a=10, c=22, d=33, b=11)
print(sorted(m.items()))
输出:
m = dict(a=10, c=22, d=33, b=11)
要是根据值来排序呢?
m = dict(a=10, c=22, d=33, b=11)
print(sorted(m.items(), key=lambda x:x[1]))
输出:
[('a', 10), ('b', 11), ('c', 22), ('d', 33)]
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:
aa = [i for i in range(10)]
print(aa)
输出:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
或者求10以内数的平方:
aa = [i*i for i in range(10)]
print(aa)
输出:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
仔细看如下代码:
aa = [i*i for i in range(10)]
print(aa)
bb = (i*i for i in range(10))
print(bb)
输出:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
<generator object <genexpr> at 0x0517F2D0>
创建aa和bb的区别仅在于最外层的[]和(),aa是一个list,而bb是一个generator。
我们可以直接打印出list的每一个元素,但我们怎么打印出generator(生成器)的每一个元素呢?
如果要一个一个打印出来,可以通过for循环获得generator的返回值:
bb = (i*i for i in range(10))
for i in bb:
print(i)
输出:
0
1
4
9
16
25
36
49
64
81
next()函数用法:
python3可以直接调取next函数
aa = (x for x in range(10) if x%2==0)
print(next(aa))
print(next(aa))
print(next(aa))
print(next(aa))
输出:
0
2
4
6
return:是用来返回具体的某个值;当执行到return,后续的逻辑代码不在执行。
yield:一般与循环一起用,相当于生成了一个容器(常见的就是字典);当执行到yield后,还会继续执行下面的逻辑代码。
实例:
针对/etc/passwd 列表中的内容按照uid排序:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 4/13/2018 4:55 PM
# @Author : zhdya
# @File : demon2.py
import codecs
'''
/etc/passwd 查找用户,对用户优先级进行排序
'''
with codecs.open("passwd.sh", "r") as f:
result = sorted(f.readlines(), key=lambda x: int(x.split(':')[2]))
with codecs.open("sortPasswd", "w") as f:
f.writelines(result)
分析:
》》 首先需要打开文件的内容;
》》 选择分隔符;
》》 选择每行的uid进行排序;
》》 按照原理是已经可以排序了,但是最终排序下来是按照ascall来排序的;
》》 转变类型
》》 写入一个文件进行检查