一函数基础
1.1 函数分类
a.内置函数:为了方便我们的开发,针对一些简单的功能,python解释器已经为我们定义好了的函数即内置函数。对于内置函数,我们可以拿来就用而无需事先定义,如len(),sum(),max()
b.自定义函数:很明显内置函数所能提供的功能是有限的,这就需要我们自己根据需求,事先定制好我们自己的函数来实现某种功能,以后,在遇到应用场景时,调用自定义的函数即可。
1.2 定义函数
#语法 def 函数名(参数1,参数2,参数3,...): '''注释''' 函数体 return 返回的值
#1、无参:应用场景仅仅只是执行一些操作,比如与用户交互,打印
#2、有参:需要根据外部传进来的参数,才能执行相应的逻辑,比如统计长度,求最大值最小值
#3、空函数:设计代码结构
1.3 调用函数
1 语句形式:foo()
2 表达式形式:3*len('hello')
3 当中另外一个函数的参数:range(len('hello'))
函数练习:
''' 1、写函数,,用户传入修改的文件名,与要修改的内容,执行函数,完成批了修改操作 ''' import os def foo(x,y,z): ''' :param x: 文件名 :param y: 修改的内容 :return: ''' with open(x,'r')as f_read,open('tmp.txt','w')as f_write: for line in f_read: data=line.replace(y,z) f_write.write(data) os.remove(x) os.rename('tmp.txt',x) foo('a.txt','ha','yi')
''' 2、写函数,计算传入字符串中【数字】、【字母】、【空格] 以及 【其他】的个数 ''' def foo(a): n_num=0 n_word=0 n_space=0 n_other=0 for word in a: if word.isdigit():n_num+=1 elif word.isalpha():n_word+=1 elif word==' ':n_space+=1 else:n_other+=1 print(word) print(n_num,n_word,n_space,n_other) foo('123 wef wd23!2')
''' 3、写函数,判断用户传入的对象(字符串、列表、元组)长度是否大于5。 ''' def func(a): if len(a)>5:return True else:return False print(func('23rsdsd2'))
''' 4、写函数,检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。 ''' def func(a): while True: if type(a)!=list: print('list please!') else:break if len(a)>=2: data=a[0:2] else:data=a print(data) func([12,])
''' 5、写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者。 ''' def func(a): l=[] for x in a: if a.index(x)%2!=0: l.append(x) return l print(func(['qef','123','asdf','dcsc','csdcd']))
''' 6、写函数,检查字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。 dic = {"k1": "v1v1", "k2": [11,22,33,44]} PS:字典中的value只能是字符串或列表 ''' def func(dic): for key in dic: if len(dic[key])>=2: new_value=dic[key][0:2] dic.pop(key) dic[key]=new_value return dic print(func( {"k1": "v1v1", "k2": [11,22,33,44]}))
1.4 函数对象
#1 可以被引用 #2 可以当作参数传递 #3 返回值可以是函数 #3 可以当作容器类型的元素
#取代多分支if语句def foo(): print('foo') def bar(): print('bar') dic={ 'foo':foo, 'bar':bar, } while True: choice=input('>>: ').strip() if choice in dic: dic[choice]()
1.5 函数嵌套
def max1(x,y): return x if x>y else y def max4(a,b,c,d): res1=max1(a,b) res2=max1(c,d) res=max1(res1,res2) return res print(max4(1,2,3,4))
# 函数的嵌套定义 def f1(): def f2(): def f3(): print('from f3') f3() f2() f1()
1.6 名称空间和作用域
名称空间:存放名字的地方。局部名称空间,全局名称空间,内置名称空间
名字的查找顺序:局部名称空间--->全局名称空间-->内置名称空间
名称空间的加载顺序:
python test.py #1、python解释器先启动,因而首先加载的是:内置名称空间 #2、执行test.py文件,然后以文件为基础,加载全局名称空间 #3、在执行文件的过程中如果调用函数,则临时产生局部名称空间
作用域即范围
- 全局范围(内置名称空间与全局名称空间属于该范围):全局存活,全局有效
- 局部范围(局部名称空间属于该范围):临时存活,局部有效
查看作用域:globals(),locals()
LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__
locals 是函数内的名字空间,包括局部变量和形参
enclosing 外部嵌套函数的名字空间(闭包中常见)
globals 全局变量,函数定义所在模块的名字空间
builtins 内置模块的名字空间
二.闭包函数和装饰器
2.1 闭包函数
定义在函数内部的函数,特点是,包含对外部作用域而不是对全局作用域名字的引用。
from urllib.request import urlopen def get(url): def inner(): return urlopen(url).read() return inner baidu=get('http://www.baidu.com') baidu()闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
2.2 装饰器
1.为什么要用装饰器:开放封闭原则,对扩展是开放的,对修改是封闭的
2.什么是装饰器
-用来装饰它人,装饰器本身可以是任意可调用对象,被装饰器的对象也可以是任意可调用对象。
-遵循的原则:1.不修改被装饰对象的源代码 2.不修改被装饰对象的调用方式
-目标是:在遵循原则1和2的前提,为被装饰对象添加新功能
从普通的函数逐渐加入装饰器的过程(不修改原函数代码,不修改调用方式):
def get_up(): '''描述睡觉起床过程''' print('睡他妈的觉') time.sleep(random.randint(2,4)) print('起他妈的床') def wash(): '''描述洗漱过程''' print('洗他妈的脸') time.sleep(random.randint(1,3)) print('刷他妈的牙')
def count_time(fun): def wraper(): start_time=time.time() fun() fin_time=time.time() print(fin_time-start_time) return wraper def get_up(): '''描述睡觉起床过程''' print('睡他妈的觉') time.sleep(random.randint(2,4)) print('起他妈的床') def wash(): '''描述洗漱过程''' print('洗他妈的脸') time.sleep(random.randint(1,3)) print('刷他妈的牙') get_up=count_time(get_up) #也就是返回的wraper ------fun=get_up get_up()
import time,random def count_time(fun): def wraper(): start_time=time.time() fun() fin_time=time.time() print(fin_time-start_time) return wraper #get_up=count_time(get_up) #也就是返回的wraper ------fun=get_up @count_time def get_up(): '''描述睡觉起床过程''' print('睡他妈的觉') time.sleep(random.randint(2,4)) print('起他妈的床') @count_time def wash(): '''描述洗漱过程''' print('洗他妈的脸') time.sleep(random.randint(1,3)) print('刷他妈的牙') get_up() wash()
import time,random def count_time(fun): def wraper(*args,**kwargs): start_time=time.time() fun(*args,**kwargs) fin_time=time.time() print(fin_time-start_time) return wraper #get_up=count_time(get_up) #也就是返回的wraper ------fun=get_up @count_time def get_up(name): '''描述睡觉起床过程''' print('睡他妈的觉%s'%name) time.sleep(random.randint(2,4)) print('起他妈的床%s'%name) @count_time def wash(): '''描述洗漱过程''' print('洗他妈的脸') time.sleep(random.randint(1,3)) print('刷他妈的牙') get_up('hantao') wash()
import time,random def count_time(fun): def wraper(*args,**kwargs): start_time=time.time() res=fun(*args,**kwargs) fin_time=time.time() print(fin_time-start_time) return res return wraper #get_up=count_time(get_up) #也就是返回的wraper ------fun=get_up @count_time def get_up(name): '''描述睡觉起床过程''' print('睡他妈的觉%s'%name) time.sleep(random.randint(2,4)) print('起他妈的床%s'%name) return '开心的一天开始了' @count_time def wash(): '''描述洗漱过程''' print('洗他妈的脸') time.sleep(random.randint(1,3)) print('刷他妈的牙') res=get_up('hantao') wash() print(res)
import time def index(): time.sleep(2) print('welcome to index page!') def timer(func): def inner(): start_time=time.time() func() stop_time=time.time() print(stop_time-start_time) return inner index=timer(index) index()
def timer(func): def inner(): start_time=time.time() func() stop_time=time.time() print(stop_time-start_time) return inner @timer def index(): time.sleep(2) print('welcome to index page!') index()
#无参装饰器import time from functools import wraps def timmer(func): @wraps(func) def inner(*args,**kwargs): start_time=time.time() res=func(*args,**kwargs) stop_time=time.time() print('run time is :%s'%(stop_time-start_time)) return res return inner @timmer def index(): time.sleep(2) print('welcom to index!') return 'index' @timmer def home(name): time.sleep(3) print('welcome %s to home'%name) return 'home' index() home('hantao') print(index()) print(home('hantao'))
#有参装饰器 import time current_status={'user':None,'status':False} def auth(egine='file'): def wrapper(func): def inner(*args,**kwargs): if current_status['user'] and current_status['status']: res=func(*args,**kwargs) return res if egine=='file': name=input('username>>:').strip() pwd=input('password>>:').strip() if name=='hantao'and pwd=='123': print('login successful!') current_status['user']=name current_status['status']=True res=func(*args,**kwargs) return res elif egine=='mysql': print('mysql') else:pass return inner return wrapper @auth(egine='file') #@wrapper #index=wrapper(index) def index(): time.sleep(2) print('welcom to index!') return 'index' index()
''' 编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码 ''' from functools import wraps auth_status={'user':None,} def auth(engine='file'): def wrapper(func): @wraps(func) def inner(*args,**kwargs): if engine=='file': with open('aaa')as read_f: userinfo=eval(read_f.read()) else: pass while True: if auth_status.get('user'):break username=input('username:').strip() password=input('password:').strip() with open('aaa')as read_f: if username == userinfo.get('name') and password==userinfo.get('password'):break res=func(*args,**kwargs) return res return inner return wrapper @auth(engine='file') def index(x): print(x) index('hantao')
#编写装饰器,为多个函数加上认证功能,要求登录成功一次,在超时时间内无需重复登录,超过了超时时间,则必须重新登录 from functools import wraps import time auth_status={'user':None,'auth_time':None} def auth(engine='file'): def wrapper(func): @wraps(func) def inner(*args,**kwargs): with open('aaa')as read_f: userinfo=eval(read_f.read()) while True: if auth_status.get('user') and time.time()-auth_status['auth_time']<10:break username=input('username:').strip() password=input('password:').strip() if username == userinfo.get('name') and password==userinfo.get('password'): auth_status['user']=username auth_status['auth_time']=time.time() break res=func(*args,**kwargs) return res return inner return wrapper @auth(engine='file') def index1(x): time.sleep(3) print(x) time.sleep(8) @auth(engine='file') def index2(x): print(x) index1('hantao') index2('hantao')
三.迭代器和生成器
3.1 迭代器
1.什么叫迭代:迭代是一个重复过程,每次重复都是基于上一次的结果来的
2.为什么用迭代器?
-对于序列类型:字符串,列表,元祖,可以基于索引的迭代取值方式,而对于没有索引的类型,入字典、集合、文件,这种方式不适用,于是我们必须找出一种能不依赖与索引的取值方式,这就是迭代器。
3.可迭代对象:只要对象内置有__iter__方法,obj.__iter__(字符串,列表,元祖,字典,集合,文件)
4.迭代器对象:对象既内置有__iter__方法,又内置有__next__,如文件对象
注意:可迭代对象不一定是迭代器对象,而迭代器对象一定是可迭代的对象
list=[1,2,3,4] #可迭代对象 list_item=list.__item__() #一个迭代器对象 list_item.__next__() #相当于next(list__item) 不依赖所有取值
#for循环就是将被循环对象执行__item__()方法,进行next()操作,进行取值
dic={'a':1,'b':2,'c':3} iter_dic=dic.__iter__() while True: try: print(next(iter_dic)) except StopIteration: break
迭代器的优缺点:
-优点:
提供了一种统一的迭代取值方式,该方式不再依赖于索引
更节省内存(迭代器只是一个内存地址连接到文件,next()取值到内存)
-缺点:
无法统计长度
一次性的,只能往后走,不能往后退,无法获取指定位置的值
from collections import Iterable,Iterator print(isinstance([1,2,3],Iterable)) print(isinstance([1,2,3],Iterator))
3.2 生成器
''' 定义:只要函数内部出现yield关键字,那么再调用该函数,将不会立即执行函数体代码,会得到一个结果 该结果就是生成器对象 ''' def fun(): print('first') yield 1 print('second') yield 2 print('third') yield 3 g=fun()********************************************************************************** #生成器本质就是迭代器'''next() 在生成器的实质是: 1.让函数继续运行,直到运行到yield停止。 2.将yield的值返回到next()'''print(next(g))print(next(g)) for i in g: print(i)********************************************************************************* ''' yield的功能: -为我们提供了一种自定义迭代器的方式 -对比return,可以返回多次值,挂起函数的运行状态 '''********************************************************************************** #利用生成器实现range()方法 def my_range(start,stop,step=1): while start<stop: yield start start+=step g=my_range(1,5) print(next(g)) print(next(g)) print(next(g)) for i in my_range(1,1342341,step=2): print(i)
import time def tail(filepath): with open(filepath,'rb')as read_f: read_f.seek(0,2) while True: read_line=read_f.readline() if read_line: yield read_line.decode('utf-8') else: time.sleep(0.2) def grep(pattern,lines): lines=tail('access.log') for line in lines: if pattern in line: print(line,end='') grep('404',tail('access.log'))
#协程函数 #yield的表达式形式用法 def eat(name): food_list=[] print('%s开始吃了'%(name)) while True: food=yield food_list print('%s正在吃%s'%(name,food)) food_list.append(food) g_eat=eat('喵') ''' send的作用: 1.next()的作用 2.向yield传值 3.要注意的是第一次要先send(None) == next() ''' print(g_eat.send(None)) print(g_eat.send('猫粮')) print(g_eat.send('小鱼干')) print(g_eat.send('猫罐头')) g_eat.close() print(g_eat.send('狗粮'))
四.面向过程编程
定义:面向过程的核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么 基于面向过程设计程序就好比在设计一条流水线,是一种机械式的思维方式
优点:复杂的问题流程化,进而简单化
缺点:可扩展性差
五.三元表达式,列表推导式,生成器表达式
5.1 三元表达式
name=input('>>:') if name == 'hantao': print('sb') else: print('nb') name=input('>>:') print('sb' if name=='hantao' else 'nb')
5.2 列表推导式
#语法 [expression for item1 in iterable1 if condition1 for item2 in iterable2 if condition2 ... for itemN in iterableN if conditionN #相当于 res=[] for item1 in iterable1: if condition1: for item2 in iterable2: if condition2 ... for itemN in iterableN: if conditionN: res.append(expression)
egg_list=[] for i in range(10): res='egg%s'%i egg_list.append(res) print(egg_list) l=['egg%s'%i for i in range(10) if i >=3] print(l)
names=['egon','alex_sb','wupeiqi','yuanhao'] names=[name.upper() for name in names if not name.endswith('sb')] print(names)
5.3 生成器表达式
#把列表推导式的[]换成()就是生成器表达式 l=('hantao%s'%i for i in range(10) if i>=3) print(l) print(next(l)) print(next(l)) print(next(l)) #优点:省内存,一次只产生一个值在内存中
六. 函数递归与二分法
#函数递归调用:在调用一个函数的过程中直接或间接的调用该函数本身,称之为函数的递归调用 import sys sys.setrecursionlimit(3000) count=1 def func1(): global count print('func1',count) count+=1 func1() func1()
#递归分为两个重要的阶段:递推+回溯 def age(n): if n==1: return 18 return age(n-1)+2 res=age(12) print(res)
#总结递归调用 #1:进入下一次递归时,问题的规模必须降低 #2:递归调用必须要有一个明确的约束条件 #3:在python中没有尾递归优化,递归调用的效率就是不高 l=[1,2,[3,4,[5,6,[7,8]]]] def func(l): for i in l: if isinstance(i,list): func(i) else: print(i) func(l)
#二分法 l=[1,2,4,8,11,15,19,23,38,80,123,234,345,456,567,678,789] #从小到大排列的数字列表 def get(num,l): print(l) if len(l)>0: mid=len(l)//2 if num>l[mid]: #in right l=l[mid+1:] elif num<l[mid]: #in left l=l[:mid] else: print('find it') return get(num, l) else: print('not exists') get(68,l)
l=[1,2,4,6,9] def search(num,l,start=0,stop=len(l)-1): if start <= stop: mid=start+(stop-start)//2 if num > l[mid]: start=mid+1 elif num< l[mid]: stop=mid-1 else: print(mid) return search(num,l,start,stop) else: print('meiyou') search(6,l)
七.匿名函数lambda
7.1 语法
#匿名函数没有绑定名字的函数,没有绑定名字意味着只能用一次就会被回收 #所以匿名函数的应用场景就是,某个功能只用一次就结束了 def f1(n): res=n**2 return res lambda n:n**2
7.2 匿名函数和一些内置函数的配合使用
#lambda和max配合使用 #求最高工资 salary={'hantao':1000, 'mayun':500, 'xi':30} res=max(salary,key=lambda k:salary[k]) #key传入函数进行比较规则制定 print(res) #与min()函数用法相同
#lambda和sorted配合使用 salary={'hantao':1000, 'mayun':500, 'xi':30} print(sorted(salary,key=lambda k:salary[k],reverse=True))
#map 映射 l1=['hantao','mayun','xjp'] print(list(map(lambda x:x+'_主席',l1))) #reduce 进行处理 from functools import reduce print(reduce(lambda x,y:x+y,range(101))) #filter 过滤 l2=['hantao主席','mayun主席','xjp'] print(list(filter(lambda name:name.endswith('主席'),l2)))
来源:https://www.cnblogs.com/hantaozi430/p/7602957.html