最新消息:XAMPP默认安装之后是很不安全的,我们只需要点击左方菜单的 "安全"选项,按照向导操作即可完成安全设置。

Python核心笔记2- yield 函数创建生成器方式

XAMPP案例 admin 469浏览 0评论

上篇讲述了Python核心笔记1-一切皆是对象

今天我们来讲述Python核心笔记2-  yield 函数创建生成器方式

1、生成器

在 Python 中,使用了 yield 的函数被称为生成器(generator),一边循环一边计算的机制;

在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。

好处:节省内存空间;适用想要得到庞大的数据,又想让它占用空间少的场景;

0Python

1.1 创建生成器方式1

第一种方法很简单,只要把一个列表生成式的 [ ] 改成 ( )

#  原有方式
test_list = [x*2 for x in range(5)]  # 执行后test_list : [0, 2, 4, 6, 8]
#  生成器
test_gen = (x*2 for x in range(5))  # 执行后test_gen : <generator object <genexpr> at 0x106d2c820>
#  生成器的打印
next(test_gen)  # 执行后打印 0
next(test_gen)  # 执行后打印 2
next(test_gen)  # 执行后打印 3
#  遍历test_gen
for x in test_gen:
    print(x)  # 打印 0 2 4 6 8

注意: 

通过next()方式超出边界会报StopIteration 异常;

创建了一个生成器后,基本上永远不会调用 next() ,而是通过 for 循环来迭代它,并且不需要关心 StopIteration 异常。

 

1.2 创建生成器方式2

如果一个函数中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。调用函数就是创建了一个生成器(generator)对象。

#  斐波那契数列, 原有写法
def fib(times):
    n = 0
    a,b = 0,1
    while n < times:
        print(b)
        a,b = b, a+b
        n += 1
    return True
    
fib(5) # 打印结果:1, 1, 2, 3, 5, 8
    
# 斐波那契, 生成器方式
def fib(times):
    n = 0
    a,b = 0,1
    while n < times:
        yield b
        a,b = b, a+b
        n += 1
    return True  
    
 obj_fit = fib(5)
 
 #  逐次d打印
 next(obj_fit)  # 打印结果:1
 next(obj_fit)  # 打印结果:1
 next(obj_fit)  # 打印结果:2
 
 #  打印返回的迭代器
 for x in obj_fit:
     print x   # 打印结果 1, 1, 2, 3, 5, 8   

注:

yield相当于 return 返回一个值,并且记住这个返回的位置,下次迭代时,代码从yield的下一条语句开始执行。

 

1.3 send方法

.send() 和next()一样,都能让生成器继续往下走一步(下次遇到yield停),但send()能传一个值,这个值作为yield表达式整体的结果。

def test():
  i = 0
  while i < 5:
    temp = yield i
    print(temp)
    print(i)
    i += 1  
  
t=test()
next(t)
t.send('test')
next(t)
# 代码执行结果:hshs 0 None 1

2、迭代器

迭代是访问集合元素的一种方式;

迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束;

迭代器只能往前不会后退。

2.1 可迭代对象

以直接作用于 for 循环的数据类型有以下几种:

一类是集合数据类型,如 list 、 tuple 、 dict 、 set 、 str 等;

一类是 generator ,包括生成器和带 yield 的generator function。

这些可以直接作用于 for 循环的对象统称为可迭代对象:Iterable 。

2.2 是否可迭代

可以使用 isinstance() 判断一个对象是否是 Iterable 对象;

from collections import Iterable
print (isinstance([], Iterable))  # 打印 True

2.3 迭代器

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。

可以使用 isinstance() 判断一个对象是否是 Iterator 对象

print(isinstance((x for x in range(10)), Iterator)) # 打印ture
print(isinstance([], Iterator)) # 打印false

生成器都是 Iterator 对象,但 list 、 dict 、 str 虽然是 Iterable ,却不是 Iterator 。

把 list 、 dict 、 str 等 Iterable 变成 Iterator 可以使用 iter() 函数;

print(isinstance([], Iterator)) # 打印true

3、闭包

在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包.

def test_bb(numa):
  
  def test_inner(numb):
    return numa + numb
  return test_inner
tb = test_bb(10)  # tb指向test_inner
result = tb(5)  # 调用test_inner
print(result) # 打印 15

3.1 实例

闭包可以提高代码复用;

例如下面案例,如果没有闭包我们需要每次创建直线函数的时候同时说明a,b,x,需要多参数传递;

def line_conf(a, b):
    def line(x):
        return a*x + b
    return line
line1 = line_conf(100,100)
line2 = line_conf(100,100)
line1(10)line2(20)

4、装饰器

装饰器是闭包的一种应用,用于拓展原来函数功能的一种方式,好处就是在不用更改原函数的代码前提下给函数增加新的功能。

4.1 简单装饰器

在执行执行方法的上面增加一个帽子(装饰这个方法),格式为 @check

def check(func):
  def wrapper():
    print('---check---')
    func()
  return wrapper
@check
def login():
  print('login')
  
login() # 打印 ---check---  login

4.2 多个装饰器

天气太冷,一个帽子不够,那就扩展两个;

@check_one

@check_two

def check_one(func):
  def wrapper():
    print('---check_one---')
    func()
  return wrapper
def check_two(func):
  def wrapper():
    print('---check_two---')
    func()
  return wrapper
@check_one
@check_two
def login():
  print('login')
  
login() # 打印 ---check_one---  ---check_two---  login 

注:装饰器装饰的时候从下往上, 调用的时候从上往下调用;

 

4.3 带参数装饰器

装饰器中可以传入参数,先形成一个完整的装饰器,然后再来装饰函数;

函数如果需要传入参数也是可以的,用不定长参数符号就可以接收,例子中传入了2个参数(name, password)。

def check(user):
  def outwrapper(func):
    def wrapper(*args, **kwargs):
      if user == 'admin':
        print('---check admin---')
      else:
        print('---check other---')
      func(*args, **kwargs)
    return wrapper
  return outwrapper
@check(user='admin')
def login(name, password):
  print('Name:%s Pass:%s' % (name, password))
login('HAHA', 'NMNM')  # 打印 ---check admin---   Name:HAHA Pass:NMNM

4.4 类装饰器

装饰器也不一定只能用函数来写,也可以使用类装饰器,实质是使用了类方法中的call魔法方法来实现类的直接调用。

class check(object):
  def __init__(self, user):
    self.user = user
    
  def __call__(self, func):
    def wrapper(*args, **kwargs):
      if self.user == 'admin':
        print('---check admin---')
      else:
        print('---check other---')
      func(*args, **kwargs)
    return wrapper
@check(user='admin')
def login(name, password):
  print('login name:%s  pass:%s' % (name, password))
login('HAHA', 'NMNM')   # 打印 ---check admin---   Name:HAHA Pass:NMNM

转载请注明:XAMPP中文组官网 » Python核心笔记2- yield 函数创建生成器方式

您必须 登录 才能发表评论!