Python 函数
一、函数
1、什么是函数:函数就是具备某一功能的工具
函数的使用必须遵循先定义、后调用的原则
事先准备工具的过程即函数的定义
拿来就用即为函数的调用
函数分为两大类:1、内置的函数 2、自定义的函数
2、为什么要用函数:
2.1 程序的组织结构不清晰、可读性差
2.2 日积月累冗余代码过多
2.3 程序的可扩展性极差
3、怎么用函数
3.1定义函数
3.1.1 语法
# def 函数名(参数1,参数2,参数3,...): # """ # 文档注释 # """ # code1 # code2 # code3 # ... # return 返回值
3.1.2 定义函数阶段发生哪些事:只检测语法,不执行代码
def foo(): # foo=函数的内存地址 print('first') print('sencod') print('asdfsadfasdfas') print('third') foo()
# # 定义阶段 def foo(): print('from foo') bar() def bar(): print('from bar') #调用阶段 foo()
3.1.3 定义函数的三种形式
1.无参函数
def bar(): print('from bar') bar()
2.有参函数
def func2(x,y): # x=1 # y=3 if x > y: print(x) else: print(y) func2(1,3)
3.空函数(做占位使用)
def foo(): pass
3.2调用函数
语法:函数名()
调用函数发生了:1、根据函数名找到函数的内存地址 2、函数的内存地址加括号可以触发函数体代码的执行
调用函数的三种方式:
3.2.1 语句
def f1(): print('from 1') f1()
3.2.2表达式
def max2(x,y): if x > y: return x else: return y res=max(1,2)*10 print(res)
3.2.3当做参数传给其他函数
def max2(x,y): if x > y: return x else: return y res=max2(max2(1,2),3) print(res)
4、函数的返回值
1、什么是函数的返回值:函数体代码运行的一个成果
return 值:
返回值没有类型限制、返回值没有个数限制
逗号分割多个值:返回一个元组
一个值:返回一个值
没有return:默认返回None
def login(): while True: username=input('name>>: ').strip() pwd=input('password>>:').strip() if username not in user_dic: print('not found') continue if pwd != user_dic[username]: print('pwd error') continue print('login successful') return username print(login())
# return是函数结束的标志: # 函数内可以有多个return,但只要执行一次,整个函数就立即结束,并且将return后的值当作本次调用的结果返回
二、函数的参数
1、函数的参数分为两大类:形参、实参
形参:指的是在定义函数时,括号指定的参数,本质就是变量名
实参:指的是在调用函数时,括号内传入的值,本质就是值
只有在调用函数时才会在函数体内发生实参(值)与形参(变量名)的绑定关系
该绑定关系只在调用函数时临时生效,在调用函数结束后就解除绑定
def foo(x,y): #x=1,y=2 print(x) print(y) # a=1 # b=2 # foo(a,b) foo(1,2)
2、位置参数
位置形参:在定义函数时,按照从左到右的顺序依次定义的形参称之为位置形参
ps:但凡是按照位置定义的形参,在调用函数时必须为其传值,多一个不行少一个也不行
位置实参:在调用函数时,按照从左到右的顺序依次传入的值
ps:传值是按照顺序与形参一 一对应
def foo(x,y,z): print(x,y,z) # foo(1,2) foo(1,2,3,4)#多传一个值 报错 # foo(1,2,3) foo(3,2,1)
3、关键字实参:
在调用函数时,按照key=value的形式定义的实参,称之为关键字实参
注意:
1、在传值时可以完全打乱顺序,但仍然能指定道姓地为指定的参数传值
2、可以在调用函数时,混合使用位置实参与关键字实参
但是位置实参必须跟在关键字实参左边
并且不能为一个形参重复传值
def register(name,sex,age): print(name) print(sex) print(age) register(sex='male',name='mogu',age=18)
register('mogu',age=18,sex='male')#混合使用
4、默认参数
在定义函数时,就已经为某些参数绑定值,称为默认参数
ps:1、在定义阶段就已经有值,意味在调用阶段可以不用传值
2、默认形参必须放在位置形参的后面
3、默认形参的值只在定义阶段生效一次,在函数定义之后发生的改动无效
4、默认形参的值通常应该是不可变类型
默认形参:大多数情况下值都一样
位置形参:大多数情况值都不同
def foo(x,y,z=3): print(x) print(y) print(z) foo(1,2) foo(1,2,4) #传值后改变了默认值
def register(name,age,sex='female'): print(name) print(sex) print(age) register('mogu',18) register('xiaohuochai',28) register('momo',19) register('张三',33,'male')
m=10 def foo(x,y,z=m): print('x:%s' %x) print('y:%s' %y) print('z:%s' %z) m=111111111 #定义阶段就是10 此更改无效 foo(1,2)
def foo(name,hobby,l=None): if l is None: l=[] l.append(hobby) print('%s 的爱好是 %s' %(name,l)) l1=[] foo('mogu','read',l1) #l1=['read'] foo('xiaomogu','movie') #l1=['read','music'] foo('nvhai',' 卖火柴') foo('张三','吹牛') foo('关二爷','耍大刀')
5、可变长度的参数
可变长度指的是在调用函数时,函数参数的个数可以不固定
然而实参终究是要为形参传值的,针对两种形式实参个数不固定,对应着形参也必须有两种解决方案
那就是 * 和 ** 来分别处理溢出位置实参与溢出关键字实参
5.1 * 会将溢出的位置实参存成元组,然后赋值给紧跟其后的变量名
5.1.1 形参中带 *
def foo(x,y,*z): #z=(3,4,5,6,7,8) print(x) print(y) print(z) foo(1,2,3,4,5,6,7,8)
5.1.2 形参中带* 实参中带 * ,窍门:但凡碰到实参中带* 都先将其打散成位置实参,然后考虑传值
def foo(x,y,*z): #z=(3,4,5,6,7,8) print(x) print(y) print(z) foo(1,2,[3,4,5,6,7,8]) #z=([3,4,5,6,7,8],) foo(1,2,*[3,4,5,6,7,8]) #foo(1,2,3,4,5,6,7,8)====>z=(3,4,5,6,7,8) foo(1,2,*'hello') #foo(1,2,'h','e','l','l','o') foo(1,*[2,3,4,5,6]) #foo(1,2,3,4,5,6)
5.1.3 实参中带 * 窍门同上
def foo(x,y,z): print(x,y,z) l = ['mogu', 'huochai', 'nvhai'] foo(*l) # foo('mogu', 'huochai', 'nvhai')
5.2 ** 会将溢出的关键字实参存成字典,然后赋值给紧跟其后的变量名
5.2.1 形参中带 **
def foo(x,y,m,n,**z): # print(x) print(y) print(m) print(n) print(z) foo(1,2,n=10,m=20,a=1,b=2,c=3)
5.2.2 形参中带 ** 实参中带 ** 窍门:但凡碰到实参中带** 都先将其打散成位置实参,然后考虑传值
def foo(x,y,**z): # print(x,y,z) foo(1,2,**{'a':1,'b':2,'c':2}) #foo(1,2,c=2,a=1,b=2) foo(1,**{'a':1,'b':2,'c':2,'y':111}) #foo(1,c=2,a=1,b=2,y=111)
5.2.3 实参中带**
def foo(x,y,z): print(x,y,z) foo(1,**{'y':111,'z':222}) #foo(1,y=111,z=222) foo(**{'z':1,'y':2,'x':3}) #foo(y=2,z=1,x=3)
6、 *args 和 **kwargs
可接收任意长度,任意格式的参数(ps:实参中:位置实参必须在关键字实参的左边)
def foo(*args,**kwargs): print(args,kwargs)#可完美转嫁 foo(任意长度,格式的实参)
#需要将外层函数的参数格式原封不动的转嫁给其内部调用的函数,就需要以下 def index(name,age,sex): print('name:%s age:%s sex:%s' %(name,age,sex)) def foo(*args,**kwargs): index(*args,**kwargs)#可完美转嫁 foo('mogu',sex='male',age=18)#虽然调用的是foo函数,但是需要遵循 index函数的参数规则
三、函数对象
函数是第一类对象,意味着函数可以当做数据去使用
def foo(): print('from foo')
引用
print(foo) func=foo print(func) func()
当做参数传给另外一个函数
def bar(x): #x=foo的内存地址 print(x) x() bar(foo)
当做函数的返回值
def bar(): return foo f=bar() # print(f is foo) f()
当作容器类型的元素
def f1(): print('from f1') def f2(): print('from f2') l=[f1,f2] #列表内全为函数体 print(l) l[1]() l[0]()
四、函数的嵌套调用
1、嵌套调用
在调用一个函数时,其内部的代码又调用其他的函数
def bar(): print('from bar') def foo(): print('from foo') bar() foo()
def max2(x,y): if x > y: return x else: return y # def max4(a,b,c,d): res1=max2(a,b) res2=max2(res1,c) res3=max2(res2,d) return res3 print(max4(1,2,3,4))
2、嵌套定义
在一个函数的内部又定义了另外一个函数
def f1(): x=1 def f2(): print('from f2') print(x) print(f2) f2() f1()
五、名称空间和作用域
1、什么是名称空间:名称空间是存放名字与值绑定关系的地方
要取到值必须通过名字才能找,而名字又在名称空间中存放着,所以取值时首先去名称空间中找名字
找到了名字自然拿到值的内存地址。
2、名称空间分为三种:
2.1 内置名称空间:存放的python解释器自带的名字
生命周期:在解释器启动时产生,在解释器关闭时回收
2.2 全局名称空间:除了内置的与局部的之外名字都属于全局名称空间
生命周期:在程序文件执行时就立刻产生,在程序执行完毕后就回收
x=1 y=2 def foo(): x=1 y=2 foo() if y > x: print(x) z=3 # 其中:x,y,foo,z都是全局名称空间中的名字
2.3 局部名称空间:存放的是函数内部定义的名字
生命周期:在调用时临时生效,在函数结束后立刻回收
len=100 # print(len) # 站在全局查找 def foo(): len=2222 print(len) #先在局部查找 foo()
加载顺序
内置名称空间--->全局名称空间--->局部名称空间
加载名称空间的目的是为了将名字与值的绑定关系存放起来
而存的目的是为了取,也就是当我们查找名字时,必然是在三者之一中找到
查找顺序
局部名称空间--->全局名称空间--->内置名称空间
基于当前所在位置往后查找
x=100 y=200 # 强调:函数的形参名属于局部名称空间 def foo(x,y): print(x,y) foo(1,2) #print结果为1,2
x=2222 def f1(): # x=1 def f2(): # x=2 print('from f2',x) f2() x=111 f1() #print结果为 from f2 111
x=2222 def f1(): # x=1 def f2(): x=2 #先在局部查找 print('from f2',x) f2() x=111 f1() #结果为 from f2 2
3、作用域
域指的是范围,作用域指的是作用范围
3.1.全局作用范围:包含内置名称空间与全局名称空间中的名字
特点:全局有效,全局存活
3.2.局部作用范围:包含局部名称空间中的名字
特点:局部有效,临时存活
x=1 def f1(): def f2(): def f3(): x=3 #函数此处有值 所有全局的x=1 并不会取 print(x) f3() f2() f1() #函数调用会先在函数内部寻找,所有结果为 3 # def foo(): print(x) foo() #而此处函数内部未定义x 所以会找全局 1
#如何打破函数层级带来的访问限制,让我能够在任意位置都可以访问到一个内部函数 # 基于函数对象的概念将一个内部函数返回(return)到全局使用,从而打破了函数的层级限制
3.3.函数的作用域关系是在函数定义阶段就已经固定死的,与函数的调用位置无关
即在调用函数时一定要跑到定义函数的位置寻找作用域关系
x=111 def outter(): x=33333 def inner(): print('from inner',x) # x=4444 #此处再定义会报错 return inner x=222 f=outter() #f=指向outter.locals.inner f() #结果为from inner 33333
3.4. global 和 nonlocal
global :在局部声明名字是来自全局的
x=1 def func(): global x #声明x为全局 x=2 #所以此处即修改了全局的x func() print(x) #结果为 2
nonlocal :声明变量来自当前层外层(必须在函数内)
x=222 def f1(): x=111 def f2(): # nonlocal x x=3 print('f2---->',x) #f2-----> 3 f2() print('f1---->',x) # f1-------> 111 f1() print('global------>',x) #global------> 222
x=222 def f1(): x=111 def f2(): nonlocal x x=3 print('f2---->',x) #f2-----> 3 f2() print('f1---->',x) # f1-------> 3 f1() print('global------>',x) #global------> 222
六、装饰器
一、闭包函数(函数体传值的新方式)
1、闭 -------->定义在函数内部的函数
2、包 -------->该内部函数包含对其外层函数作用域名字的引用
闭包函数通常需要结合函数对象的概念,将闭包函数返回到外部使用
#闭包函数基本形式 def outter(): x=1 def inner(): print(x) return inner
# 将值包给函数 import requests #导入爬虫模块 # def outter(url): # #url='https://www.jd.com' # def get(): # response=requests.get(url) # print(len(response.text)) # return get # # jd=outter('https://www.jd.com')#第一调用传入京东 # jd() # 以后调用只需要 jd加括号就能得到结果, 新的传值方式
二、装饰器
装饰指的是为被装饰对象添加新的功能
器指的工具
装饰器本身是任意可以调用的对象,被装饰对象也是任意可以调用的对象
ps:写一个函数用来为另一个函数添加新功能,需要遵循开放封闭原则(对修改是封闭的,对扩展是开放的)
1、不修改被装饰对象的源代码
2、不修改被装饰对象的调用方式
import time def index(): #被装饰对象 time.sleep(2) print('welcome to index page') # # index() #原先功能 def outter(func): #func=最原始index def wrapper(): start_time=time.time() func() #上方的index() 原先功能 stop_time=time.time() print('run time is %s' %(stop_time-start_time)) #加入新功能 return wrapper index=outter(index) #index=wrapper 加入新功能,并且调用方式没变 index()
import time def home(name): #有参 time.sleep(1) print('welcome %s to home page' %name) return 'lalala' def timmer(func): #func=最原始index def wrapper(*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 wrapper home=timmer(home) #home=warapper print(home('mogu'))
二、1、装饰器的语法糖
在被装饰对象正上方单独一行写上@装饰器名字
import time def timmer(func): #func=最原始index def wrapper(*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 wrapper @timmer #index=timmer(index) def index(): time.sleep(1) print('welcome to index page') return 'lalala' index()
import time current_userinfo={'user':None} def outter(func): def wrapper(*args,**kwargs): if current_userinfo['user']: return func(*args,**kwargs) user=input('please input you username: ').strip() pwd=input('please input you password: ').strip() if user == 'mogu' and pwd == '123': print('login successfull') # 保存登录状态 current_userinfo['user']=user res=func(*args,**kwargs) return res else: print('user or password error') return wrapper @outter # index=outter(index) def index(): print('welcome to index page') time.sleep(3) @outter #home=outter(home) def home(name): print('welecom %s ' %name) time.sleep(2) return 123 index() # wrapper() res=home('mogu') # res=wrapper('mogu')
二、2、添加多个装饰器
import time current_userinfo={'user':None} def timmer(func): #func=最原始的index指向的内存地址 def wrapper2(*args,**kwargs): print('wrapper2.....') start=time.time() res=func(*args,**kwargs) # func=最原始的index指向的内存地址 stop=time.time() print('run time is %s' %(stop - start)) return res return wrapper2 def outter(func): # func=wrapper2 def wrapper1(*args,**kwargs): print('wrapper1.....') if current_userinfo['user']: return func(*args,**kwargs) user=input('please input you username: ').strip() pwd=input('please input you password: ').strip() if user == 'mogu' and pwd == '123': print('login successfull') # 保存登录状态 current_userinfo['user']=user res=func(*args,**kwargs) # func=wrapper2 return res else: print('user or password err') return wrapper1 # 解释语法的时候应该自下而上 # 执行时则是自上而下 # 可以连续写多个装饰器,处于最顶层的装饰器先执行 @outter # index=outter(wrapper2) # index=wrapper1 @timmer # timmer(最原始的index指向的内存地址) ==>wrapper2 def index(): print('welcome to index page') time.sleep(3) index() #wrapper1()
二、3、有参数的装饰器
import time current_userinfo={'user':None} def auth(engine='file'):#参数代表认证模式 def outter(func): #func=最原始的index def wrapper(*args,**kwargs): if engine == 'file':#if判断认证模式 if current_userinfo['user']: return func(*args,**kwargs) user=input('please input you username: ').strip() pwd=input('please input you password: ').strip() if user == 'mogu' and pwd == '123': print('login successfull') # 保存登录状态 current_userinfo['user']=user res=func(*args,**kwargs) return res else: print('user or password err') elif engine == 'mysql': print('mysql 的认证机制') res = func(*args, **kwargs) return res elif engine == 'ldap': print('ldap 的认证机制') else: print('不支持该engine') return wrapper return outter @auth(engine='mysql') #@outter # index=outter(最原始的index) # index= wrapper def index(): print('welcome to index page') time.sleep(3) @auth(engine='ldap') def home(name): print('welecom %s ' %name) time.sleep(2) return 123 index() #warpper() home('蘑菇') #wrapper('蘑菇')
二、4、wraps装饰器
被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),为了不影响,Python的functools包中提供了一个叫wraps的decorator来消除这样的副作用。
#wraps作用将被装饰对象属性赋值给 装饰器的wrapper import time from functools import wraps def timmer(func): @wraps(func) def wrapper(*args,**kwargs): start=time.time() res=func(*args,**kwargs) stop=time.time() print('run time is %s' %(stop - start)) return res # wrapper.__doc__ = func.__doc__ # wrapper.__name__= func.__name__ return wrapper @timmer def index(): """ 这是一个index函数 :return: """ print('welcome to index page') time.sleep(1) return 123 print(help(index)) # index.__doc__ # print(index.__name__)
七、表达式,生成式
三元表达式
语法:【条件成立时的返回值】 + if 条件 + else【条件不成立时的返回值】
# res=条件成立时的返回值 if 条件 else 条件不成立时的返回值 def max2(x,y): if x > y: return x else: return y res=max2(1,2) x=10 y=2 res=x if x > y else y res=True if x > y else False print(res)
列表生成式
语法: i + for循环 可以跟 【条件】
# 原先列表生成 l=[] for i in range(10): if i > 3: l.append(i) print(l) #列表生成式 l1=[i for i in range(10) if i > 3] print(l1)
#原先操作列表 user=input('>>>:').strip() names=['hello world','hello dream','hello %s'%(user)] l=[] for name in names: if name.startswith('he'): l.append(name.upper()) names=l print(names) #列表生成式操作 user=input('>>>:').strip() names=['hello world','hello dream','hello %s'%(user)] names=[name.upper() for name in names if name.startswith('hello')] print(names)
字典生成式
info=[ ['name','mogu'], ('age',18), ['sex','male']] #将列表转成字典:方法一 d={} for item in info: d[item[0]] = item[1] print(d) #字典生成式 :方法二 d={item[0]:item[1] for item in info} print(d)
d={ 'name':'蘑菇', 'age':18, 'sex':'male' } d={k.upper():v for k,v in d.items()} print(d)
语法:同列表一样 用到 for循环操作时优先考虑生成式操作
八、函数的递归调用
在调用一个函数的过程中又直接或间接的调用了自身。
本质就是一个重复的过程,必须有两个明确的阶段
1、回溯:一层一层地递归调用下去,每进入一层问题的规模都应该有所减少
2、递推:递归必须有一个明确的结束条件,在满足该条件的情况下终止递归,往回一层一层地结束调用
#询问年龄,第一个人说我比第二个人大2岁,第二个人说我比第三个人大2岁,。。。第六个人说“我18岁” # age(6) = age(5) + 2 # age(5) = age(4) + 2 # age(4) = age(3) + 2 # age(3) = age(2) + 2 # age(2) = age(1) + 2 # age(1) = 18 # age(n) = age(n-1) + 2 #n > 1 # age(n) = 18 #n=1 # def age(n): if n == 1: #结束条件 return 18 return age(n-1) + 2 #基于上一次的结果调用自己 print(age(6))
# 将一个列表中包含的值全部取出 l=[1,[2,[3,[4,[5,[6,[7,[8,[9,]]]]]]]]] def tell(l): for item in l: if type(item) is list: #item 是列表 # 再次调用本身的逻辑,传入item tell(item) else: #item是单独的元素 print(item) tell(l)
#数字列表,数字是从小到大排列的 nums=[3,11,13,15,23,27,43,51,72,81,93,101] #算法:就是如何高效地解决某一个具体问题的方法 l1=[3,11,13,15,23,27] l2=[23,27] l3=[23] def binary_search(nums,find_num): print(nums) if len(nums) == 0: print('not exists') return mid_index=len(nums) // 2 if find_num > nums[mid_index]: # in the right nums=nums[mid_index+1:] # 重复调用本身的逻辑,传入新的nums binary_search(nums,find_num) elif find_num < nums[mid_index]: # in the left nums=nums[:mid_index] # 重复调用本身的逻辑,传入新的nums binary_search(nums,find_num) else: print('find it') binary_search(nums,94)
九、匿名函数
匿名函数lambda:临时用一次以后不再使用了。
#格式: def sum2(x,y): return x + y print(sum2) sum2=lambda x,y:x + y
wage={ 'I':3800, 'BOSS':9999999, 'friends':10000, 'web celebrity':1000000 } print(max(wage,key=lambda x:wage[x]))#匿名函数使用场景 最大 print(min(wage,key=lambda x:wage[x]))#最小 # 按照薪资高低排序人名 print(sorted(wage,key=lambda x:wage[x])) #从小到大 print(sorted(wage,key=lambda x:wage[x],reverse=True))#翻转
十、迭代器,生成器,生成器表达式
1、迭代器
迭代器就是迭代取值的工具
迭代是一个重复的过程,但是每一次重复都是基于上一次的结果而进行。
迭代器的作用:针对没有索引的数据类型,比如(字典、集合、文件)想要迭代取出其中包含的值
python解释器提供了一种不依赖索引取值的工具
# 可迭代的对象:在python中但凡内置有__iter__方法的对象都称之为可迭代对象
(字符串、列表、元组、字典、集合、文件)
str1 = 'hello' list1 = ['a', 'b', 'c'] t1 = ('a', 'b', 'c') dic = {'x': 1, 'y': 2} set1 = {'m', 'n'} f = open('a.txt', mode='rt', encoding='utf-8')
# 迭代器对象: # 1、内置有__iter__方法,调用迭代器对象的__iter__方法得到仍然是迭代器本身 # ps: 文件对象本身就是一个迭代器对象 # 2、内置有__next__方法
dic = {'x': 1, 'y': 2} iter_dic = iter(dic) # iter_dic=dic.__iter__() #上面得到迭代器对象 iter_dic print(iter_dic.__next__()) print(iter_dic.__next__()) #就可以调__next__方法取值
dic={'x':1,'y':2} iter_dic=iter(dic) # 调__iter__得到迭代器 while True: try: #检测异常 k=next(iter_dic) #执行__next__取值 print(k) except StopIteration: #接try 的检测 break ----------------------------------------------------------------- #上述即为 for循环的 底层原理
总结
迭代器的优点:
一、提供了一种能够不依赖索引的、通用的迭代取值方式
补充:for循环可以称之为迭代器循环
list1=['a','b','c'] for item in list1: print(item)
for循环的工作流程
1、调用 in 后面那个对象的__iter__方法,拿到一个迭代器对象
2、调用迭代器对象的__next__方法,拿到一个返回值赋值给变量名item
3、循环往复,直到抛出异常,for循环会自动捕捉异常结束循环
二、节省内存
迭代器的缺点:
1、针对同一个迭代器对象只能取完一次,不如按照索引或者key取值方式灵活
2、无法预测迭代器对象所包含值的个数
2、生成器
在函数内但凡出现yield 关键字,在调用函数就不会触发函数体代码的执行了,
会得到一个返回值,返回值就是一个生成器对象
而生成器对象本质就是迭代器(ps:生成器是自定义的迭代器)
def foo(): print('first') yield 1 print('second') yield 2 print('third') yield 3 print('fourth') g=foo() #g是生成器=》就是迭代器 g.__next__() g.__next__() g.__next__()
上述会触发g对应的函数体代码的执行,直到碰到一个yield就暂停住,该yield后的值当做本次__next__的返回值返回
print(g.__next__()) print(g.__next__()) print(g.__next__())
总结yield的功能:
1、提供了一种自定义迭代器的方式
2、可以用于返回值
yield和return的区别:
相同点:都可以用于返回值,个数以及类型都没有限制
不同点:yield可以返回多次值,return只能返回一次值整个函数就结束了
3、函数暂停以及继续执行的状态是由yield保存的
def my_range(start,stop,step=1): while start < stop: # 4 < 4 yield start #start = 3 start+=step #star=4 #---------------------------------------------------------- #range()的原理 for i in my_range(1,5): # 1 3 print(i)
了解:yield关键字表达式形式的应用
def cat(name): print('橘猫[%s]准备开吃' %name) food_list=[] while True: food=yield food_list#food=yield='鱼干' print('橘猫[%s]吃了: %s' %(name,food)) food_list.append(food) # ct=cat('蘑菇') # 强调:针对表达式形式的yield,在使用生成器时必先send(None),相当于先完成一个初始化操作 res0=next(ct) #ct.send(None) # print(res0) #send有两个功能: #1、为当前暂停位置的yield赋值 #2、与next的效果一样 ct.send('鱼干') # next(ct) # ct.send(None) ct.send('三鹿') res1=ct.send('鱼干') # print(res1) res2=ct.send('牛奶') print(res2)
3、生成器表达式
同上述列表、字典生成式一样的形式,只是两边换成了()
l=[i**2 for i in range(1,11)] print(l)###列表生成式 #[1, 4, 9, 16, 25, 36, 49, 64, 81, 100] #================================== l1=(i**2 for i in range(1,11)) print(l1) #<generator object <genexpr> at 0x0000000001EC05C8> #()括号生成了一个迭代器对象,只要不调用l1,其内部就没有值,调一次next方法就取出一个值 print(next(l1))
优点是:
更加节省内存
自定义迭代器的方式
十一、面向过程编程
#=============复杂的问题变得简单 #注册功能: #阶段1: 接收用户输入账号与密码,完成合法性校验 def talk(): while True: username=input('请输入你的用户名: ').strip() if username.isalpha(): break else: print('用户必须为字母') while True: password1=input('请输入你的密码: ').strip() password2=input('请再次输入你的密码: ').strip() if password1 == password2: break else: print('两次输入的密码不一致') return username,password1 #阶段2: 将账号密码拼成固定的格式 def register_interface(username,password): format_str='%s:%s\n' %(username,password) return format_str #阶段3: 将拼好的格式写入文件 def handle_file(format_str,filepath): with open(r'%s' %filepath,'at',encoding='utf-8') as f: f.write(format_str) def register(): user,pwd=talk() format_str=register_interface(user,pwd) handle_file(format_str,'user.txt') register()
#1、首先强调:面向过程编程绝对不是用函数编程这么简单,
面向过程是一种编程思路、思想,而编程思路是不依赖于具体的语言或语法的。
言外之意是即使我们不依赖于函数,也可以基于面向过程的思想编写程序 #2、定义 面向过程的核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么 基于面向过程设计程序就好比在设计一条流水线,是一种机械式的思维方式 #3、优点:复杂的问题流程化,进而简单化 #4、缺点:可扩展性差,修改流水线的任意一个阶段,都会牵一发而动全身 #5、应用:扩展性要求不高的场景,典型案例如linux内核,git,httpd #6、举例 流水线1: 用户输入用户名、密码--->用户验证--->欢迎界面 流水线2: 用户输入sql--->sql解析--->执行功能
十二、补充内置函数
链接地址:https://www.cnblogs.com/nixindecat/p/9599829.html#label5