Python学习总结【第三篇】:Python之函数(自定义函数、内置函数、lambda表达式、装饰器、迭代器&生成器)
1、函数
1.1 自定义函数
背景需求:
在学习函数之前,一直遵循:面向过程编程,即:根据业务逻辑从上到下实现功能,其往往用一长段代码来实现指定功能,开发过程中最常见的操作就是粘贴复制,也就是将之前实现的代码块复制到现需功能处,如下:
while True: if cpu利用率 > 90%: #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 if 硬盘使用空间 > 90%: #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 if 内存占用 > 80%: #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接
上述代码,if条件语句下的内容可以被提取出来公用,如下:
def 发送邮件(内容) #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 while True: if cpu利用率 > 90%: 发送邮件('CPU报警') if 硬盘使用空间 > 90%: 发送邮件('硬盘报警') if 内存占用 > 80%:
对于上述的两种实现方式,第二次必然比第一次的重用性和可读性要好,其实这就是函数式编程和面向过程编程的区别:
函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可
面向对象:对函数进行分类和封装,让开发“更快更好更强...”
函数式编程最重要的是增强代码的重用性和可读性
自定义函数练习
1、写函数,计算传入字符串中【数字】、【字母】、【空格] 以及 【其他】的个数
def func(get_str): """ 计算传入字符串中【数字】、【字母】、【空格] 以及 【其他】的个数 :param get_str: :return: """ digit, alpha, space, other = 0, 0, 0, 0 # 数字 字母 空格 其他 for i in get_str: if i.isdigit(): digit += 1 elif i.isalpha(): alpha += 1 elif i.isspace(): space += 1 else : other += 1 return digit, alpha, space, other def main(): get_str = input("请输入一个字符串:") result = func(get_str) # print(result) print( """ ============================ 数字:%s 字母:%s 空格:%s 其他:%s ============================""" % result) if __name__ == '__main__': main()
2、写函数,判断用户传入的对象(字符串、列表、元组)长度是否大于5
def func(get_obj): """ 判断用户传入的对象(字符串、列表、元组)长度是否大于5 :param get_obj: :return: """ ret = False if isinstance(get_obj, str) or isinstance(get_obj, list) or isinstance(get_obj, tuple): if len(get_obj) > 5: ret = True return len(get_obj), ret def main(): # get_obj = "dsfwerqwer" # get_obj = (1, 2, 3, 4,) get_obj = [1, 2, 3, ] result = func(get_obj) print("长度为:%s,是否大于5:%s" % result) if __name__ == '__main__': main()
3、写函数,检查用户传入的对象(字符串、列表、元组)的每一个元素是否含有空内容
def func(get_obj): """ 检查用户传入的对象(字符串、列表、元组)的每一个元素是否含有空内容 :param get_obj: :return: """ ret = False if isinstance(get_obj, str) or isinstance(get_obj, list) or isinstance(get_obj, tuple): for i in get_obj: if i == '': ret = True break return ret def main(): get_obj = "ds fwerqwer" # get_obj = (1, 2, 3, 4, '',) # get_obj = (1, 2, 3, 4,) # get_obj = [1, 2, 3, '', 5, ] result = func(get_obj) print("该对象是否含有空元素%s" % result) if __name__ == '__main__': main()
4、写函数,检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
5、写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者。
6、写函数,检查传入字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
7、写函数,利用递归获取斐波那契数列中的第 10 个数,并将该值返回给调用者。
地址:http://www.cnblogs.com/Wxtrkbc/p/5466082.html
1.2 函数的定义与使用
def 函数名(参数): ... 函数体 ...
函数的定义主要有如下要点:
def:表示函数的关键字
函数名:函数的名称,日后根据函数名调用函数
函数体:函数中进行一系列的逻辑计算,如:发送邮件、计算出 [11,22,38,888,2]中的最大数等...
参数:为函数体提供数据
返回值:当函数执行完毕后,可以给调用者返回数据。
以上要点中,比较重要有参数和返回值:
1.2.1 返回值
函数是一个功能块,该功能到底执行成功与否,需要通过返回值来告知调用者。
def 发送短信(): 发送短信的代码... if 发送成功: return True else: return False while True: # 每次执行发送短信函数,都会将返回值自动赋值给result # 之后,可以根据result来写日志,或重发等操作 result = 发送短信() if result == False: 记录日志,短信发送失败...
1.2.2 参数
1)为什么要使用参数?
2)参数类型
普通参数(多个参数将严格按照顺序将实际参数赋值给形式参数)
# 函数定义:name叫做函数func的形式参数,简称:形参 >>> def func(name): ... print(name) ... # 函数的调用执行 # 'alex' 叫做函数func的实际参数,简称:实参 >>> func('alex') alex
默认参数
>>> def func(name, age = 18): ... print "%s:%s" %(name,age) ... # 指定参数 >>> func('wupeiqi', 19) wupeiqi:19 # 使用默认参数 >>> func('alex') alex:18 注:默认参数需要放在参数列表最后
指定参数赋值
>>> def show(a1,a2): ... print(a1,a2) ... >>> show(100,111) # 按照顺序将多个实参赋值给形参 (100, 111) >>> show(a2=111,a1=100) # 指定参数进行赋值,不按照顺序进行赋值 (100, 111)
动态参数
动态参数一:默认将传入的参数,全部放置在元组中, f1(*[1`1,22,33,44]) >>> def func(*args): ... print(args) ... # 执行方式一 >>> func(11,33,4,4454,5) (11, 33, 4, 4454, 5) # 执行方式二 >>> li = [11,33,4,4454,5] # 元组,列表,字典都要做类似处理 >>> func(*li) (11, 33, 4, 4454, 5) # 错误执行方法 >>> func(li) # 这样并非正确的动态传参,这样函数会把整个列表当做元组的一个元素进行处理 ([11, 33, 4, 4454, 5],) 动态参数二:默认将传入的参数,全部放置在字典中 f1(**{"kl":"v1", "k2":"v2"}) >>> def func(**kwargs): ... print(kwargs) ... # 执行方式一 >>> func(name='wupeiqi',age=18) {'name': 'wupeiqi', 'age': 18} # 执行方式二 >>> li = {'name':'wupeiqi', "age":18, 'gender':'male'} >>> func(**li) {'name': 'wupeiqi', 'gender': 'male', 'age': 18} 动态参数三:把元组和字典结合进行传参(元组在前,字典在后) >>> def show(*args,**kwargs): ... print(args,type(args)) ... print(kwargs,type(kwargs)) ... >>> show(11,22,33,100,a1=11,abc=100) (11, 22, 33, 100) <class 'tuple'> {'abc': 100, 'a1': 11} <class 'dict'> #str.format()格式化输出 讲解动态参数 *args ,**kwargs s1 = "I am {0},age {1}".format("alex",18) # 利用*args进行传参 print(s1) lis = ["alex",18] s1 = "I am {0},age {1}".format(*lis) # 利用*args进行传参 print(s1) s1 = "I am {name},age {age}".format(name="alex",age=18) # 利用**kwargs进行传参 print(s1) dic = {"name":"alex","age":18} s1 = "I am {name},age {age}".format(**dic) # 利用**kwargs进行传参 print(s1) 输出结果都为: I am alex,age 18
邮件代码:
def sendmail(xxoo, content): # xxoo = alex try: import smtplib from email.mime.text import MIMEText from email.utils import formataddr msg = MIMEText(content, 'plain', 'utf-8') msg['From'] = formataddr(["武沛齐",'wptawy@126.com']) msg['To'] = formataddr(["走人",'424662508@qq.com']) msg['Subject'] = "主题" server = smtplib.SMTP("smtp.126.com", 25) server.login("wptawy@126.com", "WW.3945.59") server.sendmail('wptawy@126.com', [xxoo,], msg.as_string()) server.quit() except: # 发送失败 return "失败" else: # 发送成功 return "cc" while True: em = input("请输入邮箱地址:") result = sendmail(em, "SB") if result == "cc": print("发送成功") else: print("发送失败")
1.2.3 函数与变量定义
1、 def f1 def f1 (生效) 2、函数传递引用 3、全局变量 全局变量定义要大写 读,都可读 赋值,globals() 字典,列表等全局变量,可以修改,但是无法重新赋值 全局变量定义位置:将全局变量在代码开始即进行定义,也可以在函数体内定义,但是不友好,需要阅读全部的代码,找出在各个函数体内定义的全局变量
# 补充问题1: def f1(a1,a2): return a1+a2 def f1(a1,a2): return a1*a2 res = f1(8,8) print(res)
# 问题:结果多少为什么? # 解答:结果是64 代码是顺序执行,f1被重新指向,第一个f1定义失效,f2生效
# 补充问题2: def f1(a1): a1.append(999) li = [11,22,33,44] f1(li) print(li)
# 问题:结果多少,为什么? # 解答:结果为[11, 22, 33, 44, 999] # 即:Python是传递一个引用 并非复制一份内容 a1和li的指向是同一块内存地址,修改了a1即修改了li
# 补充问题3: # 各个函数内定义变量的引用问题:没有结果,name变量只在f1内定义及使用 def f1(): name = "alex" print(name) def f2(): print(name)
f1()
alex
f2()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in f2
NameError: name 'name' is not defined # 全局变量,所有作用域都能读 name = "alex" def f1(): age =18 print(age,name) def f2(): age =19 print(age,name)
>>> f1()
18 alex
>>> f2()
19 alex # 对全局变量进行重新赋值,需要global #全局变量和函数体内变量都定义了,优先使用自己函数体内定义的变量
# global说明:
# 1、global---将变量定义为全局变量。可以通过定义为全局变量,实现在函数内部改变变量值。
# 2、一个global语句可以同时定义多个变量,如 global x, y, z
# 执行方式1
>>> NAME = None
>>> def f1():
... age = 18
... global NAME
... NAME = "123"
... print(age, NAME)
...
>>> def f2():
... age = 19
... print(age, NAME)
...
...
>>> f1()
18 123
>>> f2()
19 123
# 执行方式 2
>>> NAME = None
>>> def f1():
... age = 18
... global NAME
... NAME = "123"
... print(age, NAME)
...
>>> def f2():
... age = 19
... print(age, NAME)
...
>>> f2()
19 None
>>> f1()
18 123
# 特殊:列表字典,可修改,不可重新赋值 name = [11,22,33,44] # 可以在函数体内增加值(name.append(55)),当时无法重新赋值(name = "123") def f1(): age =18 name = "123" print(age,name) def f2(): age =19 name.append(55) print(age,name)
函数应用范例
#!/usr/bin/env python # -*- coding:utf-8 -*- # Author:Alex Li def login(username, password): """ 用于用户登录 :param username: 用户输入的用户名 :param password: 用户输入的密码 :return: true,表示登录成功;false,登录失败 """ f = open("db", 'r') for line in f: line_list = line.strip().split("|") if line_list[0] == username and line_list[1] == password: return True return False def register(username, password): """ 用于用户注册 :param username: 用户名 :param password: 密码 :return: 默认None """ f = open("db", 'a') temp = "\n" + username + "|" + password f.write(temp) f.close() def main(): t = input("1:登录;2:注册") if t == "1": user = input("请输入用户名:") pwd = input("请输入密码:") r = login(user, pwd) if r: print("登录成功") else: print("登录失败") elif t == "2": user = input("请输入用户名:") pwd = input("请输入密码:") register(user, pwd) main()
1.3 内置函数
官网:http://data.digitser.net/python_3.4.2/zh-CN/library/functions.html
如何查看Python当前版本的内置函数有哪些,可以用下面的指令查看:
C:\Users\Administrator>python
Python 2.7.11 (v2.7.11:6d1b6a68f775, Dec 5 2015, 20:32:19) [MSC v.1500 32 bit (
Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> dir(sys.modules['__builtin__'])
Python 2.x内置函数列表
地址:http://python.usyiyi.cn/python_278/library/functions.html
Python 3.x 内置函数列表
地址:http://python.usyiyi.cn/python_343/library/functions.html
'__package__', 'abs','all', 'any', 'apply', 'basestring', 'bin', 'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip']
# abs--求绝对值 >>> print(abs(100)) 100 >>> print(abs(-100)) 100 # all--集合中的元素都为真的时候为真 >>> n = all([1,2,3,None]) >>> print(n) False >>> n = all([1,2,3,34]) >>> print(n) True # any--集合中的元素有一个为真的时候为真 常见为假的对象:[],{},None,0,"",() >>> n = any([[],0,"",None]) # 全为假 >>> print(n) False >>> n = any([[],0,"",1]) # 1 为真 >>> print(n) True # cmp(x,y)--如果x < y ,返回负数;x == y, 返回0;x > y,返回正数 # ascii--自动执行对象的 __repr__ python 2.7没有 Python 3.0才有 >>> class Foo: ... def __repr__(self): ... return "444" ... >>> n = ascii(Foo()) >>> print(n) 444 # apply--过期不再叙述 # basestring--str和unicode的超类,不能直接调用,可以用作isinstance判断 # bin--将一个整数转换成一个二进制字符串 # oct--将整数x转换为八进制字符串 # hex-- 将整数x转换为十六进制字符串 >>> n = 20 >>> print(bin(n)) 0b10100 >>> print(oct(n)) 0o24 >>> print(hex(n)) 0x14 # bool--将x转换为Boolean类型 # buffer--过期的内置函数,故不说明 # bytearray--过期的内置函数,故不说明 # bytes--字符串转字节类型(重点) >>> n = bytes("李杰", encoding="utf-8") >>> print(n) b'\xe6\x9d\x8e\xe6\x9d\xb0' >>> n = bytes("李杰", encoding="gbk") >>> print(n) b'\xc0\xee\xbd\xdc' # str--字节转化成字符串 >>> new_str = str(bytes("李杰", encoding="utf-8"), encoding="utf-8") >>> print(new_str) 李杰 # callable(object)--如果 object 参数可调用,返回True;否则返回False。如果返回True,仍有可能调用失败,但是如果返回False,调用object将永不成功 >>> def f1(): ... print(123) ... >>> f2 = 123 >>> print(callable(f1)) True >>> print(callable(f2)) False # chr()--返回整数i对应的ASCII字符 # ord()--返回ASCII字符对应的整数 # 应用案例:生成一个随机的6位验证码,包含大写字母、数字 最终版本: import random li = [] # 使用列表用于存储完整的验证码 for i in range(6): # 用于生成六位的验证码 r = random.randrange(0, 5) # 在0-6位的验证码中,随机生成一个数字,用于指定验证码的第几个位用于生成数字序列 if r == 2 or r == 4 : # 进行判断,如果为指定行,则进行如下操作 num = random.randrange(0, 10) # 用于在指定序列的生成随机数,即生成1-9之间的一个数字 li.append(str(num)) # 将生成的随机数字存放到列表中 else: tmp = random.randrange(65, 91) # 用于在指定序列的生成随机数 c = chr(tmp) # ascii数字-->大写字母 li.append(c) # 将生成的随机大写字母存放到列表中 result = "".join(li) # 将列表拼接成字符串 print("你的随机验证码:", result) # classmethod(function)--将function包装成类方法 暂时无需了解 # compile()--把字符串编译为Python代码 # eval()--执行Python表达式 有返回值 子集 # exec()--执行Python代码或者字符串 没有返回值 父集 >>> s = "print(123)" >>> r = compile(s, "<string>", "exec") # 将字符串编译成Python代码 编译,single,eval,exec >>> print(r) <code object <module> at 0x02A2C5C0, file "<string>", line 1> >>> exec(r) # 执行代码 123 >>> s = "8*8" >>> res = eval(s) >>> print(res) 64 # complex()--返回一个复数 # delattr()--删除object对象名为name的属性 # hasattr(object, name) # setattr() # getattr(object, name[, default])--返回object的属性值 # divmod(a,b)--参数为两个数值(非复数),返回它们相除后的的商和余数 应用场景:博客分页 (重要) >>> r = divmod(97, 10) >>> print(r) (9, 7) >>> n1, n2 = divmod(97, 10) >>> print(n1, n2) 9 7 # enumerate(iterable, start=0)--返回一个枚举对象。iterable 必须是序列、迭代器,或者其他支持迭代的对象 # exit()--退出 # filter(函数,可迭代的对象)--函数返回Ture,将元素添加到结果中 # 需求:有一个列表,要进行筛选,大于22的返回给我
# 自定义方法实现
def f1(args):
result = []
for item in args:
if item > 22:
result.append(item)
return result
li = [11, 22, 33, 44, 55]
ret = f1(li)
print(ret)
# 通过filter功能实现需求 def f2(a): if a > 22: return True li = [11, 22, 33, 44, 55] res = filter(f2, li) print(list(res)) # filter和lambda实现需求 li = [11, 22, 33, 44, 55, ] result = filter(lambda a: a > 33, li) print(list(result)) # float--将一个字符串或数转换为浮点数。如果无参数将返回0.0 # format--格式化输出字符串,格式化的参数顺序从0开始,如“I am {0},I like {1}” # frozenset()--内置类,暂时忽略 # locals()--更新并返回表示当前局部符号表的字典。当locals在函数块中而不是类块中被调用时,locals()返回自由变量 # globals()--返回表示当前全局符号表的字典。它总是当前模块的字典(在函数或者方法中,它指定义的模块而不是调用的模块) NAME = "ALEX" def f1(): age = 10 return NAME, age print(f1()) print(locals()) print(globals()) # hash()--返回对象的hash值, 应用场景:字典的key值进行hash,存hash值作为字典key,其他语言也适用 s = "adsafsd" print(hash(s)) # help()--获取详细帮助信息 # dir()--返回对象的功能方法列表 # id()--返回对象的唯一标识 # input([prompt])--如果有prompt参数,则将它输出到标准输出且不带换行。该函数然后从标准输入读取一行,将它转换成一个字符串(去掉一个末尾的换行符),然后返回它 # int()--返回一个由数值或字符串 x 转换而成的整数,如果省略参数,则返回 0 # isinstance()--判断对象是否是某个类的实例,与type()区别 s = "alex" print(isinstance(s, str)) print(isinstance(s, list)) # issubclass--如果class是classinfo的子类(直接的,间接的,或者virtual) ,返回真。忽略 # iter(object[, sentinel])--返回一个iterator对象 # len()--返回一个对象的长度 (元素的个数) . 参数可以是序列(如字符串,字节,元组,列表或者范围)或者集合(如字典,集合或者固定集合) s = "李杰" print(len(s)) # Python 3.x 默认按照字符统计,可以按照字节统计 结果:2 b = bytes(s, encoding="utf-8") # Python 3.x 也可以按照字节统计 结果:6 print(len(b)) print(len(s)) # Python 2.x 按照字节统计 结果:6
)
# Python 2.x
>>> name = "李杰"
>>> for i in name:
... print(i)
...
>>>
# Python 3.x
>>> name = "李杰"
>>> for i in name:
... print(i)
...
李
杰
# map(函数,可迭代的对象(可以for循环))--将函数返回值添加到结果中 # 需求:给一个列表,所有元素+100,返回给我。即:一批数据进行统一的一类操作
# 自己实现 li = [11, 22, 33, 44, 55, ] def f1(args): result = [] for i in args: result.append(100+i) return result print(f1(li)) # map实现 li = [11, 22, 33, 44, 55, ] def f1(a): return a + 100 result = map(f1, li) print(list(result)) # map和lambda功能实现 li = [11, 22, 33, 44, 55, ] result = map(lambda a: a + 100, li) result = map(f1, li) print(list(result))
[111, 122, 133, 144, 155]
# 其他应用场景:字符串,列表的应用
>>> li_list = ['shuaige','nihao',]
>>> result = map(lambda a: "%s is string" % a,li_list)
>>> print(list(result))
['shuaige is string', 'nihao is string']
>>> li_str = 'abcdefg'
>>> result = map(lambda a: "%s is string" % a,li_str)
>>> print(list(result))
['a is string', 'b is string', 'c is string', 'd is string', 'e is string', 'f i
s string', 'g is string']
# sum(iterable[, start])--将start以及iterable的元素从左向右相加并返回总和。start默认为0 # max()--返回可迭代的对象中的最大的元素,或者返回2个或多个参数中的最大的参数 # min()--返回可迭代的对象中的最小的元素,或者返回2个或多个参数中的最小的参数
>>> r = sum([11,22,33,1])
>>> print(r)
67
>>> r = max([11,22,33,1])
>>> print(r)
33
>>> r = min([11,22,33,1])
>>> print(r)
1 # memoryview()--返回给定参数的“内存视图” # next() # object--返回一个新的无特征的对象 # open--文件操作(重点) # pow(x, y[, z])--返回x 的 y次方; 如果 z 提供的时候,返回 x 的 y 次方,然后对 z取模。(这样比 pow(x, y) % z) 更高效。 pow(x, y)的效果类似于: x**y. >>> print(2**10) 1024 >>> print(pow(2, 10)) 1024 # print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False) # 打印 objects 到文本流对象 file,以 sep 为分隔符,以 end 为结尾符。如果要提供 sep, end 和 file 这三个参数的话,必须使用键值对的形式
# property()--返回一个property 属性
# range(stop) # range(start, stop[, step])--返回一个指定范围内的不可变的序列 # xrange() # raw_input()--接收用户输入 Python 2.7.x # repr(object)--返回一个字符串 >>> r = repr("alex") >>> print(r) 'alex' # reversed(seq)--返回一个反向迭代器 >>> li = [11, 22, 1, 1, ] >>> li.reverse() >>> print(li) [1, 1, 22, 11] >>> li = [11, 22, 1, 1, ] >>> reversed(li) <list_reverseiterator object at 0x02A1F530> >>> print(list(reversed(li))) [1, 1, 22, 11] >>> print(li) [11, 22, 1, 1] # round(number[, ndigits])--返回浮点数 number 四舍五入到小数点之后 ndigits 位的结果 >>> r = round(1.9) >>> print(r) 2 >>> r = round(1.4) >>> print(r) 1 # type()--查看数据类型 # tuple()--元组 # set()--set集合 无序不重复 # list()--列表 # dict()--字典 # slice()--返回一个slice对象 http://i.cnblogs.com/EditArticles.aspx?postid=5515410&update=1 # sorted(iterable[, key][, reverse])--依据iterable中的元素返回一个新的列表 # staticmethod(function)--返回function的一个静态方法# super([type[, object-or-type]])--返回一个代理对象,这个对象指派方法给一个父类或者同类. # vars([object])--返回模块 # zip(*iterables)--利用每个可迭代元素,制作一个迭代器来聚合元素。 >>> l1 = ["alex", 11, 22, 33] >>> l2 = ["is", 11, 22, 33] >>> l3 = ["sb", 11, 22, 33] >>> >>> r = zip(l1, l2, l3) >>> print(list(r)) [('alex', 'is', 'sb'), (11, 11, 11), (22, 22, 22), (33, 33, 33)] # __import__()
1.3.1 reduce(Python 2.x)
对于序列内所有元素进行累计操作
>>> li = [1,2,3,4,5,6,7,8] >>> result = reduce(lambda a1,a2:a1+a2,li) #累乘、除、加、减 >>> print result 36 # reduce的第一个参数,函数必须要有两个参数,因为他是两两进行操作 # reduce的第二个参数,要循环的序列 # reduce的第三个参数,初始值 #初始值 >>> li = [1,2,3,4,5,6,7,8] >>> result = reduce(lambda a1,a2:a1+a2,li,100000) #累乘、除、加、减 >>> print result 100036
默认参数:
常见的内置函数又分为如下几类,详细介绍参考:http://jianfeihit.iteye.com/blog/1835272
总结:
内置函数,一般都是因为使用频率比较频繁或是是元操作,所以通过内置函数的形式提供出来,通过对python的内置函数分类分析可以看出来:基本的数据 操 作基本都是一些数学运算(当然除了加减乘除)、逻辑操作、集合操作、基本IO操作,然后就是对于语言自身的反射操作,还有就是字符串操作,也是比较常用 的,尤其需要注意的是反射操作。
2、lambda表达式
学习条件运算时,对于简单的 if else 语句,可以使用三元运算来表示,即:
# 普通条件语句 if 1 == 1: name = 'wupeiqi' else: name = 'alex' # 三元运算 name = 'wupeiqi' if 1 == 1 else 'alex'
对于简单的函数,也存在一种简便的表示方式,即:lambda表达式
####################### 普通函数 ###################### # 定义函数(普通方式) >>> def func(arg): ... return arg + 1 ... # 执行函数 >>> result = func(123) >>> print(result) 124 ####################### lambda ###################### # 定义函数(lambda表达式) >>> my_lambda = lambda arg : arg + 1 # 执行函数 ... result = my_lambda(123) >>> print(result) 124
lambda存在意义就是对简单函数的简洁表示
3、yield生成器
3.1 yield介绍
您可能听说过,带有 yield 的函数在 Python 中被称之为 generator(生成器),何谓 generator ?我们先抛开 generator,以一个常见的编程题目来展示 yield 的概念。
如何生成斐波那契數列?
斐波那契(Fibonacci)數列是一个非常简单的递归数列,除第一个和第二个数外,任意一个数都可由前两个数相加得到。用计算机程序输出斐波那契數列的前 N 个数是一个非常简单的问题,许多初学者都可以轻易写出如下函数:
清单 1. 简单输出斐波那契數列前 N 个数
def fab(max): n, a, b = 0, 0, 1 while n < max: print b a, b = b, a + b n = n + 1
执行 fab(5),我们可以得到如下输出:
>>> fab(5) 1 1 2 3 5
结果没有问题,但有经验的开发者会指出,直接在 fab 函数中用 print 打印数字会导致该函数可复用性较差,因为 fab 函数返回 None,其他函数无法获得该函数生成的数列。要提高 fab 函数的可复用性,最好不要直接打印出数列,而是返回一个 List。以下是 fab 函数改写后的第二个版本:
清单 2. 输出斐波那契數列前 N 个数第二版
def fab(max): n, a, b = 0, 0, 1 L = [] while n < max: L.append(b) a, b = b, a + b n = n + 1 return L 可以使用如下方式打印出 fab 函数返回的 List: >>> for n in fab(5): ... print n ... 1 1 2 3 5
改写后的 fab 函数通过返回 List 能满足复用性的要求,但是更有经验的开发者会指出,该函数在运行中占用的内存会随着参数 max 的增大而增大,如果要控制内存占用,最好不要用 List来保存中间结果,而是通过 iterable 对象来迭代。例如,在 Python2.x 中,代码:
清单 3. 通过 iterable 对象来迭代
for i in range(1000): pass 会导致生成一个 1000 个元素的 List,而代码: for i in xrange(1000): pass
则不会生成一个 1000 个元素的 List,而是在每次迭代中返回下一个数值,内存空间占用很小。因为 xrange 不返回 List,而是返回一个 iterable 对象。利用 iterable 我们可以把 fab 函数改写为一个支持 iterable 的 class,以下是第三个版本的 Fab:
清单 4. 第三个版本
class Fab(object): def __init__(self, max): self.max = max self.n, self.a, self.b = 0, 0, 1 def __iter__(self): return self def next(self): if self.n < self.max: r = self.b self.a, self.b = self.b, self.a + self.b self.n = self.n + 1 return r raise StopIteration() Fab 类通过 next() 不断返回数列的下一个数,内存占用始终为常数: >>> for n in Fab(5): ... print n ... 1 1 2 3 5
然而,使用 class 改写的这个版本,代码远远没有第一版的 fab 函数来得简洁。如果我们想要保持第一版 fab 函数的简洁性,同时又要获得 iterable 的效果,yield 就派上用场了:
清单 5. 使用 yield 的第四版
def fab(max): n, a, b = 0, 0, 1 while n < max: yield b # print b a, b = b, a + b n = n + 1 ''' 第四个版本的 fab 和第一版相比,仅仅把 print b 改为了 yield b,就在保持简洁性的同时获得了 iterable 的效果。 调用第四版的 fab 和第二版的 fab 完全一致: ''' >>> for n in fab(5): ... print n ... 1 1 2 3 5
简单地讲,yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行 fab 函数,而是返回一个 iterable 对象!在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。
也可以手动调用 fab(5) 的 next() 方法(因为 fab(5) 是一个 generator 对象,该对象具有 next() 方法),这样我们就可以更清楚地看到 fab 的执行流程:
清单 6. 执行流程
>>> f = fab(5) >>> f.next() 1 >>> f.next() 1 >>> f.next() 2 >>> f.next() 3 >>> f.next() 5 >>> f.next() Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
当函数执行结束时,generator 自动抛出 StopIteration 异常,表示迭代完成。在 for 循环里,无需处理 StopIteration 异常,循环会正常结束。
我们可以得出以下结论:
一个带有 yield 的函数就是一个 generator,它和普通函数不同,生成一个 generator 看起来像函数调用,但不会执行任何函数代码,直到对其调用 next()(在 for 循环中会自动调用 next())才开始执行。虽然执行流程仍按函数的流程执行,但每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。
yield 的好处是显而易见的,把一个函数改写为一个 generator 就获得了迭代能力,比起用类的实例保存状态来计算下一个 next() 的值,不仅代码简洁,而且执行流程异常清晰。
如何判断一个函数是否是一个特殊的 generator 函数?可以利用 isgeneratorfunction 判断:
清单 7. 使用 isgeneratorfunction 判断
>>> from inspect import isgeneratorfunction >>> isgeneratorfunction(fab) True
要注意区分 fab 和 fab(5),fab 是一个 generator function,而 fab(5) 是调用 fab 返回的一个 generator,好比类的定义和类的实例的区别:
清单 8. 类的定义和类的实例
>>> import types >>> isinstance(fab, types.GeneratorType) False >>> isinstance(fab(5), types.GeneratorType) True fab 是无法迭代的,而 fab(5) 是可迭代的: >>> from collections import Iterable >>> isinstance(fab, Iterable) False >>> isinstance(fab(5), Iterable) True 每次调用 fab 函数都会生成一个新的 generator 实例,各实例互不影响: >>> f1 = fab(3) >>> f2 = fab(5) >>> print 'f1:', f1.next() f1: 1 >>> print 'f2:', f2.next() f2: 1 >>> print 'f1:', f1.next() f1: 1 >>> print 'f2:', f2.next() f2: 1 >>> print 'f1:', f1.next() f1: 2 >>> print 'f2:', f2.next() f2: 2 >>> print 'f2:', f2.next() f2: 3 >>> print 'f2:', f2.next() f2: 5
return 的作用
在一个 generator function 中,如果没有 return,则默认执行至函数完毕,如果在执行过程中 return,则直接抛出 StopIteration 终止迭代。
另一个例子
另一个 yield 的例子来源于文件读取。如果直接对文件对象调用 read() 方法,会导致不可预测的内存占用。好的方法是利用固定长度的缓冲区来不断读取文件内容。通过 yield,我们不再需要编写读文件的迭代类,就可以轻松实现文件读取:
清单 9. 另一个 yield 的例子
def read_file(fpath): BLOCK_SIZE = 1024 with open(fpath, 'rb') as f: while True: block = f.read(BLOCK_SIZE) if block: yield block else: return
以上仅仅简单介绍了 yield 的基本概念和用法,yield 在 Python 3 中还有更强大的用法,我们会在后续文章中讨论。
注:本文的代码均在 Python 2.7 中调试通过
3.2 range和xrange的区别
# Python 2.x >>> print(range(10)) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> print(xrange(10)) xrange(10)
# range会在内存中创建所有指定的数字,而xrange不会立即创建,只有在迭代循环时,才去创建每个数组
# Python 3.x >>> print(range(10)) range(0, 10) >>> print(xrange(10)) Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'xrange' is not defined
http://i.cnblogs.com/EditArticles.aspx?postid=5515410&update=1
3.3 文件操作的read和xreadlinex的区别
xreadlines则只有在循环迭代时才获取
def func():
print("111")
yield 1
print("222")
yield 2
print("333")
yield 3
ret = func()
# print(list(ret))
r1 = ret.__next__() # 执行到 yield 1 停止
print(r1)
r2 = ret.__next__() # 执行到 yield 2 停止
print(r2)
r3 = ret.__next__() # 执行到 yield 3 停止
print(r3)
# 结果
111
1
222
2
333
3
def my_range(arg):
start = 0
while True:
if start > arg:
return
yield start
start += 1
ret = my_range(4)
r1 = ret.__next__()
print(r1)
r1 = ret.__next__()
print(r1)
r1 = ret.__next__()
print(r1)
结果:
0
1
2
#######基础平台函数库######### def func1(): print('功能1') def func2(): print('功能2') def func3(): print('功能3') def func4(): print('功能4') # 测试组 def func1() def func2() def func3() # 设计组 def func1() def func2() def func3()
需求:基础平台函数库的调用要添加验证机制,只能验证通过才能进行函数调用,在完成这个需求的前提下要满足如下条件
1)各个部门修改自己的代码
2)在每个部门实行的功能上添加最少的代码完成改造
3)追求开放封闭原则,尽可能的不改变原基础函数库内部实现的方法解决方案:利用装饰器功能解决该需求
def login(func): def inner(): # 验证1 # 验证2 # 验证3 return func() return inner
@login def func1(): print '功能1' @login def func2(): print '功能2' @login def func3(): print '功能3' @login def func4(): print '功能4'
当各个组执行各自功能的时候,可以先调用基础平台提供的装饰器函数,完成验证需求
def login(func): def inner(): # 验证1 return func() return inner @login def func1(): print('功能1')
功能:
1. 自动执行login函数并且将其下面的函数名func1当作参数传递
2. 将login函数的返回值,重复赋值给 func1
当调用功能1的时候 会先把功能1的函数名带入内存地址,之后会执行login函数,func为功能1,之后inner会将功能1的参数带入等待执行inner的验证功能后,会将参数交给func执行功能1的命令。
# 装饰器如何装饰多个参数个数不同的函数 def outer(func): def inner(*args, **kwargs): print("func before") result = func(*args, **kwargs) print("func after") return result return inner @outer def f1(arg): print(arg) # return "f1函数返回值" @outer def f2(arg1,arg2): print(arg1,arg2) # return "f1函数返回值"
LOGIN_USER = {"is_login": False} def outer(func): def inner(*args, **kwargs): if LOGIN_USER['is_login']: r = func() return r else: print("请登录") return inner def outer1(func): def inner(*args, **kwargs): if LOGIN_USER['is_login'] and LOGIN_USER['user_type'] == 2: r = func() return r else: print("请登录,或者权限不够") return inner @outer1 def order(): print("欢迎%s登录" % LOGIN_USER['current_user']) @outer def changepwd(): print("欢迎%s登录" % LOGIN_USER['current_user']) @outer def manager(): print("欢迎%s登录" % LOGIN_USER['current_user']) def login(user, pwd): if user == "alex" and pwd == "123": LOGIN_USER['is_login'] = True LOGIN_USER['current_user'] = user manager() def main(): while True: inp = input("1,后台管理;2,登录") if inp == '1': manager() elif inp == '2': username = input("请输入用户名") pwd = input("请输入密码") login(username, pwd) if __name__ == '__main__': main()
# 执行结果:
USER_INFO = {} def check_login(func): def inner(*args, **kwargs): if USER_INFO.get("is_login", None): # ret = func(*args, **kwargs) func(*args, **kwargs) else: print("请先登录") return inner def check_admin(func): def inner(*args, **kwargs): if USER_INFO.get("user_type", None): # ret = func(*args, **kwargs) func(*args, **kwargs) else: print("请管理员") return inner def login(): print("登录成功") USER_INFO["is_login"] = True @check_login def home(): print("普通查看信息") @check_login @check_admin def admin(): print("管理员权限") def main(): while True: choice_num = input("1、登录 2、查看信息 3、管理员权限 请选择") if choice_num == "1": login() elif choice_num == "2": home() elif choice_num == "3": admin() if __name__ == '__main__': main()
特点:
1)访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容
2)不能随机访问集合中的某个值 ,只能从头到尾依次访问
3)访问到一半时不能往回退
4)便于循环比较大的数据集合,节省内存
>>> a = iter([1,2,3,4]) >>> a.__next__() 1 >>> a.__next__() 2 >>> a.__next__() 3 >>> a.__next__() 4 >>> a.__next__() Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
需求:请按照从小到大对列表 [13, 22, 6, 99, 11] 进行排序
思路:相邻两个值进行比较,将较大的值放在右侧,依次比较!
7、递归
特点
递归算法是一种直接或者间接地调用自身算法的过程。在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解。
递归算法解决问题的特点:
(1) 递归就是在过程或函数里调用自身。
(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
(3) 递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。所以一般不提倡用递归算法设计程序。
(4) 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。所以一般不提倡用递归算法设计程序。
要求
递归算法所体现的“重复”一般有三个要求:
一是每次调用在规模上都有所缩小(通常是减半);
二是相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入);
三是在问题的规模极小时必须用直接给出解答而不再进行递归调用,因而每次递归调用都是有条件的(以规模未达到直接解答的大小为条件),无条件递归调用将会成为死循环而不能正常结束。
斐波那契数列指的是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368
>>> def func(arg1, arg2): ... if arg1 == 0: ... print(arg1, arg2) ... arg3 = arg1 + arg2 ... print(arg3) ... if arg3 < 1000: ... func(arg2, arg3) ... >>> func(0, 1) 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
def func(n): print(n) n += 1 if n >= 4: return "end" return func(n) r = func(1) print(r) 结果: 1 2 3 end
案例3:实现 1*2*3*4*5*6
>>> def fact(n): ... if n == 1: ... return 1 ... return n*fact(n-1) ... >>> >>> res = fact(3) >>> print(res) 6
出处:http://www.cnblogs.com/madsnotes/
声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。