装饰器
现在让你统计每个函数的执行时间,你怎么做?
import time #引入时间函数 def func1(): start = time.time() #定于开始的时间 print('in func1') #执行函数里的内容 print(time.time() - start) #让现在的时间减去开始的时间,求出效率 func1()
现在让你写一个函数,来测试另一个函数的执行效率,如果测试500个函数的执行效率呢?
import time def func1(): #定义一个函数 print('in func1') def timer(func): # 定义一个函数,在嵌套一个函数 def inner(): start = time.time() #定义开始的时间 func() #执行func1函数 print(time.time() - start) #定义效率 return inner #返回值返回inner给func1,func1=inner func1 = timer(func1) #func1实参传递给timer函数 func1() #此时的func1()=inner()
但是Python认为你这个还是不简单,所以Python给你提供了一个更见的方式就是语法糖。
import time def timer(func): def inner(): start = time.time() func() print(time.time() - start) return inner @timer #==> func1 = timer(func1) #语法糖 def func1(): print('in func1') func1()
到这里,我们可以简单的总结一下:
装饰器的本质:一个闭包函数
装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展
还有最后一个问题要解决,刚刚我们讨论的装饰器都是装饰不带参数的函数,现在要装饰一个带参数的函数怎么办呢?
def timer(func): def inner(a): start = time.time() func(a) print(time.time() - start) return inner @timer #func1=timer(func1) def func1(a): print(a) func1(1)
其实装饰带参的函数并不是什么难事,但假如你有两个函数,需要传递的参数不一样呢?
import time def timer(func): def inner(*args,**kwargs): start = time.time() re = func(*args,**kwargs) print(time.time() - start) return re return inner @timer #==> func1 = timer(func1) def func1(a,b): print('in func1') @timer #==> func2 = timer(func2) def func2(a): print('in func2 and get a:%s'%(a)) return 'fun2 over' func1('aaaaaa','bbbbbb') print(func2('aaaaaa'))
现在参数的问题已经完美的解决了,可是如果你的函数是有返回值的呢?
import time def timer(func): def inner(*args,**kwargs): start = time.time() re = func(*args,**kwargs) print(time.time() - start) return re return inner @timer #==> func2 = timer(func2) def func2(a): print('in func2 and get a:%s'%(a)) return 'fun2 over' func2('aaaaaa') print(func2('aaaaaa'))
刚刚那个装饰器已经非常完美了,但是正常我们情况下查看函数的一些信息的方法在此处都会失效
def index(): '''这是一个主页信息''' print('from index') print(index.__doc__) #查看函数注释的方法 print(index.__name__) #查看函数名的方法
为了不让他们失效,我们还要在装饰器上加上一点来完善它:
from functools import wraps def deco(func): @wraps(func) #加在最内层函数正上方 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper @deco def index(): '''哈哈哈哈''' print('from index') print(index.__doc__) print(index.__name__)
开放封闭原则:
1.对扩展是开放的
为什么要对扩展开放呢?
我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。
2.对修改是封闭的
为什么要对修改封闭呢?
就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。
装饰器完美的遵循了这个开放封闭原则。
装饰器的主要功能:
在不改变函数调用方式的基础上在函数的前、后添加功能。
装饰器的固定格式:
def timer(func): def inner(*args,**kwargs): '''执行函数之前要做的''' re = func(*args,**kwargs) '''执行函数之后要做的''' return re return inner ************************************* from functools import wraps def deco(func): @wraps(func) #加在最内层函数正上方 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper
假如你有成千上万个函数使用了一个装饰器,现在你想把这些装饰器都取消掉,你要怎么做?
def outer(flag): def timer(func): def inner(*args,**kwargs): if flag: print('''执行函数之前要做的''') re = func(*args,**kwargs) if flag: print('''执行函数之后要做的''') return re return inner return timer @outer(False) def func(): print(111) func()
多个装饰器装饰同一个函数
def wrapper1(func): def inner(): print('wrapper1 ,before func') func() print('wrapper1 ,after func') return inner def wrapper2(func): def inner(): print('wrapper2 ,before func') func() print('wrapper2 ,after func') return inner @wrapper2 @wrapper1 def f(): print('in f') f()
内置函数
匿名函数:这个函数真的没有名字 # lambda 关键字 x参数:x是返回值 # 一行函数 用于简单需求 # print((lambda x:x)(5)) # lambda 的返回值只能是一个 sorted() 可迭代对象 key=指定排序方式 可以调整排序方式 filter() 函数,可迭代对象 过滤的规则在函数中写 map() 函数,可迭代对象,将每个元素进行同样的操作 from functools import reduce # reduce() 函数,可迭代对象 累计算 # 以上4个内置函数,都帮咱们提前实现了for循环
今 天我们就认识一下python的内置函数.
# 1.记住怎么用 # print(abs(-98)) # 求绝对值 正的负的 出来后全都是正的 ** # print(all([1,0,3,4])) # all 判断元素中都为真的才是真 * # print(any([1,False,0])) # any 判断元素中只要有一个为真就是真 * # print(ascii('你')) # 查看元素对应的内容 # print(bin(10)) # 将10进制转行2进制 ** # print(bool([1])) # 将内容转换成布尔值 # b = bytearray('meet'.encode('utf-8')) # # 返回一个新的元组,元组可以切片,切片的内容对应的ascii表 # print(b[3]) # print(bytes('你',encoding='utf-8')) * # print('你'.encode('utf-8')) # def func(): # pass # # print(callable(func)) # 检查这个对象是否可以调用 ** # print(chr(65)) # 输入数字,返回对应的ascii表位上对应的内容 ** # a = compile('input(">>>")','','exec') # exec(a) # print(complex(8)) # 复数 * # print(dict(key=1,name=2)) # print(dir([1,2])) # 查看对象的所有方法 *** # print(divmod(5,2)) # 返回一个元组,元组的第一个元素是商,第二个元素是余数 ** # print(enumerate) # 枚举 # li = [1,2,3,4,5,6,7] # # for i,em in enumerate(li,1): # enumerate不写值默认是0 **** # # enumerate 第一个参数是可迭代对象,第二参数是计数 # print(i,em) # s = """9+4+3""" # 将字符串中内容执行 # print(eval(s)) # 上班以后禁止使用 # li = [1,23,4,] # s = """ # def func(): # print(1) # func() # """ # g = exec(s) # print(g) # print(li) # 公司非常禁止 # print(float(20)) # i = 3.56 # print(int(i)) # python3 6 / 3 2.0 # python2 6 / 3 2 # 's'.format() # 字符串的方法 # print(format('a','>10')) # 公用函数 右对齐 # print(format('a','<10')) # 公用函数 左对齐 # print(format('a','^10')) # 公用函数 居中 # print(format(3,'b')) # print(format(3,'08b')) # 00000011 二进制 # print(format(3,'o')) # 八进制 # print(format(3,'x')) # 八进制 # a = 1 # def func(): # pass # print(globals()) # 查看全局都哪些内容 ** # print(b) # print(globals().get('b')) # dic = {[1,2,3]:1} # print(hash([1,2,3])) #求对象的哈希值 * # print(help(input)) # 不知道怎么用的时候可以使用help查看一下 # print(hex(33)) # 将10进制转换成16进制 * # print(id('s')) # 查看数据的内存地址 *** # print(input(">>>")) # 获取用户输入的内容 ***** # print(int()) # 将数据转换成整型 ***** # print(isinstance([1,2,3],str)) #判断这个数据时什么类型 *** # iter # 判断是不是可迭代对象 *** # len() # 获取数据的长度 ***** # list() # 转换成一个列表 *** # def func(): # a = 1 # print(locals()) # 查看局部空间的内容 *** # # func() # print(max(1,2,3,4,5)) # 求最大值 *** # print(min(1,2,3,4)) # 求最小值 *** # print(memoryview(b'a')) # 查看字节的内存地址 # print(next()) # 迭代器中的取下一个值 *** # print(oct(9)) # 将10进制转换成8进制 ** # open(文件名,对这个文件要操作的模式,编码) # '你好'.encode('utf-8') # coding:utf-8 # print(ord('中')) # 输入的是unicode编码的内容 ** # print(chr(20013)) # 输入的是unicode的内容 ** # print(pow(2,3)) #两个参数的时候求幂运算 # print(pow(2,3)) #三个参数的时候先求幂运算在取余 # print('你好','我好',sep=' ',end='') # print('大家好') # print('你好',file=open('a','w',encoding='utf-8')) # print('123') # 是处理后给你显示的 ***** # print(repr('123')) # 显示的是原数据 *** # print(list(reversed())) # 反转 元组,列表,字符串 **** # print(round(5.472343212,3)) #四舍五入 *** # li = [1,2,3,4] # # s = slice(2) #切片 # print(li[3]) # print(sum({1:4,2:5})) #求和 *** # print(type('aasas')) # 获取数据类型 # print(vars(str)) # print(locals()) # li = [1,2,3,4] # ls = [5,6,7,4,5,6] # lst = ['a','b','c','d','e'] # print(list(zip(li,ls,lst))) #拉链 **** # __import__('time') # 导入的方式 ---- > 反射
2.整体函数使用:
2.1 作用域相关
2.1.1 locals() 返回当前作⽤用域中的名字
2.1.2 globals() 返回全局作⽤用域中的名字
2.2 迭代器相关
2.2.1 range() 生成数据
2.2.2.next() 迭代器向下执⾏一次, 内部实际使用了__next__()方法返回迭代器的下一个项目
2.2.3 iter() 获取迭代器, 内部实际使用的是__iter__()方法来获取迭代器
2.3 字符串类型代码的执行
2.3.1 eval() 执行部分字符串类型的代码,并返回最终结果
print(eval("2+2"))
# 4
n = 8
print(eval("2+n"))
# 10
def func():
print(666)
eval("func()")
# 666
2.3.2 exec() 执行字符串类型的代码
msg = '''
def func():
print('有计划没行动等于零')
func()
'''
exec(msg)
以上这两个在公司开发中禁止使用,如果里边出现del就会出现很大的问题
2.4 输入和输出相关
2.4.1 input() 获取用户输入的内容
2.4.2 print() 打印输出
print('你好','我好')
print('你好','我好',sep='|')
结果:
你好 我好
你好|我好
sep是将多个元素进行修改 默认的是空格
print('你好')
print('我好')
print('你好',end='')
print('我好')
end默认是 这就是我们为什么使用print的时候会出现换行,end的值修改成了空字符串
2.5 内存相关
2.5.1 hash() 获取到对象的哈希值(int, str, bool, tuple)
print(hash('123'))
结果:
-6822401661081700707
这样是求出数据结构,如果能够获取到哈希值就是可以当做字典的键
2.5.2 id() 获取到对象的内存地址
2.6 文件操作相关
2.6.1 open() 用于打开一个文件, 创建一个文件句柄
2.7 帮助
2.7.1 help() 函数用于查看函数或模块用途的详细说明
help(print)
结果:
Help on built-in function print in module builtins:
print(...)
print(value, ..., sep=' ', end='
', file=sys.stdout, flush=False)
Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file: a file-like object (stream); defaults to the current sys.stdout.
sep: string inserted between values, default a space.
end: string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.
Process finished with exit code 0
2.8 调用相关
-
8.1 callable() 用于检查一个对象是否是可调用的. 如果返回True, object有可能调用失败, 但如果返回False. 那调用绝对不会成功
print(callable(print))
结果:
True
2.9 查看内置属性
2.9.1 dir()查看对象的内置属性
方法.访问的是对象中的__dir__()⽅方法
print(dir(list))
结果:
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
2.10 基础数据类型相关
2.10.1 数字相关
bool() 将给定的数据转换成bool值. 如果不给值. 返回False
int() 将给定的数据转换成int值. 如果不给值, 返回0
float() 将给定的数据转换成float值. 也就是小数
complex() 创建一个复数. 第一个参数为实部, 第二个参数为虚部. 或者第一个参数直接 用字符串来描述复数
2.10.2 数学运算
abs() 返回绝对值
print(abs(-1))
结果:
1
divmod() 返回商和余数
print(divmod(15,2))
结果:
(7, 1)
round() 四舍五入
print(round(15.1111,2)) # 保留2位小数
结果:
15.11
pow(a, b) 求a的b次幂, 如果有三个参数. 则求完次幂后对第三个数取余
print(pow(15,2,3))
结果:
0
sum() 求和
print(sum([12,3,4])) #sum里边的参数是一个可迭代对象
结果:
19
min() 求最小值
print(min([12,3,4])) # 寻找最小的数字
结果:
3
max() 求最大值
print(max([12,3,4])) # 寻找最大的数字
结果:
12
2.10 .3数据结构相关
列表和元组:
list() 将一个可迭代对象转换成列表
tuple() 将一个可迭代对象转换成元组
reversed() 将一个序列翻转, 返回翻转序列的迭代器
reversed 示例:
l = reversed('你好') # l 获取到的是一个生成器
print(list(l))
字符串相关:
str() 将数据转化成字符串
format() 与具体数据相关, 用于计算各种小数, 精算等
print(format('meet','>20')) # 右对齐
print(format('meet','<20')) # 左对齐
print(format('meet','^20')) # 居中
数值
#数值
print(format(3,'b')) # 二进制
print(format(97,'c')) # 转换成unicodezif
print(format(11,'d')) #十进制
print(format(56)) #和d一样
print(format(11,'n')) #十进制
print(format(11,'o')) #八进制
print(format(11,'x')) # 十六进制(小写字母)
print(format(11,'X')) # 十六进制(大写字母)
# 浮点数
print(format(1234567890,'e')) #科学计算法,默认使用6位
print(format(123456789,'0.2e'))# 科学计算,保留2位小数(小写)
print(format(123456789,'0.2E'))# 科学计算,保留2位小数(大写)
print(format(1.23456789,'f')) #小数点计数法,保留6位小数
print(format(1.23456789,'0.2f')) # 小数点计数法,保留2位数
print(format(1.23456789,'0.10f')) # 小数点计数法,保留2位数
print(format(1.23456789e+1000,'F')) # 小数点计数法
bytes() 把字符串转换成bytes类型
s = '你好武大'
bs = s.encode('utf-8')
print(bs)
结果:b'xe4xbdxa0xe5xa5xbdxe6xadxa6xe5xa4xa7'
s1 = bs.decode('utf-8')
print(s1)
结果: 你好武大
s = '你好'
bs = bytes(s,encoding='utf-8')
print(bs)
# 将字符串转换成字节
bs1 = str(bs,encoding='utf-8')
print(bs1)
# 将字节转换成字符串
repr() 返回一个对象的官方表示形式
# repr 输出一个字符串的官方表示形式.
print(repr('大家好,
我叫周杰伦')) print('大家好我叫周杰伦')
# %r
%r用的就是repr
name = 'taibai'
print('我叫%r' % name)
2.11 数据集合
dict() 创建一个字典
set() 创建一个集合
frozenset() 创建一个冻结的集合,冻结的集合不能进行添加和删除操作
2.12 其他相关
len() 返回一个对象的元素个数
enumerate() 获取枚举对象
enumerate() 举例
lst = ['alex','wusir','taibai']
for i,k in enumerate(lst):
print('这是序号',i)
print('这是元素',k)
all() 可迭代对象中全部是True,结果才是True
lst = [1,2,3,4,True,0,False]
lst1 = [1,2,3,4,True]
print(all(lst))
print(all(lst1))
结果:
False
True
any() 可迭代对象中有一个是True,就是True
lst = [1,2,3,4,True,0,False]
lst1 = [1,2,3,4,True]
print(any(lst))
print(any(lst1))
结果:
False
True
zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元祖,
然后返回由这些元祖组成的内容,如果各个迭代器的元素个数不一致,则按照长度最短的返回
lst1 = [1,2,3]
lst2 = ['a','b','c','d']
lst3 = (11,12,13,14,15)
for i in zip(lst1,lst2,lst3):
print(i)
结果:
(1, 'a', 11)
(2, 'b', 12)
(3, 'c', 13)
2.13 lambda
匿名函数,为了解决一些简单的需求而设计的一句话函数
def func(n):
return n**n
print(func(4))
f = lambda x: x**x
print(f(4))
结果:
256
256
lambda表示的是匿名函数,不需要用def来声明,一句话就可以声明出一个函数
语法:
函数名 = lambda 参数:返回值
注意:
1.函数的参数可以有多个,多个参数之间用逗号隔开
2.匿名函数不管多复杂.只能写一行.且逻辑结束后直接返回数据
3.返回值和正常的函数一样,可以是任意数据类型,返回值的时候只能返回一个不能返回多个
匿名函数并不是说一定没有名字,这里前面的变量就是一个函数名,说他是匿名原因是我们通过
__name__查看的时候是没有名字的.统一都叫做lambda.在调用的时候没有什么特别之处
像正常的函数调用既可
2.14 sorted
排序函数
语法:sorted(iterable,key=None,reverse=False)
iterable : 可迭代对象
key: 排序规则(排序函数),在sorted内部会将可迭代对象中的每一个元素传递给这个函数的参数.根据函数运算的结果进行排序
reverse :是否是倒叙,True 倒叙 False 正序
lst = [1,3,2,5,4]
lst2 = sorted(lst)
print(lst) #原列表不会改变
print(lst2) #返回的新列表是经过排序的
lst3 = sorted(lst,reverse=True)
print(lst3) #倒叙
结果:
[1, 3, 2, 5, 4]
[1, 2, 3, 4, 5]
[5, 4, 3, 2, 1]
字典使用sorted排序
dic = {1:'a',3:'c',2:'b'}
print(sorted(dic)) # 字典排序返回的就是排序后的key
结果:
[1,2,3]
和函数组合使用
# 定义一个列表,然后根据一元素的长度排序
lst = ['天龙八部','西游记','红楼梦','三国演义']
# 计算字符串的长度
def func(s):
return len(s)
print(sorted(lst,key=func))
# 结果:
# ['西游记', '红楼梦', '天龙八部', '三国演义']
和lambda组合使用
lst = ['天龙八部','西游记','红楼梦','三国演义']
print(sorted(lst,key=lambda s:len(s)))
结果:
['西游记', '红楼梦', '天龙八部', '三国演义']
lst = [{'id':1,'name':'alex','age':18},
{'id':2,'name':'wusir','age':17},
{'id':3,'name':'taibai','age':16},]
# 按照年龄对学生信息进行排序
print(sorted(lst,key=lambda e:e['age']))
结果:
[{'id': 3, 'name': 'taibai', 'age': 16}, {'id': 2, 'name': 'wusir', 'age': 17}, {'id': 1, 'name': 'alex', 'age': 18}]
2.15 filter
筛选过滤
语法: filter(function,iterable)
function: 用来筛选的函数,在filter中会自动的把iterable中的元素传递给function,然后根据function返回的True或者False来判断是否保留此项数据
iterable:可迭代对象
lst = [{'id':1,'name':'alex','age':18},
{'id':1,'name':'wusir','age':17},
{'id':1,'name':'taibai','age':16},]
ls = filter(lambda e:e['age'] > 16,lst)
print(list(ls))
结果:
[{'id': 1, 'name': 'alex', 'age': 18},
{'id': 1, 'name': 'wusir', 'age': 17}]
2.16 map
映射函数
语法: map(function,iterable) 可以对可迭代对象中的每一个元素进映射,分别取执行function
计算列表中每个元素的平方,返回新列表
lst = [1,2,3,4,5]
def func(s):
return s*s
mp = map(func,lst)
print(mp)
print(list(mp))
改写成lambda
lst = [1,2,3,4,5]
print(list(map(lambda s:s*s,lst)))
计算两个列表中相同位置的数据的和
lst1 = [1, 2, 3, 4, 5]
lst2 = [2, 4, 6, 8, 10]
print(list(map(lambda x, y: x+y, lst1, lst2)))
结果:
[3, 6, 9, 12, 15]
2.17 reduce
from functools import reduce
def func(x,y):
return x + y
# reduce 的使用方式:
# reduce(函数名,可迭代对象) # 这两个参数必须都要有,缺一个不行
ret = reduce(func,[3,4,5,6,7])
print(ret) # 结果 25
reduce的作用是先把列表中的前俩个元素取出计算出一个值然后临时保存着,
接下来用这个临时保存的值和列表中第三个元素进行计算,求出一个新的值将最开始
临时保存的值覆盖掉,然后在用这个新的临时值和列表中第四个元素计算.依次类推
注意:我们放进去的可迭代对象没有更改
以上这个例子我们使用sum就可以完全的实现了.我现在有[1,2,3,4]想让列表中的数变成1234,就要用到reduce了.
普通函数版
from functools import reduce
def func(x,y):
return x * 10 + y
# 第一次的时候 x是1 y是2 x乘以10就是10,然后加上y也就是2最终结果是12然后临时存储起来了
# 第二次的时候x是临时存储的值12 x乘以10就是 120 然后加上y也就是3最终结果是123临时存储起来了
# 第三次的时候x是临时存储的值123 x乘以10就是 1230 然后加上y也就是4最终结果是1234然后返回了
l = reduce(func,[1,2,3,4])
print(l)
匿名函数版
l = reduce(lambda x,y:x*10+y,[1,2,3,4])
print(l)