装饰器

装饰器(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的文件

特点:

  1. 访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容
  2. 不能随机访问集合中的某个值 ,只能从头到尾依次访问
  3. 访问到一半时不能往回退
  4. 便于循环比较大的数据集合,节省内存

例子:

>>> 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)-装饰器,迭代器,生成器的更多相关文章

  1. python装饰器,迭代器,生成器,协程

    python装饰器[1] 首先先明白以下两点 #嵌套函数 def out1(): def inner1(): print(1234) inner1()#当没有加入inner时out()不会打印输出12 ...

  2. python笔记3 闭包 装饰器 迭代器 生成器 内置函数 初识递归 列表推导式 字典推导式

    闭包 1, 闭包是嵌套在函数中的 2, 闭包是内层函数对外层函数的变量(非全局变量)的引用(改变) 3,闭包需要将其作为一个对象返回,而且必须逐层返回,直至最外层函数的返回值 闭包例子: def a1 ...

  3. 【Python 函数对象 命名空间与作用域 闭包函数 装饰器 迭代器 内置函数】

    一.函数对象 函数(Function)作为程序语言中不可或缺的一部分,但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性. 那到底什么是第一类对象(Firs ...

  4. Python学习---装饰器/迭代器/生成器的学习【all】

    Python学习---装饰器的学习1210 Python学习---生成器的学习1210 Python学习---迭代器学习1210

  5. Python中的装饰器,迭代器,生成器

    1. 装饰器 装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象. 强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式 装饰器的目标:在遵循1和2的 ...

  6. python之路递归、冒泡算法、装饰器

    map使用 完整用户名登录,注册 冒泡排序 递归 def func(arg1,arg2): if arg1 == 0: print arg1, arg2 arg3 = arg1 + arg2 prin ...

  7. python中的装饰器迭代器生成器

    装饰器: 定义:本质是函数(装饰其它函数) 为其它函数添加附加功能 原则: 1 不能修改被装饰函数源代码    2 不修改被装饰函数调用方式 实现装饰器知识储备: 1 函数即‘’变量‘’ 2 高阶函数 ...

  8. Python之路(第四十六篇)多种方法实现python线程池(threadpool模块\multiprocessing.dummy模块\concurrent.futures模块)

    一.线程池 很久(python2.6)之前python没有官方的线程池模块,只有第三方的threadpool模块, 之后再python2.6加入了multiprocessing.dummy 作为可以使 ...

  9. python基础—函数装饰器

    python基础-函数装饰器 1.什么是装饰器 装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能. 装饰器的返回值是也是一个函数对象. 装饰器经常用于有切 ...

  10. 十. Python基础(10)--装饰器

    十. Python基础(10)--装饰器 1 ● 装饰器 A decorator is a function that take a function as an argument and retur ...

随机推荐

  1. 对WEB标准以及W3C的理解与认识 - 提高网页加载速度

    在写代码的时候应该注意: 1.标签闭合 2.标签小写 3.不能随意嵌套 提高被搜索引擎搜到几率: mate中的name变量[其中keywords和description尤其重要] Meta name= ...

  2. VS2013 编译错误 error: MSB8031

    VS2010 创建的 MFC 程序,用 VS2013 打开后编译出现错误: C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microso ...

  3. jquery学习之笔记一

    jquery是继prototype后一个很好用的javascript库.jquery是一个轻量级的库,拥有强大的选择器,出色的DOM操作,可靠的事件处理,完善的兼容性和链式操作等功能. window. ...

  4. 常量 - PHP手册笔记

    常量语法 常量在脚本执行期间其值不能改变.常量大小写敏感,传统上常量标识符总是大写.常量一旦定义就不能被重新定义或取消定义,常量的值只能是标量. 可以用define()函数来定义常量,也可以使用con ...

  5. Leetcode 242 Valid Anagram pytyhon

    题目: Given two strings s and t, write a function to determine if t is an anagram of s. For example,s  ...

  6. javascript闭包特性

    http://www.cnblogs.com/rubylouvre/archive/2009/07/24/1530074.html var name = "The Window"; ...

  7. 要熟悉QT的所有类和元类系统,当然还有qmake

    http://doc.qt.io/qt-5/classes.html http://doc.qt.io/qt-5/gettingstarted.html http://doc.qt.io/qt-5/q ...

  8. windows 2003 server 安装 .NET Framework 2.0环境

    下载net2.0安装包,这里提供官方下载地址: http://www.microsoft.com/zh-cn/download/confirmation.aspx?id=1639 然后运行exe文件, ...

  9. 1、什么是Lucene,Lucene能干什么

    1.什么是lucene  Lucene是一个全文搜索框架,而不是应用产品.因此它并不像http://www.baidu.com/ 或者google Desktop那么拿来就能用,它只是提供了一种工具让 ...

  10. nginx添加需要代理的域名 配置

    dap.cns.360buy.com为需要nginx代理的域名,被代理的端口为:8089,配置需要在${nginx_home}/conf/nginx.conf的文件中加入如下配置即可 upstream ...