18910140161

JavaScript ES6 和 Python 中的 Generator

顺晟科技

2021-06-16 10:58:32

245

最近,一个关于RSS聚合器的爬虫涉及到前端的redux-saga。用ES6中介绍的Generator很花俏,好像有雾。其实从思维和写作上来说基本和Python的生成器和产量一样。我之前已经用Python写了用法,这里简单的用动态语言写下我对生成器的学习和理解。

常识

首先,生成器本质上是一个函数,但是它的行为略有特殊。

普通函数会在执行结束时通过return返回;

生成器可以中断函数的执行过程,返回断点处继续执行。具体实现是通过yield和interrupt将结果返回给调用者,然后通过next()方法继续返回断点,再执行到下一个yield断点。

普通函数只返回一次,即执行结束;生成器函数在执行过程中可以多次返回,也就是说,它在产出断点处替换返回。

与生成器密切相关的另一个概念是迭代器。简单描述两者之间的关系,就是生成器实现的目的是生成迭代器,迭代器是可重复的,也就是可以循环遍历。

ES6

JavaScript ES6的生成器和普通函数最明显的区别在于,它的关键字包括星号*和yield,比如MDN文档上的代码示例:

函数*生成器(i) {

产量I;

产量i10;

}

var gen=发电机(10);

console.log(gen.next()。值);

//预期输出: 10

console.log(gen.next()。值);

//预期输出: 20

让我们看看上面的代码发生了什么事

function* generator(i) {}代码块声明了一个生成器,此时没有任何事情发生;

Var gen=generator(10)创建一个生成器并将其分配给变量gen

调用gen.next()时。值时,被执行的生成器进入个让步位置,中断执行并返回I,即10;

调用gen.next()时。第二次取值,回到发生器断点处继续执行,直到第二次屈服再次中断,返回i 10,即20;

可以预期,如果调用gen.next()。值,您将得到未定义的,因为这个生成器已经完成了所有断点,并在您第二次调用它时完成了“生成”任务。

请注意下一个()方法,它返回一个具有两个属性的JSON对象:

{

value:对象,

done:布尔值

}

值是生成器在迭代器中创建的元素,完成表示迭代器是否完成。

看看生成器的经典场景,生成斐波那契序列。

//生成器模式

函数* genFib(n) {

产量a=0

b=1

while(b=n) {

产量b

b=b a

a=b - a

}

}

var fib=genFib(100)

for(让fib值){

console.log(值)

}

从前面的过程分析来看,这个斐波那契序列生成过程非常容易理解。

换句话说,如果斐波那契序列是由普通的循环迭代生成的,一般类似于下面的代码。

//循环模式

函数genFib(n) {

假设a=0

让b=1

让fib=[0]

while(b=n) {

fib.push(b)

b=b a

a=b - a

}

返回纤维

}

乍一看,似乎两者只是写法不同,实际运行速度并没有因为样本量太小而有所不同。但仔细观察后不难发现,第二次循环迭代会将所有结果存储在内存中,只有完全生成后才会返回;个生成器被编写为一次只生成一个元素,并立即返回。当数量n较大时,发生器的资源和性能增益相当大。

JavaScript就像一匹脱缰的野马。它的语法太灵活了。有很多种写法会让程序员觉得很奇怪,比如yield*的用法。这个表达其实是用来把一个发电机托付给另一个发电机,笑哭…….

例如,在前面的例子中,生成器被分配给一个普通变量,yield* [[expression]]是对右表达式的生成器的每个元素进行yield。

function* gen1() {

产量1;

产量2;

产量3;

}

function* gen2() {

yield * gen 1();

产量4;

}

[.gen 2()];

//[ 1, 2, 3, 4 ]

JavaScript中有字符串、数组、类型、映射、集合等支持可迭代的。因此,这些内置对象也支持产量*表达式、for-of表达式和.表达式,非常灵活。

理解JavaScript ES6中的生成器,更容易理解redux-saga的状态管理,有空再写redux-saga。

计算机编程语言

Python中的生成器和JavaScript基本相同。或者以斐波那契为例。

def gen_fib(n):

产量0

a,b=0,1

而b=n:

产量b

b=b a

a=b - a

对于gen_fib(100):中的值

打印(数值)

Python版本只添加了yield关键字,没有设计*来表示声明函数的生成器。

之前的博客理解Python生成器很浅,所以在这里我尝试从Magic Method写的更深一些。

Python内置了一些叫做Magic Method的特殊方法,比如__init__,__new__,__str__。这些Magic Method的初衷是描述对象的内在行为,而不需要外部的显式调用。例如,我们声明一个对象并编写它的__init__方法:

class Book:

def __init__(自我,姓名,作者):

self.name=name

self.author=作者

书=书(《哈利波特》,《罗琳》)

书。__getattribute__('name ')

书。__getattribute__(“作者”)

我们没有直接调用__init__方法,但是Python解释可以理解并调用__init__初始化对象。

相关文章
我们已经准备好了,你呢?
2024我们与您携手共赢,为您的企业形象保驾护航