python 中return和yield有什么区别

By 刘志军, 2022-12-09, 分类: Python

python

先说return

return 关键字用在中函数,后面跟一个表达式或者啥也不写,表示该函数被调用时会返回一个值(如果不写东西就返回一个None)

def function():
    return 10

value = function()
print(value)  # 10

程序执行到return这行代码时,该函数的直接就结束了,哪怕后面还有代码也不会执行。因此有时候我们也用return来提前结束函数

def function(name):
    if name=='人妖':
        return
    else:
        print("你好", name)

再来说yield

理解yield这个关键字之前,需要先理解一些前置知识,主要迭代器和生成器的概念。

什么是迭代器

顾名思义,迭代器就是用于迭代操作(for 循环)的对象,它像列表一样可以迭代获取其中的每一个元素,任何实现了 __next__ 方法的对象都可以称为迭代器。

它与列表的区别在于,调用迭代器的时候,不像列表把所有元素一次性加载到内存,而是以一种延迟计算(lazy evaluation)方式返回元素,这正是它的优点。比如列表含有中一千万个整数,需要占超过400M的内存,而迭代器只需要几十个字节的空间。因为它并没有把所有元素装载到内存中,而是等到调用 next 方法时候才返回该元素(按需调用 call by need 的方式),本质上 for 循环就是不断地调用迭代器的next方法,直到遇到异常StopIteration结束循环。

以斐波那契数列为例来实现一个迭代器:

class Fib:
    def __init__(self, n):
        self.prev = 0
        self.cur = 1
        self.n = n

    def __iter__(self):
        return self

    def __next__(self):
        if self.n > 0:
            value = self.cur
            self.cur = self.cur + self.prev
            self.prev = value
            self.n -= 1
            return value
        else:
            raise StopIteration()


f = Fib(10)
print([i for i in f])  # [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

什么是生成器

普通函数用 return 返回一个值,在 Python 中还有一种函数,用关键字 yield 来返回值,这种函数叫生成器函数,函数被调用时会返回一个生成器对象而不是yield后面的值。

生成器本质上还是一个迭代器,也是用在迭代操作中,因此它有和迭代器一样的特性,唯一的区别在于实现方式上不一样,后者更加简洁

最简单的生成器函数:

>>> def func(n):
...     yield n*2
...
>>> func
<function func at 0x00000000029F6EB8>
>>> g = func(5)
>>> g
<generator object func at 0x0000000002908630>
>>>

func 就是一个生成器函数,调用该函数时返回对象就是生成器 g ,这个生成器对象的行为和迭代器是非常相似的,可以用在 for 循环等场景中。注意 yield 对应的值在函数被调用时不会立刻返回,而是调用next方法时才返回

>>> g = func(5)
>>> next(g)
10

>>> g = func(5)
>>> for i in g:
...     print(i)
...
10

一个函数中可以有多个yield语句,有几个yield语句有可以迭代几次。

def generate():
    yield 1
    yield 2
    yield 3


g = generate()

print(next(g)) # 1
print(next(g)) # 2
print(next(g)) # 3
print(next(g)) # 报错 StopIteration

那为什么要用生成器呢?显然,它没有那么多冗长代码了,而且性能上一样的高效,为什么不用呢?来看看用生成器实现斐波那契数列有多简单。

def fib(n):
    prev, curr = 0, 1
    while n > 0:
        n -= 1
        yield curr
        prev, curr = curr, curr + prev

print([i for i in fib(10)])
#[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

生成器表达式

我曾经介绍过列表推导式(list comprehension),生成器表达式与列表推导式长的非常像,但是它俩返回的对象不一样,前者返回生成器对象,后者返回列表对象。

>>> g = (x*2 for x in range(10))
>>> type(g)
<type 'generator'>
>>> l = [x*2 for x in range(10)]
>>> type(l)
<type 'list'>

前面已经介绍过生成器的优势,就是迭代海量数据时,显然生成器更合适。


有问题可以扫描二维码和我交流

关注公众号「Python之禅」,回复「1024」免费获取Python资源

python之禅

猜你喜欢

2019-05-16
命名难,难于上青天
2020-06-14
python合并两个列表
2021-09-28
保姆级教程,3行代码制作国旗头像
2019-05-12
一行代码将 cookie 字符串转换成字典对象
2013-10-30
Python“不为人知的”特性
2018-09-27
关于Python包和模块的10个知识清单
2020-06-13
检查对象中是否存在某个属性
2017-05-15
一步一步教你认识Python闭包
2020-05-07
Python3.9要来了
2020-06-07
python判断文件是否存在