Python之路第四天,基础(4)-装饰器,迭代器,生成器
装饰器
装饰器(decorator)是一种高级Python语法。装饰器可以对一个函数、方法或者类进行加工。在Python中,我们有多种方法对函数和类进行加工,比如在Python闭包中,我们见到函数对象作为某一个函数的返回结果。相对于其它方式,装饰器语法简单,代码可读性高。因此,装饰器在Python项目中有广泛的应用。
为了说明装饰器的使用方法,我们先写几个简单的例子,然后逐步深入。
简单的写了两个函数,他们的功能很简单就是打印一句话:
def f1():
print('hello,f1()')
def f2():
print('hello,f2()')
f1()
f2()
接着,我想让这两个函数都添加一个功能,就是在打印这一句话之前先打印'before'
def f1():
print('before')
print('hello,f1()')
def f2():
print('before')
print('hello,f2()')
f1()
f2()
试想,如果我们有100个这样的函数,那我们就需要改100次,改动的比较多,那我们有什么办法可以在不改变函数的情况下为每个函数添加这些功能,这时就用到了装饰器
def outer(func):
def inner():
print('before')
func()
return inner #返回函数名inner,这时 f1 = inner,也就是说f1被重新赋值成inner,
#调用f1实际上是执行的inner函数。inner函数又调用func 实际是调用
#的老的f1函数。
@outer
def f1():
print('hello,f1()')
@outer
def f2():
print('hello,f2()')
f1()
f2()
装饰器可以用def的形式定义,如上面代码中的outer。装饰器接收一个可调用对象作为输入参数,并返回一个新的可调用对象。装饰器新建了一个可调用对象,也就是上面的inner。inner中,我们增加了打印before功能,并通过调用func()来实现原有函数的功能。
定义好装饰器后,我们就可以通过 @ 语法使用了。在函数f1和f2定义之前调用 @outer,我们实际上将f1或f2传递给outer,并将outer返回的新的可调用对象赋给原来的函数名(f1或f2)。 所以,当我们调用f1()的时候,就相当于:
f1 = outer(f1)
f1()
上面例子函数都不带参数,下面我们讲一下带参数的函数装饰器的使用:
def outer(func):
def inner(s):
print('before')
func(s)
return inner
@outer
def f1(s):
print(s)
@outer
def f2(s):
print(s)
s1 = 'hello,f1()'
s2 = 'hello,f2()'
f1(s1)
f2(s2)
和上面的不带参数的其实没多大的变化,只是你函数带几个参数,inner也得带几个参数,然后func也就是老的f1或f2也得带上参数。
函数还有一个特性就是有返回值,那我们下面讲一下带有返回值的函数该怎么用:
def outer(func):
def inner(s):
print('before')
return func(s)
return inner
@outer
def f1(s):
print(s)
return 'Successful call f1'
@outer
def f2(s):
print(s)
return 'Successful call f2'
s1 = 'hello,f1()'
s2 = 'hello,f2()'
res1 = f1(s1)
res2 = f2(s2)
print(res1)
print(res2)
上面例子函数只带了一个参数,下面我将函数改成不定参数:
def outer(func):
def inner(*args, **kwargs):
print('before')
return func(*args, **kwargs)
return inner
@outer
def f1(s):
print(s)
return 'Successful call f1'
@outer
def f2(s):
print(s)
return 'Successful call f2'
s1 = 'hello,f1()'
s2 = 'hello,f2()'
res1 = f1(s1)
res2 = f2(s2)
print(res1)
print(res2)
双层装饰器,下面用用户管理系统举例
# 装饰器,判断是否登录
def is_login(func):
"""
装饰器,在使用功能之前判断用户是否登录,没登录是不能使用某些功能的
:param func: 使用装饰器的函数的函数名
:return: 将新的函数名传回去赋值给使用装饰器的函数
"""
def inner(*args, **kwargs):
if USER_INFO['is_login']:
return func(*args, **kwargs)
else:
print('\033[31m您还未登录,请登录!\033[0m')
return inner
# 装饰器,判断用户是否是管理员
def is_manager(func):
"""
装饰器,在使用某些功能之前判断用户是否为管理员,非管理员不能使用
:param func: 使用装饰器的函数的函数名
:return: 将新的函数名传回去赋值给使用装饰器的函数
"""
def inner(*args, **kwargs):
if USER_INFO['role'] == '1':
return func(*args, **kwargs)
else:
print('\033[31m您不是管理员,没有权限使用这些功能,抱歉!\033[0m')
return inner
@is_login
@is_manager
def show_info_all():
"""
显示所有用户信息,此功能只有登录后,并且是管理员才能使用。
:return: None
"""
x = PrettyTable(["姓名", "密码", "邮箱", "手机号码", "角色"])
x.align["姓名"] = "l"
x.padding_width = 1
user_dict = get_user_info()
users = []
for user in user_dict:
users.append(user)
users.sort()
for user in users:
# 将用户名插入到列表的第一个元素
user_dict[user].insert(0, user)
# 密码用6个*代替
user_dict[user][1] = '*'*6
if user_dict[user][4] == '1':
user_dict[user][4] = '管理员'
else:
user_dict[user][4] = '普通用户'
x.add_row(user_dict[user])
print(x)
双层装饰器的执行顺序是从上往下,如上,先判断用户是否登录,再判断用户是否为管理员;然后代码解释的顺序是从下往上,例如先解释是否为管理员,然后再解释是否登录。
迭代器
迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件
特点:
- 访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容
- 不能随机访问集合中的某个值 ,只能从头到尾依次访问
- 访问到一半时不能往回退
- 便于循环比较大的数据集合,节省内存
例子:
>>> num = iter([1,2,3,4,5])
>>> num
<list_iterator object at 0x101402630>
>>> num.__next__()
1
>>> num.__next__()
2
>>> num.__next__()
3
>>> num.__next__()
4
>>> num.__next__()
5
>>> num.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
生成器
一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator);如果函数中包含yield语法,那这个函数就会变成生成器;
def func():
yield 1
yield 2
yield 3
yield 4
上述代码中:func是函数称为生成器,当执行此函数func()时会得到一个迭代器。
>>> temp = func()
>>> temp.__next__()
1
>>> temp.__next__()
2
>>> temp.__next__()
3
>>> temp.__next__()
4
>>> temp.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
例子:
利用生成器自定义range
def myrange(num):
start = -1
while True:
start = start + 1
if start >= num:
return
else:
yield start
利用迭代器访问range
x = myrange(4)
for i in x:
print(i)
Python之路第四天,基础(4)-装饰器,迭代器,生成器的更多相关文章
- python装饰器,迭代器,生成器,协程
python装饰器[1] 首先先明白以下两点 #嵌套函数 def out1(): def inner1(): print(1234) inner1()#当没有加入inner时out()不会打印输出12 ...
- python笔记3 闭包 装饰器 迭代器 生成器 内置函数 初识递归 列表推导式 字典推导式
闭包 1, 闭包是嵌套在函数中的 2, 闭包是内层函数对外层函数的变量(非全局变量)的引用(改变) 3,闭包需要将其作为一个对象返回,而且必须逐层返回,直至最外层函数的返回值 闭包例子: def a1 ...
- 【Python 函数对象 命名空间与作用域 闭包函数 装饰器 迭代器 内置函数】
一.函数对象 函数(Function)作为程序语言中不可或缺的一部分,但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性. 那到底什么是第一类对象(Firs ...
- Python学习---装饰器/迭代器/生成器的学习【all】
Python学习---装饰器的学习1210 Python学习---生成器的学习1210 Python学习---迭代器学习1210
- Python中的装饰器,迭代器,生成器
1. 装饰器 装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象. 强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式 装饰器的目标:在遵循1和2的 ...
- python之路递归、冒泡算法、装饰器
map使用 完整用户名登录,注册 冒泡排序 递归 def func(arg1,arg2): if arg1 == 0: print arg1, arg2 arg3 = arg1 + arg2 prin ...
- python中的装饰器迭代器生成器
装饰器: 定义:本质是函数(装饰其它函数) 为其它函数添加附加功能 原则: 1 不能修改被装饰函数源代码 2 不修改被装饰函数调用方式 实现装饰器知识储备: 1 函数即‘’变量‘’ 2 高阶函数 ...
- Python之路(第四十六篇)多种方法实现python线程池(threadpool模块\multiprocessing.dummy模块\concurrent.futures模块)
一.线程池 很久(python2.6)之前python没有官方的线程池模块,只有第三方的threadpool模块, 之后再python2.6加入了multiprocessing.dummy 作为可以使 ...
- python基础—函数装饰器
python基础-函数装饰器 1.什么是装饰器 装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能. 装饰器的返回值是也是一个函数对象. 装饰器经常用于有切 ...
- 十. Python基础(10)--装饰器
十. Python基础(10)--装饰器 1 ● 装饰器 A decorator is a function that take a function as an argument and retur ...
随机推荐
- php variance
function variance ($a) { /** variable and initializations */ $the_variance = 0.0; $the_mean = 0.0; $ ...
- jQuery + css 公告从左往右滚动
$(function() { // 公告滚动 $(".notice-content").textScroll(); }); /** * 从右往左滚动文字 * @returns {u ...
- css3投影讲解、投影
迷茫了好一段时间,今天开始整理一下自己,同时也整理下新的知识. CSS3: 从头开始做起:现在在页面中用到最多的是图片/容器投影,文字投影: 接下来就总结一个投影问题: box-shadow:阴影类型 ...
- YouComplete:vim自动补全插件
在github上下载插件,按照README.md安装 1,ubuntu安装 vim插件管理:vundle插件安装同样按照 README.md 操作 2,user guide General Usage ...
- 使用事件CreateEvent注意事项
HANDLECreateEvent( LPSECURITY_ATTRIBUTESlpEventAttributes,// 安全属性 BOOLbManualReset,// 复位方式 BOOLbInit ...
- linux function
#!/bin/bash function sayHello() { #这里的{ 和它前面的)之间可以没有空格 echo "Hello $1" } sayHello 'Neeky'
- oracle表空间使用率统计查询
今天发现有一张采样表从1月5号开始不记录数据了,所以想查看一下表空间使用率,在网上零零散散找了很多资料,现在记录如下,也不知道哪一个最准确.还有一个就是网上拷贝的sql代码格式太乱了,不好看,找到一个 ...
- java.lang.NoClassDefFoundError: org/apache/commons/io/output/DeferredFileOutputStream(转)
java.lang.NoClassDefFoundError: org/apache/commons/io/output/DeferredFileOutputStream 使用Tomcat的Manag ...
- 【测试Json的多空格问题】
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- [转]ArcGIS移动客户端离线地图的几种解决方案
原文地址:http://blog.chinaunix.net/uid-10914615-id-3023158.html 移动GIS中,通常将数据分为两大类:basemap layer和operatio ...