Python装饰器、生成器、内置函数、json
这周学习了装饰器和生成器,写下博客,记录一下装饰器和生成器相关的内容。
一、装饰器
装饰器,这个器就是函数的意思,连起来,就是装饰函数,装饰器本身也是一个函数,它的作用是用来给其他函数添加新功能,比如说,我以前写了很多代码,系统已经上线了,但是性能比较不好,现在想把程序里面每个函数都加一个功能,用来统计每个函数的运行时间是多少,找出来运行比较慢的函数,来优化代码,就需要添加一个新的功能,来统计程序的运行时间,那这样的话,就得修改每个函数了,需要改代码,但是代码特别多,改完了公司倒闭了,这时候装饰器就能排上用场了,它可以不改变原有的函数,原来的函数和原来一模一样,什么都不需要改变,只需要在函数外部加上调用哪个装饰器就可以了。so,装饰器的作用就是不改变原来函数的调用方式,不改变原来函数的代码,给它增加了一个新功能。但是不改变函数,给它增加新功能,那是不可能的,装饰器只不过是偷偷改变了原来的函数而已,而原来的函数不知不觉。
使用装饰器需要了解的知识:
1、函数即变量,这个是什么意思呢,在python里面函数就是一个变量,函数名就是一个变量,这个函数名里面存的是这个函数的内存地址,它把函数体放到内存里,在调用的时候从函数名里面的这个内存地址找到函数体然后运行这个函数。前面的博客说函数的时候,说过函数名后面加上小括号就是调用这个函数,如果只写这个函数名的话,打印一下就是这个函数的内存地址。
def test():
print('nihao')
prinit(test)#打印函数的内存地址
test()#调用函数
运行结果:
<function test at 0x100699950>
nihao
2、高阶函数,高阶函数在上篇博客里面写了,如果函数的入参是一个函数的话,那么这个函数就是一个高阶函数。
3、函数嵌套,函数嵌套,函数嵌套就是在函数里面再定义一个函数,这就是函数嵌套,而不是说在函数里面再调用一个函数。
def test():
def test1():
print('test1')
print('test')
了解了上面的这些知识之后,就可以使用装饰器了,下面我写一个简单的装饰器,用来统计函数的运行时间,然后将被统计的函数作为参数传递
import time
def bar():
time.sleep(3)
print('in the bar')
def test1(func):
start_time=time.time()
func()
stop_time = time.time()
print('the func run time is %s' % (stop_time - start_time))
test1(bar)
运行结果:
in the bar
the func run time is 3.000171661376953
但是这样的话,我们每次都要将一个函数作为参数传递给test1函数。改变了函数调用方式,之前执行业务逻辑时,执行运行bar(),但是现在不得不改成test1(bar)。此时就要用到装饰器。我们就来想想办法不修改调用的代码;如果不修改调用代码,也就意味着调用bar()需要产生调用test1(bar)的效果。我们可以想到将test1赋值给bar,但是test1似乎带有一个参数……想办法把参数统一吧!如果test1(bar)不是直接产生调用效果,而是返回一个与foo参数列表一致的函数的话……就很好办了,将test1(bar)的返回值赋值给bar,然后,调用bar()的代码完全不用修改!
import time
def timmer(func):
def deco():
start_time=time.time()
func()
stop_time=time.time()
print('the func run time is %s'%(stop_time-start_time))
return deco
def bar():
time.sleep(3)
print('in the bar')
bar=timmer(bar)
bar()
运行结果:
in the bar
the func run time is 3.000171661376953
函数timmer就是装饰器,它把执行真正业务方法的func包裹在函数里面,看起来像bar被timmer装饰了。如果我们要定义函数时使用装饰器,避免使用赋值语句bar=timmer(bar),要用到装饰器的语法糖@,语法糖的意思就是一种语法的简写,它使代码看起来简洁,上面的bar=timmer(bar)和@timmter bar()是一样的。这样写的话,看起来也比较高大上一些。
import time
def timmer(func):
def deco():
start_time=time.time()
func()
stop_time=time.time()
print('the func run time is %s'%(stop_time-start_time))
return deco
@timmer
def bar():
time.sleep(3)
print('in the bar')
bar()
运行结果:
in the bar
the func run time is 3.000171661376953
这样,我们就提高了程序的可重复利用性,当其他函数需要调用装饰器时,可以直接调用。装饰器在Python使用如此方便都要归因于Python的函数能像普通的对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。
如果要装饰的函数带有参数时,因为你也不知道到底被装饰的函数会传什么参数,所以可以使用可变参数和关键字参数来接收所有的参数,这两种参数也在上一篇博客中写过了。代码如下:
import time
def timmer(func):
def deco(*arg,**kwarg):
start_time=time.time()
func(*arg,**kwarg)
stop_time=time.time()
print('the func run time is %s'%(stop_time-start_time))
return deco
@timmer
def test1():
time.sleep(1)
print('in the test1')
@timmer
def test2(name,age) :
time.sleep(2)
print('in the test2:',name,age)
test1()
test2('niuniu,18)
运行结果:
in the test1
the func run time is 1.0000572204589844
in the test2: niuniu 18
the func run time is 2.0001144409179688
下面再用装饰器,写一个实例,判断用户是否登陆,逻辑是这样,运行程序,打印菜单,如果是选择后台管理和添加商品,就判断用户是否登录,如果没有登录的话,让用户登录,如果是查看商品就不需要登录。
import os
def login():
'''
登录函数,登录成功的话,写如user这个文件
:return:
'''
print('login')
username = input('请输入账号')
password = input('请输入密码')
if username =='admin' and password=='':
print('登录成功!')
with open('user','a+') as fw:
fw.write(username)
else:
print('账号密码错误!')
#是否登录校验装饰器
def auth(func):
def check(*args,**kwargs):
if os.path.exists('user'):#判断用户文件是否存在
func(*args,**kwargs)#存在的话,调用原来的函数
else:
print('你未登陆!')#不存在的话,调用登录函数
login()
return check
@auth
def admin():
print('welcome!')
def show():
print('show!')
@auth
def add():
print('add product!')
def menu():#打印菜单函数
msg= '''
1 : 后台管理
2 : 查看商品
3 : 添加商品
'''
print(msg)
m = {
"":admin,
"":show,
"":add
}
choice = input('请输入你的选择:').strip()
if choice in m:
m[choice]()#调用对应的函数
else:
print('输入错误!')
menu()
if __name__ == '__main__':
menu()
二、生成器
生成器是什么东西呢,可以理解为,生成器也是一个迭代的对象,和list似的,里面存数据,和list不同的是,list在定义的时候数据就已经在内存里面了,而生成器是,你用到这个里面的数据的时候它才会生成,这样就比较省内存,因为是需要这个值的时候,才会在内存里面产生。生成器是按照某种规则生成的一个列表,用到这个列表的中的数据时,才会在内存里生成,但是由于生成器是根据某种规则产生的,必须得知道前一个值是多少,才能知道后面的那个值是多少,所以不能像list那样,直接用索引去取值。
1、 列表生成式,在第二篇博客里面我写了三元运算符,和那个有点像,如果要生成列表[1x1, 2x2, 3x3, ..., 10x10]怎么做?除了循环还可以用一行语句代替循环生成
list=[x*x for x in range(1,11)]
print(list)
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]#运行结果
这种写法就是Python的列表生成式,写列表生成式时,把要生成的元素 x * x 放到前面,后面跟 for 循环,就可以把list创建出来。
2、生成器:要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator。
g=(x*x for x in range(1,11))
print(g)
<generator object <genexpr> at 0x1036ff258>#运行结果
创建list和generator的区别仅在于最外层的[]和()。list的元素我们可以一个个打印出,如果要打印generator中的元素需要借助next方法
g=(x*x for x in range(1,11))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
运行结果:
1
4
9
16
但是generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。可以通过for循环来迭代它,并且不需要关心StopIteration的错误。
g=(x*x for x in range(1,11))
for i in g:
print(i)
运行结果:
1
4
9
16
25
36
49
64
81
100
你可能比较纳闷,感觉生成器没有列表生成试好用,为什么要用生成器呢,先看下面这个例子:
mylist = [x*x for x in range(3)]
print mylist
mygen=(x*x for x in range(3))
print mygen
代码解释
行1生成一个列表list,这个列表的每个元素由x的平方组成,x的取值为range(3),也就是0,1,2。因此这个列表有三个元素:0的平方(0),1的 平方(1),2的平方(4)。
行2打印出这个列表的内容,显示结果果真是[0,1,4]
行3生成的是一个生成器generator,它和行1唯一的不同就是它用的小括号。但是产生的返回值并不再是一个列表了。那是什么呢?
行4想要打印出来这个mygen生成器,但结果显示是这样的: <generator object <genexpr> at 0x022F8030> 一个内存地址。
怎么理解这个生成器的概念呢?如上例子所示,其实这个mygen生成器就是用来生成x的平方的东西。这个结果呢就存在上面显示的内存地址里。但是由于你还没说你到底要谁的平方,所以只能看到个地址不能看到答案。mylist则不同,它是把所有答案穷举列在内存里了,你需要哪个就从里面找出来即可,比较耗费资源。而mygen则还没生成,你需要哪个我现制造一个出来放在一个内存空间显示,节省了资源。
用函数生成generator:generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。例如,斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:
def fib(max):
n,a,b=0,0,1
while n<max:
print(b)
a,b=b,a+b
n=n+1
return 'done'
f=fib(6)
运行结果:
1
1
2
3
5
8
上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:
def fib(max):
n,a,b=0,0,1
while n<max:
yield b
a,b=b,a+b
n=n+1
return 'done'
x = fib(6)
print(x)
print(x.__next__())
print(x.__next__())
print(x.__next__())
print(x.__next__())
x调用了fib(max),当max=15时,进入fib()生成器,执行到yield b, 返回b值以及整个生成器暂停的状态,将b值赋给x,由于是生成器,继续从上次截断的位置开始执行,b值赋给a, a+b值赋给b,又因为是while语句,则继续while循环,yield b值,循环暂停跳出返回b值及生成器状态,把b值赋给x, 如此往复,一直循环到while结束。
x被赋了fib(6)这个生成器,每一次执行m.__next__()函数就会打印下一个值。
注意:
1. 每个生成器只能使用一次。比如上个例子中的x生成器,一旦打印完x的6个值,就没有办法再打印x的值了,因为已经吐完了。
2. yield一般都在def生成器定义中搭配一些循环语句使用,比如for或者while,以防止运行到生成器末尾跳出生成器函数,就不能再yield了。有时候,为了保证生成器函数永远也不会执行到函数末尾,会用while True: 语句,这样就会保证只要使用next(),这个生成器就会生成一个值,是处理无穷序列的常见方法。
三、内置函数
print(all([1,2,3,4]))#判断可迭代的对象里面的值是否都为真
print(any([0,1,2,3,4]))#判断可迭代的对象里面的值是否有一个为真
print(bin(10))#十进制转二进制
print(bool('s'))#把一个对象转换成布尔类型
print(bytearray('abcde',encoding='utf-8'))#把字符串变成一个可修改的bytes
print(callable('aa'))#判断传入的对象是否可调用
print(chr(10))#打印数字对应的ascii
print(ord('b'))#打印字符串对应的ascii码
print(dict(a=1,b=2))#转换字典
print(dir(1))#打印传入对象的可调用方法
print(eval('[]'))#执行python代码,只能执行简单的,定义数据类型和运算
print(exec('def a():pass'))#执行python代码
print(filter(lambda x:x>5,[12,3,12,2,1,2,35]))#把后面的迭代对象根据前面的方法筛选
print(map(lambda x:x>5,[1,2,3,4,5,6]))#把后面的迭代对象根据前面的方法判断,返回布尔值
print(frozenset({1,2,3,3}))#定义一个不可修改的集合
print(globals())#返回程序内所有的变量,返回的是一个字典
print(locals())#返回局部变量
print(hash('aaa'))#把一个字符串哈希成一个数字
print(hex(111))#数字转成16进制
print(max(111,12))#取最大值
print(oct(111))#把数字转换成8进制
print(round(11.11,2))#取几位小数
print(sorted([2,31,34,6,1,23,4]))#根据字典序排列排序
print(sorted(["car" ,"doggies" ,"carriage" , "cats" , "koala"], key=len)) #根据长度排列排序
dic={1:2,3:4,5:6,7:8}
print(sorted(dic.items()))#按照字典的key排序
print(sorted(dic.items(),key=lambda x:x[1]))#按照字典的value排序
__import__('decorator')#导入一个模块
四、匿名函数
如果这个函数只执行一次的话,那就可以定义一个匿名函数,匿名函数只能处理比较简单的处理逻辑,只能写简单的表达式,不能写循环 判断,比如三元运算符。
匿名函数定义使用lambda关键字,比如说要定义一个函数,它的功能是返回两个数相加和,就可以使用lambda,代码如下:
s = lambda x,y:x+y#冒号号前面的x,y是入参,冒号后面的是返回值
print(s(1,9))#因为函数即变量,如果没有定一个变量把lambda存起来的话,它就不在内存里,没法执行,所有把它放到s这个变量里面
五、json处理
json是一种所有语言中都通用的key-value数据结构的数据类型,很像python中的字典,json处理使用json模块,json模块有下面常用的方法:
import json
dic = {"name":"niuniu","age":18}
print(json.dumps(dic))#把字典转成json串
fj = open('a.json','w')
print(json.dump(dic,fj))#把字典转换成的json串写到一个文件里面
s_json = '{"name":"niuniu","age":20,"status":true}'
print(json.loads(s_json))#把json串转换成字典
fr = open('b.json','r')
print(json.load(fr))#从文件中读取json数据,然后转成字典
Python装饰器、生成器、内置函数、json的更多相关文章
- Python装饰器、内置函数之金兰契友
装饰器:装饰器的实质就是一个闭包,而闭包又是嵌套函数的一种.所以也可以理解装饰器是一种特殊的函数.因为程序一般都遵守开放封闭原则,软件在设计初期不可能把所有情况都想到,所以一般软件都支持功能上的扩展, ...
- 万恶之源 - Python装饰器及内置函数
装饰器 听名字应该知道这是一个装饰的东西,我们今天就来讲解一下装饰器,有的铁子们应该听说,有的没有听说过.没有关系我告诉你们这是一个很神奇的东西 这个有多神奇呢? 我们先来复习一下闭包 def fun ...
- Python装饰器及内置函数
装饰器 听名字应该知道这是一个装饰的东西,我们今天就来讲解一下装饰器,有的铁子们应该听说,有的没有听说过.没有关系我告诉你们这是一个很神奇的东西 这个有多神奇呢? 我们先来复习一下闭包 def fun ...
- python笔记5:装饰器、内置函数、json
装饰器 装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象. 先看简单例子: def run(): time.sleep(1 ...
- 【Python 函数对象 命名空间与作用域 闭包函数 装饰器 迭代器 内置函数】
一.函数对象 函数(Function)作为程序语言中不可或缺的一部分,但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性. 那到底什么是第一类对象(Firs ...
- python 之 面向对象(多态性、装饰器方法 内置函数补充)
7.6 多态性 1 什么是多态性 多态指的是同一种事物多种形态,在程序中用继承可以表现出多态.多态性:可以在不用考虑对象具体类型的前提下而直接使用对象下的方法 2.为什要用多态 用基类创建一套统一的规 ...
- 文成小盆友python-num4 装饰器,内置函数
一 .python 内置函数补充 chr() -- 返回所给参数对应的 ASCII 对应的字符,与ord()相反 # -*- coding:utf-8 -*- # Author:wencheng.z ...
- Python--函数对象@命名空间与作用域@包函数@装饰器@迭代器@内置函数
一.函数对象 函数(Function)作为程序语言中不可或缺的一部分,但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性. 那到底什么是第一类对象(Firs ...
- day0318装饰器和内置函数
一.装饰器 1.装饰器: 解释:装饰器的本事就是一个函数,不改动主代码的情况下,增加新功能.返回值也是一个函数对象. 2.装饰器工作过程 import time def func(): print(' ...
- python 类(object)的内置函数
python 类(object)的内置函数 # python 类(object)的内置函数 ### 首先 #### 以__双下划线开头的内置函数 __ #### __往往会在某些时候被自动调用,例如之 ...
随机推荐
- 关于JavaScript的数组随机排序
昨天了解了一下Fisher–Yates shuffle费雪耶兹随机置乱算法,现在再来看看下面这个曾经网上常见的一个写法: function shuffle(arr) { arr.sort(functi ...
- 教你如何构建异步服务器和客户端的 Kotlin 框架 Ktor
Ktor 是一个使用 Kotlin 以最小的成本快速创建 Web 应用程序的框架. Ktor 是一个用于在连接系统(connected systems)中构建异步服务器和客户端的 Kotlin 框架. ...
- MySQL笔记(五)MySQL 角色与SQL CHECK约束
MySQL ROLE MySQL 8.0 Reference Manual / Security / MySQL User Account Management / Using Roles ...
- Executor简析
本文只做简要解析,实际情形下我们多用spring的taskExecutor 直接使用new Thread()创建线程的缺点: 1.new Thread()耗费性能 2.调用new Thread()创建 ...
- 使用liner、feather、multiband对已经拼接的数据进行融合
所谓"blend",英文解释为“vt. 混合vi. 混合:协调n. 混合:掺合物”这里应该理解为是图像数据的融合.这是“识别->对准->融合”的最后一步.融合是决定拼接 ...
- 20145305 《网络对抗》Web安全基础实践
实践过程及结果截图 Phishing with XSS 在文本框里面写一个钓鱼网站代码就可以了 </form> <script> function hack(){ XSSIma ...
- 20145331魏澍琛《网络对抗》Exp2 后门原理与实践
20145331魏澍琛<网络对抗>Exp2 后门原理与实践 基础问题回答 (1)例举你能想到的一个后门进入到你系统中的可能方式? 上网时候弹出一个广告说你中奖了,或者你可以贷款10万元之类 ...
- 打开vi后提示The ycmd server SHUT DOWN (restart with :YcmRestartServer)该如何处理
答:进入YouCompleteMe的安装目录安装一些必要的依赖 比如:笔者将YouCompleteMe安装到了~/.vim/bundle目录下,那么执行以下操作: cd ~/.vim/bundle/Y ...
- P4113 [HEOI2012]采花 (莫队TLE)
思路 update 11.2 树状数组AC 本题莫队过不去,会TLE ----------------------- 但也是个不错的莫队练手题 ------------------------ 毕竟C ...
- 1-20 RHEL7的启动原理和服务控制
大纲: RHEL7启动原理 RHEL7服务启动配置 网络概述 发布内网服务器 ############################################################ ...