万恶之源 - Python装饰器及内置函数
听名字应该知道这是一个装饰的东西,我们今天就来讲解一下装饰器,有的铁子们应该听说,有的没有听说过.没有关系我告诉你们这是一个很神奇的东西
这个有多神奇呢? 我们先来复习一下闭包
def func1(): name = "alex" def func2(): print(name) # 闭包 func2() func1()
这就是闭包,那刚刚说的很神奇的东西呢?,为什么又说闭包了呢? 机智的铁子们已经猜到,装饰器和闭包是有点关系的,是滴没错.
那什么是装饰器呢?装饰器是干什么的呢?
装饰器的本质其实就是闭包
现在你在公司,领导让你写一个函数,来测试另一个函数的执行效率,你怎么做?
我先告诉大家一个查看时间的东西
time.time() 获取都是一个字符串
我们可以通过这个来计算执行时间
def func(): print('嘻嘻更健康') import time start_time = time.time() time.sleep(0.1) func() end_time = time.time() print('----> 执行效率%s'%(end_time - start_time))
上面你已经写完了,但是你应该放在函数中,这样减少重复代码,可读性好,ok继续做。
def func(): print('嘻嘻更健康') def timmer(f): start_time = time.time() time.sleep(0.1) f() end_time = time.time() print('----> 执行效率%s'%(end_time - start_time))
好你又写完了,但是执行之前的函数只是func(),而你写玩了这个之后,还得加一步timmer(func),如果要是领导让你测试500个函数的执行效率呢?好,你又进一步改,如下
func() f1 = func # func func = timmer # timmer func(f1) 将他的执行结果改了一下,这样看似func(f1)与原来的调用差不多,但是加了好几步,而且添加了f1参数。。。
现在你请教了我,我说来,写个装饰器就能解决。
def timmer(f): def inner(): start_time = time.time() time.sleep(0.1) f() end_time = time.time() print('----> 执行效率%s' % (end_time - start_time)) return inner func = timmer(func) # inner func() # inner()
这样,就写好了,这是最简单的装饰器,装饰任何函数,只需要加一句func = timmer(func)
#简单的装饰器 def func(): print('嘻嘻更健康') def timmer(f): def inner(): start_time = time.time() time.sleep(0.1) f() end_time = time.time() print('----> 执行效率%s' % (end_time - start_time)) return inner func = timmer(func) # inner func() # inner()
但是Python认为你这个还是不简单,所以Python给你提供了一个更见的方式就是语法糖。
#语法糖 @ def timmer(f): def inner(): start_time = time.time() time.sleep(0.1) f() end_time = time.time() print('----> 执行效率%s' % (end_time - start_time)) return inner @timmer # func = timmer(func) 语法糖的用意
@装饰器函数 == 重新定义被装饰函数=装饰器函数(被装饰函数)
def func(): print('嘻嘻更健康') func() # inner()
内置函数(下午讲解)
什么是内置函数?就是python帮我们提供的一个工具,拿过直接用就行,比如我们的print,input,type,id等等.截止到python3.6.2版本
中一共提供了68个内置函数.他们就是python直接提供给我们的,有一些我们已经用过了.有一些还没有用过.还有一我们需要学完面向对象才能继续学习.今天我们认识一下python的内置函数
作用域相关
locals() 返回当前作用域中的名字
globals() 返回全局作用域中的名字
迭代器相关
range() 生成数据
next() 迭代器向下执行一次,内部实际使用了next()方法返回迭代器的下一个项目
iter() 获取迭代器,内部实际使用的是iter()方法来获取迭代器
字符串类型代码的执行
eval() 执行字符串类型的代码,并返回最终结果
print(eval('2+8')) 结果: 10 n = 8 print(eval('n + 10')) 结果: 18
exec() 执行字符串类型的代码
exec(''' for i in range(10): print(i) ''') # 我们按照python能够识别的语法写代码,这次写入的是字符串也可以执行 exec(''' def func(): print("444") func() ''') 结果: 444
通过上边的测试发现,只要是exec就没有返回值,eval就是有返回值的
输入和输出相关
input() 获取用户输入的内容
print() 打印 输出
print里的sep
print('alex','wusir','baoyuan') print('alex','wusir','baoyuan',sep='|') # 结果: # alex wusir baoyuan # alex|wusir|baoyuan print默认sep是一个空格,咱们打印出来的是以空格分开的,我们修改了sep打印出来的就是以管道符分开的
print里的end
print('alex') print('alex') print('alex') # 结果: # alex # alex # alex print('alex',end='') print('alex',end='') print('alex',end='') # 结果: # alexalexalex print 默认end是一个\n,打印出来的效果是有换行功能,咱们改成空字符串,打印出来的效果就是一行显示
内存相关
hash() 获取对象的哈希值(int.str,bool,tuple)
print(hash((1,2,4))) print(hash('你好')) print(hash(111)) print(hash(False))
id() 获取到对象的内存地址
name = 'alex' print(id(name)) 结果:2376700908072
文件操作相关
open() 用于打开一个文件,创建一个文件句柄
模块相关
import() 导入,引入
import time print(time.time())
帮助
help() 函数用于查看函数或模块用途的详细说明
help(input) 结果: Help on built-in function input in module builtins: input(prompt=None, /) Read a string from standard input. The trailing newline is stripped. The prompt string, if given, is printed to standard output without a trailing newline before reading input. If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError. On *nix systems, readline is used if available.
调用相关
callable() 用于检查一个对象是否是可调用的,如果返回True,object有可能调用失败,要是返回False,那调用绝对就完犊子
def func(): pass name = 'meet' print(callable(func)) 结果 True print(callable(name)) 结果 Fasle
查看内存属性
dir() 查看对象的内置属性,方法,访问的是对象的dir()方法
print(dir(input)) # 结果: # ['__call__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__text_signature__'] 基础数据类型相关
数字相关:
bool() 将给定的数据转换成bool值,如果不给值.返回False
print(bool()) 结果: False
int() 将给定的数据转换成int值,如果不给值,返回0
print(int()) 结果: 0
float() 将给定的数据转换成float值,也就上次小数
print(float()) 结果: 0.0
compilex() 创建一个复数,第一个参数为实部,第二个参数为虚部.或者第一个参数直接用字符串来描述复数
print(complex(120)) 结果: 120+0j
进制转换:
bin() 将给的参数转换成二进制
otc() 将给的参数转换成八进制
hex() 将给的参数转换成十六进制
数字运算:
abs() 求绝对值
print(abs(-100)) 结果: 100
divmod() 返回商和余数
print(divmod(20,6)) 结果: (3, 2)
第一个参数是商,第二参数是余数
round() 四舍五入
print(round(3.56)) 结果: 4 print(round(3.56,1)) 结果: 3.6 后边的参数是指定小数点后边的数字进行四舍五入,咱们指定的数字要小于咱们小时候点后边的位数
pow(a,b) 求a的b次幂,如果有个三次参数,则求万次幂后对第三方个数取余
print(pow(2,4)) 结果: 16 print(pow(2,4,3)) 结果: 1 三个参数 前来个参数是求2的3次幂,第三个参数是这个总和去除3然后获取的是余数
sum() 求和
print(sum([1,2,3,4,5])) 结果: 15 参数必须是可迭代对象 min() 求最小值 print(min([1,2,3,4,5])) 结果: 1 参数必须是可迭代对象
max() 求最大值
print(max([1,2,3,4,5])) 结果: 5 参数必须是可迭代对象
数据结构相关
列表和元祖
list() 将一个可迭代对象转换成列表
tuple() 将一个可迭代对象转换成元祖
reversed() 将一个序列反转,返回反转序列的迭代器
print(list(reversed('你好啊'))) 结果: ['啊', '好', '你']
字符串相关:
str() 将数据转化成字符串
format() 与具体数相关,用于计算各种小数,精算等
字符串
# 字符串 # print(format('meet','<20')) #左对齐 # print(format('meet','>20')) #右对齐 # print(format('meet','^20')) #居中 结果: meet meet meet
数值 自己练习
#数值 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'\xe4\xbd\xa0\xe5\xa5\xbd\xe6\xad\xa6\xe5\xa4\xa7' s1 = bs.decode('utf-8') print(s1) 结果: 你好武大 bs = bytes(s,encoding='utf-8') print(bs) 结果: b'\xe4\xbd\xa0\xe5\xa5\xbd\xe6\xad\xa6\xe5\xa4\xa7' 把字符串编码成utf-8
bytearray() 返回一个新字节数组,每个元素的值的范围是0~256对应的是ascii码表
ret = bytearray('meet',encoding='utf-8') print(ret) print(ret[0]) 结果: bytearray(b'meet') 109
memoryview() 查看bytes的内存地址
s = memoryview('麻花藤'.encode('utf-8')) print(s) # 结果: # <memory at 0x000001F332E0E288>
ord() 输入字符找带字符编码的位置
print(ord('a')) print(ord('中')) print(ord('国')) 结果: 97 20013 22269 对应的是当前编码
chr() 输入位置数字找出对应的字符
print(chr(97)) # 找到对应位置的字符 print(chr(20013)) # 找到对应位置的字符 # 结果: a 中
ascii() 是ascii码中的返回值 不是就返回\u
print(ascii('a')) 判断字符串在不在ascii码表中 print(ascii('中')) 结果: 'a' '\u4e2d' 如果不存在就返回\u...
repr() 返回一个对象本质的形式
name = 'alex' print(repr(name)) #返回这个对象本质的表示形式 结果: 'alex' name = '我叫%r' print(name%'meet') %r 用的就是repr 结果: 我叫'meet'
数据集合
dict() 创建一个字典
d = dict(k='v',key1='v2') print(d) 结果: {'k': 'v', 'key1': 'v2'}
set() 创建一个集合
s = set([1,2,4,5,6]) print(s) 结果: {1, 2, 4, 5, 6}
其他相关
len() 返回一个对象的元素个数
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)
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.在调用的时候没有什么特别之处
像正常的函数调用既可
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}]
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}]
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]
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)
在Python2.x版本中recude是直接 import就可以的, Python3.x版本中需要从functools这个包中导入
龟叔本打算将 lambda 和 reduce 都从全局名字空间都移除, 舆论说龟叔不喜欢lambda 和 reduce
最后lambda没删除是因为和一个人写信写了好多封,进行交流然后把lambda保住了.
参考资料:
https://www.processon.com/view/link/5b4ee15be4b0edb750de96ac
递归
在函数中调用函数本身,就是递归
def func(): print('我是谁') func() func()
在python中递归的深度最大到998
def func(n): print(n) n+=1 func(n) func(1)
官方文档表示最大递归深度是1000
but in 2.0 the maximum recursion depth can be read and modified using sys.getrecursionlimit() and sys.setrecursionlimit(). The default value is 1000
递归的应用:
我们可以使用递归来遍历各种树形结构,比如我们的文件夹系统.可以使用递归来遍历该文件夹中的所有文件
import os def read(filepath, n): files = os.listdir(filepath) # 获取到当前⽂件夹中的所有⽂件 for fi in files: # 遍历⽂件夹中的⽂件, 这⾥获取的只是本层⽂件名 fi_d = os.path.join(filepath,fi) # 加⼊⽂件夹 获取到⽂件夹+⽂件 if os.path.isdir(fi_d): # 如果该路径下的⽂件是⽂件夹 print("\t"*n, fi) read(fi_d, n+1) # 继续进⾏相同的操作 else: print("\t"*n, fi) # 递归出⼝. 最终在这⾥隐含着return #递归遍历⽬录下所有⽂件 read('../python_s14/', 0)