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 "

" + fn2() + "
"

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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
迭代器Python中用于遍历可迭代对象的一种机制。一个类或对象只要实现了`__iter__`和`__next__`这两个方法,就可以被称为迭代器。其中,`__iter__`方法返回一个特殊的迭代器对象,而这个迭代器对象自动实现了`__next__`方法,并通过返回一个值来迭代对象的元素。当没有更多元素可迭代时,`__next__`方法会抛出`StopIteration`异常来结束迭代。 对于一个可迭代对象来说,它需要具有一个能够返回一个迭代器对象的`__iter__`方法。迭代器对象是通过`__iter__`方法返回的,可以是对象自身(前提是对象本身就是一个迭代器),也可以是其他迭代器对象。而`__next__`方法则用于标记并返回下一个迭代器对象。 下面是一个例子: ```python from collections import Iterable, Iterator class Classmate(object): """定义一个同学类""" def __init__(self): self.name = list() self.name_num = 0 def add(self, name): self.name.append(name) def __iter__(self): return self # 返回本身 def __next__(self): if self.name_num < len(self.name): ret = self.name[self.name_num] self.name_num += 1 return ret else: raise StopIteration class1 = Classmate() class1.add("张三") class1.add("李四") class1.add("王五") print("判断是否是可迭代的对象:", isinstance(class1, Iterable)) print("判断是否是迭代器:", isinstance(class1, Iterator)) for name in class1: print(name) ``` 在这个例子中,`Classmate`类实现了`__iter__`和`__next__`方法。`__iter__`方法返回了自身作为迭代器对象,而`__next__`方法则按顺序返回了班级同学的名字,直到没有更多名字可迭代时抛出`StopIteration`异常。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值