python修饰器classmate_python3大器----装饰器,迭代器,生成器
目录
一:闭包:
1:闭包的作用和定义:
2:闭包的形成条件:
3:闭包的经典案例:
4:闭包的原理:
5: 闭包中使用外部函数变量:
二:装饰器:
1:装饰器的定义和作用:
2:装饰器经典案例分析:
3: 装饰器的两种写法:
4:通用装饰器的写法:
5:多个装饰器的执行流程:
6:带参装饰器:
7:类装饰器:
8:装饰器的反装饰:
三:迭代器:
1:可迭代对象:
2:对象能够迭代的条件
3:什么是迭代器?
4:解析for循环遍历的本质:
5:range python2与python3的区别:
6:利用生成器实现斐波那契数列:
四:生成器:
五:探索for循环的流程:
一:闭包:
1:闭包的作用和定义:
作用:保存外部函数内的变量,不会随着外部函数调用完而销毁。
定义:在函数嵌套的前提下,内部函数使用了外部函数的变量,外部函数返回了内部函数的对象,我们把这个使用外部函数变量的内部函数称为闭包。
2:闭包的形成条件:
1: 内部函数使用了外层函数的变量。
2:外部函数返回了内部函数的对象。
3:闭包的经典案例:
def func_out(num1):
def func_inner(num2):
result = num1 + num2;
print("结果是:",result)
return func_inner
f = func_out(1)
4:闭包的原理:
变量当自己的引用计数等于0的时候就会被销毁。
当将1赋值给num1的时候num1的引用计数是1,然后定义fun_inner,由于fun_inner里面用到了num1(result = num1 + num2;),所以num1的引用计数变成了2,最后函数调用完成时,销毁所有变量(本质是引用变量减一),所以num1引用计数又变成了1。所以外层函数调用完,变量是不会销的。
5: 闭包中使用外部函数变量:
闭包中使用外部函数的变量需要使用nonlocal声明,否则使用的是闭包内部自己定义的变量。
def func_out(num1):
def func_inner(num2):
nonlocal num1
num1 = 10
result = num1 + num2
print("结果是:", result)
return func_inner
f = func_out(1)
f(2)
二:装饰器:
1:装饰器的定义和作用:
1:定义与作用:
答:在不修改原函数及其调用方式的情况下对原函数功能进行扩展。
2:装饰器和闭包的区别:
装饰器外层函数只有一个变量,且变量类型是函数类型。
2:装饰器经典案例分析:
def check(fn):
def inner():
print("请先登录")
fn()
return inner
def comment():
print("发表评论")
comment = check(comment)
comment()
分析:comment = check(comment)
答:
1:将被装饰函数传入装饰器的外层函数,由装饰器 的内层函数调用,也就是装饰器内层函数可以调用被装饰函数。
2:外层函数返回内层函数对象,达到的效果是最终的对象执行的是内层函数。
3:这样在内层函数中增加功能,就可以达到不改变原函数及其调用方式的情况下对原函数功能进行扩展。
3: 装饰器的两种写法:
: 装饰器外层函数,传入被装饰函数。
def check(fn):
def inner():
print("请先登录")
fn()
return inner
def comment():
print("发表评论")
# 函数调用的写法
comment = check(comment)
comment()
: 语法糖写法:
def check(fn):
def inner():
print("请先登录")
fn()
return inner
# 语法糖写法:
@check
def comment():
print("发表评论")
comment()
4:通用装饰器的写法:
def func_out(fn):
def func_inner(*args,**kwargs):
print("----输出执行函数前的增加功能")
data = fn(*args,**kwargs)
print("-----输出函数执行后的增加功能")
return data
return func_inner
5:多个装饰器的执行流程:
def add_div(fn2):
def inner_div():
return "
"
return inner_div
def add_p(fn1):
def inner_p():
return "
"+fn1()+ "
"
return inner_p
@add_div
@add_p
def content():
return "人生苦短,我用python!"
main_content = content()
print(main_content)
分析装饰的过程:
1: 装饰的过程是先装饰近的再装饰远的。
2:先进行@add_p, 被修改函数content传入add_p, 此时fn1指向被修饰函数。add_p返回自己的内层函数,则此时的main_content指向的是inner_p这个内层函数。
3:再进行@add_div:将inner_p传入add_div,此时fn2指向fn1的内层函数。add_div返回自己的内层函数,所以main_content指向的是inner_div这个内层函数。
4:最终结果是:main_content 指向inner_div, fn2指向inner_p, fn1指向content。
分析调用过程(递归过程):
content()实际上等于inner_div(),所以先调用inner_div,然后执行 fn2(),实际上是inner_p(),然后执行fn1实际上是content()函数。然后从content函数开始向上返回,content向上返回给inner_p:"人生苦短,我用python!",inner_p组合后向上返回给inner_div:
人生苦短,我用python!
,然后inner_div向上返回给主程序
人生苦短,我用python!
6:带参装饰器:
在装饰器外层再套一层函数用来传递参数,返回内层函数。
由于这个外层函数传入变量,返回内层函数,内层函数使用外层函数变量,所以修饰器实际上是一个闭包了,而披上的是外层函数,闭包内可以访问外层函数变量。
@logging("+"):可以拆分成两部分:logging("+")传递给装饰器外层的函数,返回一个装饰器类型的对象out_num 然后@和out_num 又拼接成语法糖。
def logging(flag):
def out_num(fn):
def inner_num(x,y):
if flag == "+":
print("这是加法操作的准备工作")
sum2 = fn(x,y)
return sum
return inner_num
return out_num
@logging("+")
def add_num(a,b):
sum = a+b
return sum
sum = add_num(1,2)
print(sum)
7:类装饰器:
1: 一个类的__init__方法能够传递一个函数,就相当于装饰器的外层函数了。
2:一个类的__call__方法中调用传入的函数,就相当于装饰器的内层函数了。
3: 在__all__中实现拓展功能。
综上所述,一个类实现__init__方法和实现__call__方法就相当于一个装饰器了。
class Check(object):
def __init__(self ,fn):
self.__fn = fn;
def __call__(self, *args, **kwargs):
print("发表评论前的准备工作。。。")
self.__fn()
@Check
def comment():
print("发表评论")
comment()
8:装饰器的反装饰:
问题:使用语法糖装饰时, 被装饰器装饰过的函数,打印函数的注释和函数名,发现都改成了装饰器内层函数名和注释了,如果想要用自己原来的函数名和注释,怎么做?
解决方案一:导入wraps, 然后装饰装饰器的内层函数: @wraps(传入的函数名)
解决方案二:不再使用语法糖装饰,改用函数调用的方式。
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:可迭代对象:
如果一个类实现了__iter__方法,则根据这个类创建出来的对象都是可迭代对象。
2:对象能够迭代的条件
1: 这个类实现了__iter__方法。
2:这个类的__iter__方法必须返回一个对象。
3:这个被返回的对象的类(迭代器),必须实现了__iter__和__next__方法。
3:什么是迭代器?
由实现了__iter__方法和__next__方法的类,创建出来的对象,称为迭代器。
4:解析for循环遍历的本质:
for循环遍历的流程
1:判断这个classmate是不是可迭代对象,发现Classmate实现了__iter__方法,所以是可以迭代的。
2:判断classmate是不是可以迭代,发现__iter__返回的是自己,而自己实现了__iter__和__next__方法,所以可以迭代。
3:此时python内部调用iter()方法获取到一个迭代器。
4:接下来每次遍历迭代器的时候,就调用一次netxt(迭代器),这个方法。
5:当遍历到最后的时候,抛出StopIteration异常,python自动捕获后,停止遍历。
from collections import Iterable, Iterator
class Classmate(object):
def __init__(self):
self.names = list()
self.current_num = 0
def add(self, name):
self.names.append(name)
def __iter__(self):
# 1:将自己的引用传递过去
return self
def __next__(self):
if self.current_num < len(self.names):
ret = self.names[self.current_num]
self.current_num += 1
return ret
else:
raise StopIteration
classmate =Classmate()
classmate.add("张三")
classmate.add("李四")
classmate.add("王二麻子")
for name in classmate:
print(name)
5:range python2与python3的区别:
面试题:range与xrange的区别:
答: python2,range()函数返回的是一个数组。python3时,range函数返回的是一个可以迭代器。优点在于如果range的数量很大,列表将占用很多的资源,但是迭代器会一个一个的生成,占用的空间很少。这也是python2中, range和xrange的区别。
6:利用生成器实现斐波那契数列:
四:生成器:
生成器是一种特殊的迭代器。
一个函数的里面使用到yield,则这个函数就是生成器了。
yield作用:让程序在yield关键字处暂停,返回yield处的值。
生成器的执行本质也是调用next()函数。
使用生成器完成斐波那契额数列:
通过send启动生成器:
解释过程:当执行到obj = create_num(10)的时候,相当于把10给了all_num,然后创建了一个生成器对象。当执行到ret = next(obj)的时候,生成器开始执行,执行到yield的时候,生成器把此时a的值给了ret,然后程序暂停。然后再打印print(ret)。当执行到ret = obj.send(‘hahaha’)时,send函数也能将程序唤醒,并把输入的值传给循环中的ret, 然后程序继续执行。
五:探索for循环的流程:
: 直接遍历尝试:
class Classmate(object):
def __init__(self):
self.names = list()
def add(self, name):
self.names.append(name)
classmate =Classmate()
classmate.add("张三")
classmate.add("李四")
classmate.add("王二麻子")
for name in classmate:
print(name)
如果直接遍历会报错误:
:实现__iter__后:
class Classmate(object):
def __init__(self):
self.names = list()
def add(self, name):
self.names.append(name)
def __iter__(self):
pass
classmate =Classmate()
classmate.add("张三")
classmate.add("李四")
classmate.add("王二麻子")
for name in classmate:
print(name)
: 判断此时是不是可迭代对象?
from collections import Iterable
class Classmate(object):
def __init__(self):
self.names = list()
def add(self, name):
self.names.append(name)
def __iter__(self):
pass
classmate =Classmate()
classmate.add("张三")
classmate.add("李四")
classmate.add("王二麻子")
# 判断此时是不是可迭代对象?
print("'判断是不是可迭代对象:", isinstance(classmate, Iterable))
# for name in classmate:
# print(name)
:让__iter__方法返回一个迭代器,并判断是否是迭代器。
from collections import Iterable, Iterator
class Classmate(object):
def __init__(self):
self.names = list()
def add(self, name):
self.names.append(name)
def __iter__(self):
return ClassIteror()
class ClassIteror(object):
def __iter__(self):
pass
def __next__(self):
return 11
classmate =Classmate()
classmate.add("张三")
classmate.add("李四")
classmate.add("王二麻子")
# iter(对象),就会调用这个对象的__iter__方法。
classmate_iteror = iter(classmate)
print("判断是否是迭代器:", isinstance(classmate_iteror, Iterator))
# next(迭代器对象):就会调用这个对象的__next__方法。
print(next(classmate_iteror))
:如何让__next__拿到列表进行遍历呢?
from collections import Iterable, Iterator
class Classmate(object):
def __init__(self):
self.names = list()
def add(self, name):
self.names.append(name)
def __iter__(self):
# 1:将自己的引用传递过去
return ClassIteror(self)
class ClassIteror(object):
# 2: 接收引用
def __init__(self, obj):
self.obj = obj
def __iter__(self):
pass
def __next__(self):
# 调用方法获取数据
return self.obj.names[0]
classmate =Classmate()
classmate.add("张三")
classmate.add("李四")
classmate.add("王二麻子")
for name in classmate:
print(name)
此时会一值打印老王。
: 怎样才能一个一个的遍历呢?并且怎样能控制越界呢?
from collections import Iterable, Iterator
class Classmate(object):
def __init__(self):
self.names = list()
def add(self, name):
self.names.append(name)
def __iter__(self):
# 1:将自己的引用传递过去
return ClassIteror(self)
class ClassIteror(object):
# 2: 接收引用
def __init__(self, obj):
self.obj = obj
self.current_num = 0
def __iter__(self):
pass
def __next__(self):
if self.current_num < len(self.obj.names):
ret = self.obj.names[self.current_num]
self.current_num += 1
return ret
else:
raise StopIteration
classmate =Classmate()
classmate.add("张三")
classmate.add("李四")
classmate.add("王二麻子")
for name in classmate:
print(name)
: 代码简化:
from collections import Iterable, Iterator
class Classmate(object):
def __init__(self):
self.names = list()
self.current_num = 0
def add(self, name):
self.names.append(name)
def __iter__(self):
# 1:将自己的引用传递过去
return self
def __next__(self):
if self.current_num < len(self.names):
ret = self.names[self.current_num]
self.current_num += 1
return ret
else:
raise StopIteration
classmate =Classmate()
classmate.add("张三")
classmate.add("李四")
classmate.add("王二麻子")
for name in classmate:
print(name)
python修饰器classmate_python3大器----装饰器,迭代器,生成器相关推荐
- python3大器----装饰器,迭代器,生成器
目录 一:闭包: 1:闭包的作用和定义: 2:闭包的形成条件: 3:闭包的经典案例: 4:闭包的原理: 5: 闭包中使用外部函数变量: 二:装饰器: 1:装饰器的定义和作用: 2:装饰器经典案例分析: ...
- python装饰器模式带参数_Python进阶(七)----带参数的装饰器,多个装饰器修饰同一个函数和递归简单案例(斐波那契数列)...
Python进阶(七)----带参数的装饰器,多个装饰器修饰同一个函数和递归简单案例(斐波那契数列) 一丶带参数的装饰器 def wrapper_out(pt): def wrapper(func): ...
- python中高阶函数和装饰器_Python高阶函数与装饰器函数的深入讲解
本文主要介绍的是Python高阶函数与装饰器函数的相关内容,分享给大家,下面话不多说了,来一起看看详细的介绍吧 高阶函数 1.可以使用函数对象作为参数的函数 2.或可以将函数作为返回值的函数 3.函数 ...
- python 三个内置装饰器,python中自带的三个装饰器
说到装饰器,就不得不说python自带的三个装饰器: 1.@property 将某函数,做为属性使用 @property 修饰,就是将方法,变成一个属性来使用. class A(): @propert ...
- python 函数装饰器_python函数装饰器的用法
函数装饰器: 开闭原则:在面向对象编程领域中,开闭原则规定"软件中的对象(类,模块,函数等等)应该对于扩展是开放的, 但是对于修改是封闭的",这意味着一个实体是允许在不改变它的源代 ...
- python中高阶函数和装饰器_三.Python高阶函数和装饰器
1高阶函数 1.1 数学概念回顾下数学知识: y=f(x) 这是最开始接触的普通函数 y=g(f(x)) 这个就是我们接触到的高阶函数 在数学和计算机科学中,高阶函数至少应当是满足下面一个条件的函数: ...
- python高阶函数闭包装饰器_5.初识python装饰器 高阶函数+闭包+函数嵌套=装饰器...
一.什么是装饰器? 实际上装饰器就是个函数,这个函数可以为其他函数提供附加的功能. 装饰器在给其他函数添加功能时,不会修改原函数的源代码,不会修改原函数的调用方式. 高阶函数+函数嵌套+闭包 = 装饰 ...
- python function at 0x00000_Python函数装饰器原理与用法详解
本文实例讲述了Python函数装饰器原理与用法.分享给大家供大家参考,具体如下: 装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值 ...
- Python的神奇功能——函数装饰器MetaClass
Python中的装饰器,会让很多人望而却步.不要被它吓跑,啃下它,其实超有用,也没有想象中难. 所谓的装饰器,其实就是通过装饰器函数,来修改原函数的一些功能,使得原函数不需要修改. Python的装饰 ...
最新文章
- 菜鸡记录-王爽-汇编语言-实验十(编写子程序-显示字符串)
- nginx相关的一些记录
- 多路 IO 转接 :poll 函数
- OpenStack 计算节点删除
- 一人编程累,加班何人陪?1024 最好的礼物给最牛掰的你
- aix 文件升级-替换
- SpringBoot +MyBatisPlus打印不出sql语句
- 密码生成的思路---电脑mac地址
- H3C-NE实验主要命令
- 接口--PCI/PCIE
- 元宇宙构建基石:三维重建技术
- phyton题库+解析
- 下面哪些不是java的原始数据类型_以下哪个不是Java的原始数据类型()A? – 手机爱问...
- 使用 Lightly 在线格式化 HTML
- TED 不要变成自己人生的旁观者
- 线上教学困难多?来试试轻量级互动课堂方案
- cesium借助 turf 工具库绘制矩形 --任意倾斜角度 --vue2.0
- 机器学习的意义(转载)
- 自学软件测试 - 功能测试篇
- CP1H通过RS232连电脑上的威伦EB8000在线模拟