函数的优势:
1,减少代码的重复性。
return使用方法总结:
第四种情况:return 多个值(以元组的形式返回给函数的调用者)
函数的使用:
实参角度:三种
位置参数 :实参和形参数一一对应
举例说明:
def tes(a,b,c):
print(111)
print(a,b,c)
tes(22,'alex',[11,22,33])
关键字参数 :也得一一对应 实参和形参数量相等,实参的顺序可以变(可以理解为分别赋值)
举例说明:
def func(x,y):
print(x,y)
func(y=333,x=444 ) #也可以不用写x= y= 直接写值也行
混合参数(位置参数,关键字参数):整体数量要一一对应,位置参数必须在前面 多个关键字参数位置可以互换,不用一一对应
举例说明:
def func(x,y,z):
print(x,y,z)
func(111,222,z=555)
形参角度:三种
位置参数:相对于实参位置而言 也得一一对应
默认参数: 默认参数必须放在 形参的位置参数后面,不传值就是默认值, 传值则覆盖默认值。
举例说明:
def func2(x,y,z=100):#默认参数
print(x,y,z)
func2(1,2)
动态参数:用户传入到函数中的实参数量不定时,或为以后拓展,此时要用到动态参数。
此时要用到动态参数*args,kwargs(这个英文可以改,他们只是个变量,也叫万能参数)
*args接受的是所有的位置参数。形成元组
kwargs接受的是所有的关键字参数。形成字典
举例说明:
def func1(*args,kwargs):
print(args)
print(kwargs)
func1(1,2,3,4)
func1(x=4,y=5,z=6)
func1(1,2,3,x=4,y=5,z=6)
动态参数的位置:
*args:
位置参数 *args 默认参数
kwargs:
放在最后面:位置参数 *args 默认参数,kwargs.
举例说明:
补充:
#如果函数的默认参数是可变的数据类型,无论使用多少次默认参数,都是一个,并且如果默认参数是{} [] ()等 实参位置不用加索引(这里和学习深浅copy有相似地方)
def extendlist(val,list=[]):
list.append(val)
return list
list1=extendlist(10)
list2=extendlist(123,[])
list3=extendlist('a')
list=[10,'a'] #默认列表
list=[123,] #新列表
list=[10,'a'] #一变都变,默认列表
print('list1=&s' %list1)
*的魔性用法:将可迭代对象 直接将每个元素加入到args中
补充:
*处理剩下的元素
*除了在函数中可以这样打散,聚合外,函数外还可以灵活的运用:
名称空间,加载顺序等
当程序运行时,代码从上至下以此读取,遇到变量与值,它会在内存中开辟一个空间,存放变量与值得内存地址的对应关系。
这样存储变量与值得对应关系的空间叫做名称空间(命名空间)又称全局名称空间
内置名称空间:存放了python解释器为我们提供的名字:input,print等
如len() print() input()
函数的嵌套:主要是要明白数据的执行顺序。
global nonlocal 关键字*
2,global :1)在局部作用域中声明一个全局变量。
2)在局部作用域中更改一个全局变量(在局部作用域想要对全局作用域的全局变量进行修改时,需要用到 global(限于字符串,数字))
补充:局部作用域对全局作用域的变量(此变量只能是不可变的数据类型)只能进行引用,而不能进行改变,对于可变的数据类型,函数中如果对其进行操作,改变全局变量不用引入global
nonlocal如果上一层没有变量 就会报错(在局部作用域如果想对父级作用域的变量进行改变时,需要用到nonlocal)
补充:
*函数名的应用*
3,函数名可以作为函数的参数
4,函数名可以作为容器数据类型的元素。
5,函数名可以作为函数的返回值
*闭包*
补充理解(之前都没有理解闭包是干什么的):
由于闭包这个概念比较难以理解,尤其是初学者来说,相对难以掌握,所以我们通过示例去理解学习闭包。
给大家提个需求,然后用函数去实现:完成一个计算不断增加的系列值的平均值的需求。
例如:整个历史中的某个商品的平均收盘价。什么叫平局收盘价呢?就是从这个商品一出现开始,每天记录当天价格,然后计算他的平均值:平均值要考虑直至目前为止所有的价格。
比如大众推出了一款新车:小白轿车。
第一天价格为:元,平均收盘价:元
第二天价格为:元,平均收盘价:( + )/2 元
第三天价格为:元,平均收盘价:( + + )/3 元
........
从上面的例子可以看出,基本上完成了我们的要求,但是这个代码相对来说是不安全的,因为你的这个series列表是一个全局变量,只要是全局作用域的任何地方,都可能对这个列表进行改变。
那么怎么办呢?有人说,你把他放在函数中不就行了,这样不就是局部变量了么?数据不就相对安全了么?
这样计算的结果是不正确的,那是因为执行函数,会开启一个临时的名称空间,随着函数的结束而消失,所以你每次执行函数的时候,都是重新创建这个列表,那么这怎么做呢?这种情况下,就需要用到我们讲的闭包了,我们用闭包的思想改一下这个代码。
大家仔细看一下这个代码,我是在函数中嵌套了一个函数。那么avg 这个变量接收的实际是averager函数名,也就是其对应的内存地址,我执行了三次avg 也就是执行了三次averager这个函数。那么此时你们有什么问题?
肯定有学生就会问,那么我的make_averager这个函数只是执行了一次,为什么series这个列表没有消失?反而还可以被调用三次呢?这个就是最关键的地方,也是闭包的精华所在。我给大家说一下这个原理,以图为证:
上面被红色方框框起来的区域就是闭包,被蓝色圈起来的那个变量应该是make_averager()函数的局部变量,它应该是随着make_averager()函数的执行结束之后而消失。但是他没有,是因为此区域形成了闭包,series变量就变成了一个叫自由变量的东西,averager函数的作用域会延伸到包含自由变量series的绑定。也就是说,每次我调用avg对应的averager函数 时,都可以引用到这个自用变量series,这个就是闭包。
内层函数对外层函数非全局变量的引用就叫闭包
判断是不是闭包,是函数名.__closure__返回的是None则不是闭包,返回cell则是。
闭包有什么用?
当执行一个函数时,如果解释器判断此函数闭包存在,这样函数就有一个机制,闭包的所在的临时名称空间不会随着函数的执行完毕而消失。
闭包的作用:保存局部信息不被销毁,保证数据的安全性。
闭包的应用:
- 可以保存一些非全局变量但是不易被销毁、改变的数据。
- 装饰器。
比较有意思的一道题:
装饰器
装饰器的理解:以前你有没有这样一段经历:很久之前你写过一个函数,现在你突然有了个想法就是你想看看,以前那个函数在你数据集上的运行时间是多少,这时候你可以修改之前代码为它加上计时的功能,但是这样的话是不是还要大体读读你之前的这个的代码,稍微搞清楚一点它的逻辑,才敢给它添加新的东西。这样是不是很繁琐,要是你之前写的代码足够乱足够长,再去读它是不是很抓狂...。实际工作中,我们常常会遇到这样的场景,可能你的需求还不只是这么简单。那么有没有一种可以不对源码做任何修改,并且可以很好的实现你所有需求的手段呢?答案当然是有,这就是今天我们要介绍的python装饰器。有了装饰器,你除了不用担心前面提到的问题,并且还可以很好的处理接下来要做的事:那就是现在你又有了一个新的需求,比如为另一个函数添加计时功能,这时就非常简单了,把要装饰的函数丢给装饰器就好了,它会自动给你添加完功能并返回给你。是不是很神奇?下面我们将一层层剥开它的神秘面纱。
装饰器定义及作用:装饰器本质还是一个函数,它是用来对函数函数进行装饰的函数,在不改变原来函数调用的基础上给原来的函数添加新的功能
装饰器的原则:开放封闭原则
开放:对于原来的函数没有的功能(要添加的新的功能是开放的) 为什么要对扩展开放呢? 任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。 封闭:对于原来的函数已经实现的功能是封闭的(不能改变原来的函数) 为什么要对修改封闭呢? 就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对已经写好的函数进行了修改,很有可能影响其他已经在使用该函数的用户。 装饰器完美的遵循了这个开放封闭原则
讯享网
函数带返回值的装饰器(万能装饰器)
万能装饰器雏形:
*函数的有用信息
带参数的装饰器
这个就是带参数的装饰器,其作用就是能够很好的控制被装饰器的使用功能,就是在装饰器的原来基础上 在加个函数。
*多个装饰器装饰多个函数
补充知识点:
*迭代器
可迭代对象定义:内部含有__iter__方法的就是可迭代对象,遵循可迭代协议。
用dir函数可以检测:可以通过dir() 去判断一个对象具有什么方法,dir()会返回一个列表,这个列表中含有该对象的以字符串的形式所有方法名
print(dir('123'))#返回的是列表
print('__iter__' in dir([1,2,3])) 用这个方法判断列表中是否存在__iter__
dir():查看对象的所有方法
可迭代对象的优点:
可以直观的查看里面的数据。
可迭代对象的缺点:
1. 占用内存。
2. 可迭代对象不能迭代取值(除去索引,key以外)。
那么这个缺点有人就提出质疑了,即使抛去索引,key以外,这些我可以通过for循环进行取值呀!对,他们都可以通过for循环进行取值,其实for循环在底层做了一个小小的转化,就是先将可迭代对象转化成迭代器,然后在进行取值的。那么接下来,我们就看看迭代器是个什么鬼。
迭代器:可迭代对象通过.__iter__()可以转化成迭代器,遵循迭代器协议,其实它也是数据类型。在python中,内部含有'__Iter__'方法并且含有'__next__'方法的对象就是迭代器。 迭代器也是一种数据类型:1)内存占用非常小,节省内存;2)满足惰性机制,在循环到第四次时,再次循环它会从第5次继续执行;迭代器是未来做数据类型;3)取值过程单项不可逆的首选方式
迭代器取值方法:
生成迭代器以及取值的另一种方法:

怎样判断是否是迭代器:
迭代器:是一个非常节省内存,可以记录取值位置,可以直接通过循环+next方法取值,但是不直观,操作方法比较单一的数据集。
应用:当你的数据量过大,大到足以撑爆你的内存或者你以节省内存为首选因素时,将数据集设置为迭代器是一个不错的选择。(可参考为什么python把文件句柄设置成迭代器)
*生成器
生成器的本质也是迭代器,迭代器都是Python给你提供的已经写好的工具或者通过数据转化得来的,(比如文件句柄,iter([1,2,3])。生成器是需要我们自己用python代码构建的工具。最大的区别也就如此了。
两种构建方法:
1)函数构建生成器:将函数中的return换成yield,这样func就不是函数了,而是一个生成器函数
send的用法
yield from的用法
需要注意yield from 是将列表中的每一个元素返回,所以 如果写两个yield from 并不会产生交替的效果
2)推导器构建
列表推导式:
[变量(加工后的变量) for 变量 in 可迭代对象]-----遍历模式
li = [i for i in range(1,12)]
print(li)
字典推导式:这里只是简单介绍一个
*内置函数
目前python里共有68个内置函数
黄色一带而过:all() any() bytes() callable() chr() complex() divmod() eval() exec() format() frozenset() globals() hash() help() id() input() int() iter() locals() next() oct() ord() pow() repr() round()
红色重点讲解:abs() enumerate() filter() map() max() min() open() range() print() len() list() dict() str() float() reversed() set() sorted() sum() tuple() type() zip() dir()
蓝色未来会讲: classmethod() delattr() getattr() hasattr() issubclass() isinstance() object() property() setattr() staticmethod() super()
range()自定制一个数字范围列表
frozenset()冻结:语法:
locals() 以字典形式返回当前位置全部 局部变量
eval:去除字符串的引号,返回对应内部的值。
s = '{"a":1,"b":3}'
dic = eval(s)
print(dic,type(dic))
exec:去除字符串的引号,没有返回值,但是能执行里面的结果
print函数:
help:函数用于查看函数或模块用途的详细说明。
complex(复数):
bin:将十进制转换成二进制并返回。
oct:将十进制转换成八进制字符串并返回。
hex:将十进制转换成十六进制字符串并返回。
pow:求xy次幂 (三个参数为xy的结果对z取余)
讯享网print(pow(2,3)) # 两个参数为23次幂 print(pow(2,3,3)) # 三个参数为23次幂,对3取余。
sum:对可迭代对象进行求和计算(可设置初始值)
print(sum([1,2,3,4]))
print(sum([1,2,3,4],100))
min:返回可迭代对象的最小值(可加key,key为函数名,通过函数的规则,返回最小值)
print(min([1,3,5,7,-4]))
print(min([1,3,5,7,-4],key=abs))
max:返回可迭代对象的最小值(可加key,key为函数名,通过函数的规则,返回最大值)
list:将可迭代对象创建列表
tu = (1,2,3)
print(list(tu)) 这个其实是创建 也可理解为转换
和函数组合使用 # 定义一个列表,然后根据一元素的长度排序 lst = ['天龙八部','西游记','红楼梦','三国演义'] # 计算字符串的长度 def func(s): return len(s) print(sorted(lst,key=func)) # 结果: # ['西游记', '红楼梦', '天龙八部', '三国演义']
讯享网和lambda组合使用 lst = ['天龙八部','西游记','红楼梦','三国演义'] print(sorted(lst,key=lambda s:len(s))) 结果: ['西游记', '红楼梦', '天龙八部', '三国演义']
以什么方式切l1就以什么方式切l2
format:与具体数据相关,用于计算各种小数,精算等。
print(format('test','<20')) #左对齐
print(format('test','>20')) #右对齐
print(format('test','^20')) #居中
bytes:str-->bytes
bytearray
ret = bytearray('abc',encoding='utf-8')#类比:[97,133,......]
print(id(ret))
print(ret) #bytearray(b'abc')
print(ret[0]) #得到'a'在accii的位置。
ret[0]=65
print(ret)
memoryview:
#分字节去转化成str
b1 = bytes('您好',encoding='utf-8')
print(b1)
ret = memoryview(bytes('您好',encoding='utf-8'))
print(len(ret))
print(ret)
print(bytes(ret[:3]).decode('utf-8'))
print(bytes(ret[3:]).decode('utf-8'))
ord:输入字节找该字节编码的位置。
print(ord('a'))
print(ord('中')) #unicode编码
chr:输入位置数字找出其对应的字符
print(chr(65))
print(chr(20013))
ascii:是ascii码中的返回值,不是就返回/u
print(ascii('a'))
print(ascii(1))
print(ascii('中'))
all:可迭代对象中,全都是True才是True
all() 函数用于判断给定的可迭代参数 iterable 中的所有元素是否都为 TRUE,如果是返回 True,否则返回 False。
元素除了是 0、空、None、False 外都算 True(这里的空指的是可迭代对象里面的元素 如果是空列表,元组,返回的True)。 bool值不是可迭代对象
zip:拉链方法,返回的是一个迭代器。
函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,
然后返回由这些元祖组成的内容,如果各个迭代器的元素个数不一致,则按照长度最短的返回
map:循环模式 将第二个可迭代对象的元素 作为第一个函数的参数进行循环执行 map(function,iterable)
结合lambda函数 可以更简写为ret = filter(lambda x:x%2==0,[1,2,3,4,5,6,7])
lambda 匿名函数,一句话函数 和map filter函数相结合。
def func(x):return x % 2 == 0
def func1(x,y):
return x + y
ret = lambda x,y:x+y #lambda就相当于def ret相当于函数名
ret(2,3) #执行 相当于 func(x)
print(ret(2,3))
题
比较优秀的题
通过用户的选择进行登录
延续上面的更改如下:
下面是两个账户密码一个是京东的一个是淘宝的,分开。这个时候需要使用带参数的装饰器,这时候需要两个文件一个存京东的账户密码,一个存淘宝的账户密码
可以进行优化。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/178568.html