迭送器,生成器,闭包,装饰器

迭代器

可迭代对象:

list,str,tuple etc. ---->for … in …遍历 ---->遍历(迭代)

迭代器协议:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么引起StopIteration 异常,以终止迭代(只能往下走,不可以回退)

现在,我们可以说,实现迭代器协议的对象就是可迭代对象

如何实现?

  • 通过在对象内部定义一个__iter__方法
from collections import Iterable   #使用instance() 来判断一个对象是否可迭代
print(isinstance([],Iterable))
print(isinstance(str(),Iterable))
print(isinstance({},Iterable))
print(isinstance(set(),Iterable))
print(isinstance(123,Iterable))
print(isinstance(True,Iterable))

自定义一个类,可以容纳数据,测试该类的可迭代性

回顾之前说的’_iter_'方法,其实可以为我门提供一个迭代器.

在迭代一个可选对象的时候,实际上就是获取该对象提供的一个迭代器.然后通过该迭代器依次获取对象的每一个数据.

from collections import Iterable

class MyClass:
    def __init__(self):
        self.names = []
    def add(self,name):
        self.names.append(name)
my_class = MyClass()
my_class.add("Tom")
my_class.add("jack")
my_class.add("ddd")
print("是否为可迭代对象:",isinstance(my_class,Iterable))
for tmp in my_class:
	print(tmp,end=" ")

out


通过迭代器,迭代

print(my_class)
my_class_iter = iter(my_class)
print(my_class_iter)
print(next(my_class_iter))
print(next(my_class_iter))
print(next(my_class_iter))
print(next(my_class_iter))

for … in …循环的本质

就是通过iter()函数获取可迭代对象的Iterable的迭代器,然后对获取到的迭代器不断调用next()方法来获取下一个值并将其赋值,当遇到StopIteration的异常后,退出.

class test:
    def __init__(self,data=1):
        self.data = data

    def __iter__(self):
        return self

    def __next__(self):
        if self.data> 5:
            raise StopIteration
        else:
            self.data += 1
            return self.data

for i in test(2):
    print(i)
    

out:

3
4
5
6

应用场景

迭代器的 核心就是通过next()函数调用返回下一个数据值.如果每次返回的数据值不是在一个已有的数据集合中读取的,而是通过程序按照一定规律计算生成.那么也就意味着可以不用依赖一个已有的数据集合,namely,

无需将所有的迭代对象数据一次性缓存下来供后续使用.这样,可以节省大量的存储(内存)空间.

demo:

菲波那契数列

#两个初始值
#n ,不大于n的类似索引的值
class Fib:
    '''斐波那契数列迭代器'''
    def __init__(self, n):
        #记录生成的斐波那契数列的个数
        self.n = n
        #记录当前记录的索引
        self.current_index = 0
        #记录两个初始值
        self.num1 = 0
        self.num2 = 1
        self.name = []
    def __next__(self):
        '''调用next()函数获取下一个数'''
        if self.current_index < self.n:
            num = self.num1
            self.num1, self.num2 = self.num2, self.num1+self.num2
            self.current_index += 1
            self.name.append(num)
            return num
        else:
            raise StopIteration

    def __iter__(self):
        return self
fib = Fib(10)
for num in fib:
    print(num, end=' ')
a = fib.__iter__()
print(next(a))
print(next(a))
print(next(a))

现在我们希望通过for… in…的方式来遍历斐波拉契数列中的前n个数.

通过迭代来实现,每次迭代都可以通过数学计算生成下一个数.

生成器

生成器,利用迭代器,我们可以在每次迭代获取数据时(通过next()方法)按照特定规律进行生成.但是我们在实现一个迭代器时,关于当前迭代的状态需要我们自己记录,进而才能根据当前状态生成下一个数据.为了达到记录当前状态,并配合next()函数进行迭代使用,可以采用更简便的语法.

生成器(generator),生成器是一种特殊的迭代器,它比迭代器更优雅.

创建一个生成器

列表[] —>()

li = [x**2 for x in range(6)]
print(li)

gen = (x**2 for x in range(6))
print(gen)
print("通过next()函数取得下一个值")
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))


print("通过for遍历")
gen = (x**2 for x in range(6))
for i in gen:
    print(i,end=" ")

out:

[0, 1, 4, 9, 16, 25]
<generator object <genexpr> at 0x0000021D35DDEF68>
通过next()函数取得下一个值
0
1
通过for 遍历
4 9 16 25 

生成器函数

在函数中如果出现了yield关键字,那么该函数就不再是一个普通函数,而是一个生成器函数.

demo:

def foo():
    yield 1
    yield 2
print(next(f))   #1
print(next(f))   #2

#若 加入return
def foo():
    yield 1
    return 'Error'
    yield 2
#1
#StopIteration: Error
#则  1可以迭代输出  进而return返回   2无法进行迭代输出StopIteration

next 和 yield进行匹配,如果遇到return,

return后的语句不会再执行,直接抛出StopIteration,终止迭代

如果return后有返回值,那么这个值就是异常的说明,而不是函数的返回值.

构造一个产生无穷奇数的生成器

class OddIter:
    def __init__(self):
        self.start = -1
    def __iter__(self):
        return self
    def __next__(self):
        self.start += 2
        return self.start
odd = OddIter()

for i in range(6):
    print(next(odd))

生成器支持的方法

  • close()
    • 手动关闭生成器函数,后面调用直接引起StopIteration异常
def gen():
    yield 1
    yield 2
    yield 3
    yield 4
g = gen()
print(next(g))
print(next(g))
g.close()
print(next(g)) # 回溯
  • send()

    • x = yield y语句的含义:send()的作用就是使x赋值为其所传送的值(send的参数),然后让生成器执行到下一个yield.

      • 如果生成器未启动,则必须在使用send()前启动生成器,而启动的方法可以使gen.next(),也可以是gen.send(None)执行到yield处.之后就可以使用send(para)不断的传入值了.
    • 如果是已启动,则send(para)的作用就是给x赋值为发送的值(send的参数),然后,让生成器执行到下一个yield.

# def gen():
#     i = 0
#     while i< 5:
#         temp = yield i
#         print(temp)
#         i+=1
# # 创建生成器对象
# obj = gen()
# # 使用next()唤醒生成器
# print(next(obj))
# print(next(obj))
# print(obj.send("city"))

结果

0
None
1
city
2

def gen():
    value = 0
    while True:
        receive = yield value
        if receive == 'e':
            break
        value = 'got: %s' %receive
#send()的作用就是使 receive赋值,然后生成器执行下一个yield
# 生成器未启动时  启动方法未 gen.next() 或者 gen.send(None)执行到第一个yield处开始生成
g = gen()
print(g.send(None))
print(g.send('aaa'))
print(g.send(123))
print(g.send('e'))
# 0
# got:aaa
# got: 123
报错 StopIteration

解析:

g.send(None)启动生成器, 程序运行到 yield value终止 返回为 0
g.send(‘aaa’) ,程序 从上一步yield value后 If开始运行 send赋值给receive = ‘aaa’ 判断条件后 value=‘got: aaa’ 进而 yield value 返回 got: aaa并终止
同理 g.send(123) 赋值receive = 123, 进入 value = ‘ got: 123’, yield value 终止并返回 got:123

g.send('e) if判断break 此时迭代器没有更多的值,则报错。

  • throw()
    • 手动抛出异常.

闭包

什么是闭包

闭是封闭(函数中的函数),包时包含(该内部函数对外部函数作用域而非全局作用域变量的引用)

闭包:

  • 内部函数外部函数用域里的变量引用

  • 函数类的属性,都是有生命周期

  • 闭包内的闭包函数私有化了变量

demo:

def foo():
    print('in foo()')
    def bar():
        print('in bar()')

#1.直接允许内部函数报错
#bar()

#2.考虑先允许外部函数,再允许内部函数,依然报错
# foo()
# bar()

由于作用域的问题,函数内的属性,都是有生命周期,只有在函数执行期间

再考虑这段代码,只有调用foo()是,内部的print()及bar()才能存活.

现在我们为了让foo()内的bar()存在,就是调用bar(),我们该怎么做?

把bar() 函数返回给函数

def foo():
   print("in foo()")
   def bar():
       print("in bar()")
   return bar
var = foo()
var()
in foo()
in bar()

前面说,内部函数对外部函数作用域变量的引用,---->如果是变量呢?

def foo():
    a = 66
    print('in foo()')
    def bar(num):
        print('in bar()')
        print(a + num)
    return bar

var = foo()
var(22)

in foo()
in bar()
## 88

li = [1, 2, 3, 4, 5]
def foo(obj):
    print('foo:', obj)
    def bar():
        obj[0] -= 1
        print('bar:',obj)
    return bar
var = foo(li) #  foo: [1, 2, 3, 4, 5]
var()  #bar: [0, 2, 3, 4, 5]
var()  #bar: [-1, 2, 3, 4, 5]

foo: [1, 2, 3, 4, 5]
bar: [0, 2, 3, 4, 5]
bar: [-1, 2, 3, 4, 5]

装饰器

首先,看一个demo:


@func1
def func():
    print('aaa')
    

装饰器存在的意义

  • 不影响原有函数的功能
  • 可以添加新功能

一般常见的,比如拿到第三方的API接口,第三方不允许修改这个接口.这个时候,装饰器就派上用场.

装饰器本身也是一个函数,作用是为现有存在的函数,在不改变函数的基础上,增加一些功能进行装饰.

它以闭包形式去实现的.

在使用装饰器函数时,在被装饰的函数的前一行,使用’@装饰器名称’形式来进行装饰

Demo:

在一个项目中,有很多函数,由于我们的项目越来越大,功能也越来越多,导致程序越来越慢.

其中一个功能函数的功能,是实现一百万次的累加.


import time
def my_count():
    s =0
    for i in range(1000001):
        s +=i
    print("sum:",s)

start = time.time()
my_count()
end = time.time()
print("执行时间为;",(end-start))

修改后

import time
def my_count():
    s =0
    for i in range(1000001):
        s +=i
    print("sum:",s)

# start = time.time()
# my_count()
# end = time.time()
# print("执行时间为;",(end-start))
def count_time(func):
    start = time.time()
    func()
    end = time.time()
    print("执行那个时间为:",(end-start))

count_time(my_count)

修改后,定义一个函数来实现时间计算功能.

初看上去,比之前好很多,

只是在使用时,需要将对应的函数传入到时间计算函数中

import time
def count_time(func):
    def wrapper():
        start = time.time()
        func()
        end = time.time()
        print("执行时间为:",(end-start))
    return wrapper
@count_time
def my_count():
    s =0
    for i in range(1000001):
        s +=i
    print("sum:",s)
my_count()

在使用时,让my_count函数重新指向count_time函数返回的函数引用,

这样实现的好处,定义闭包函数后,只需要通过’@装饰器函数名’形式的装饰器语法,就可以将’@装饰器函数名’加到要装饰的函数前即可.

这种不改变原有函数功能,对函数进行拓展形式,就称为’装饰器’

在执行’@装饰器函数名’时,就是将原有函数传递到闭包中,然后,原函数的引用指向闭包返回的装饰过的内部函数引用.

资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 在当今的软件开发领域,自动化构建与发布是提升开发效率和项目质量的关键环节。Jenkins Pipeline作为一种强大的自动化工具,能够有效助力Java项目的快速构建、测试及部署。本文将详细介绍如何利用Jenkins Pipeline实现Java项目的自动化构建与发布。 Jenkins Pipeline简介 Jenkins Pipeline是运行在Jenkins上的一套工作流框架,它将原本分散在单个或多个节点上独立运行的任务串联起来,实现复杂流程的编排与可视化。它是Jenkins 2.X的核心特性之一,推动了Jenkins从持续集成(CI)向持续交付(CD)及DevOps的转变。 创建Pipeline项目 要使用Jenkins Pipeline自动化构建发布Java项目,首先需要创建Pipeline项目。具体步骤如下: 登录Jenkins,点击“新建项”,选择“Pipeline”。 输入项目名称和描述,点击“确定”。 在Pipeline脚本中定义项目字典、发版脚本和预发布脚本。 编写Pipeline脚本 Pipeline脚本是Jenkins Pipeline的核心,用于定义自动化构建和发布的流程。以下是一个简单的Pipeline脚本示例: 在上述脚本中,定义了四个阶段:Checkout、Build、Push package和Deploy/Rollback。每个阶段都可以根据实际需求进行配置和调整。 通过Jenkins Pipeline自动化构建发布Java项目,可以显著提升开发效率和项目质量。借助Pipeline,我们能够轻松实现自动化构建、测试和部署,从而提高项目的整体质量和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值