当前位置:首页 » 编程语言 » python3yield

python3yield

发布时间: 2022-04-01 01:09:03

Ⅰ 说说这篇我为什么从python转向go

恩看了这篇我为什么从python转向go,
看来作者也是 KSO 轻办公/企业快盘团队的。作为快盘从无到有时期的工程师之一(总是被潇洒哥说他们改我留下的 bug ),又恰好是
Python/Go 双修(大雾其实我是 Rust 党),其实一开始我是拒绝的,ang ang ang,那就随手写一点把。

一段段来吧,首先作者说 Python 是动态语言

python是一门动态语言,不是强类型系统。对于一个变量,我们有时候压根不知道它是什么类型,然后就可能出现int + string这样的运行时错误。

在python里面,可以允许同名函数的出现,后一个函数会覆盖前一个函数,有一次我们系统一个很严重的错误就是因为这个导致的。

事实上,如果是静态检查,pylint 和 pyflakes 是可以做这件事的,虽然不能和 go
那种静态编译型语言比,但也足够了。如果没记错的话,阿通当年是要求全组都在提交前做静态检查的。我认为这种问题更多的应该是人员素质上来避免,毕竟葱头
也说过,代码自己写的就要多回头看看,看能不能重构,能不能做更好。不是说偷懒不行,但是从中得出 Python
动态特性太灵活,Python:怪我咯看

另外,函数作为第一对象,在 Python 中是 feature,Go 要写个 mock,简直虐得不要不要的。

其实这个一直是很多人吐槽python的地方,不过想想,python最开始是为了解决啥问题而被开发出来的看我们硬是要将他用到高性能服务器开发上面,其实也是有点难为它。

如果没记错,无论是轻办公还是快盘,是重 IO 不重 CPU,最大耗时是数据块加密那块,我在的时候是 java 写的。另外高性能服务器选 Go 也是虐得不要不要的,各种小心翼翼避免 GC。大多数极端情况下,pypy 的性能足矣胜任了,我认为这不算充分条件。

python的GIL导致导致无法真正的多线程,大家可能会说我用多进程不就完了。但如果一些计算需要涉及到多进程交互,进程之间的通讯开销也是不得不考虑的。

其实,Python 有宏可以绕开这个 GIL,但是呢架构设计得好其实可以避免的,到异步那块我会说。

无状态的分布式处理使用多进程很方便,譬如处理http请求,我们就是在nginx后面挂载了200多个django server来处理http的,但这么多个进程自然导致整体机器负载偏高。

但即使我们使用了多个django进程来处理http请求,对于一些超大量请求,python仍然处理不过来。所以我们使用openresty,将高频次的http请求使用lua来实现。可这样又导致使用两种开发语言,而且一些逻辑还得写两份不同的代码。

如果推测没错,你们现在还在用五年前写的 Gateway看那个基于 django route
的流量分发层看四年前我离开的时候已经小范围的使用 Flask+Gevent Demo 测试过了,无论是性能还是负载都比同步模型的 django
有优势。如果还是 django
这套的话,我只能说比较遗憾,毕竟当年金山新员工大赛头牌就是我和几个小伙伴写的实时同步在线文档编辑系统,用的就是这套技术。

因此这是个工程问题,并非语言问题。 Python 提供给了你了这么多工具,硬要选一个传统的,Old fashion 的,Python:怪我咯看

django的网络是同步阻塞的,也就是说,如果我们需要访问外部的一个服务,在等待结果返回这段时间,django不能处理任何其他的逻辑(当然,多线程的除外)。如果访问外部服务需要很长时间,那就意味着我们的整个服务几乎在很长一段时间完全不可用。

为了解决这个问题,我们只能不断的多开django进程,同时需要保证所有服务都能快速的处理响应,但想想这其实是一件很不靠谱的事情。

同步模型并非不行,因为 overhead 足够低,很多业务场景下用同步模型反而会取得更好的效果,比如豆瓣。同步模型最大的问题是对于 IO 密集型业务等待时间足够长,这时候需要的不是换语言 ,而是提醒你是不是架构要改一下了。

虽然tornado是异步的,但是python的mysql库都不支持异步,这也就意味着如果我们在tornado里面访问数据库,我们仍然可能面临因为数据库问题造成的整个服务不可用。

tornado 是有这个问题,但是 gevent 已经解决了。我在 node.js 的某问题下曾经回答过,对于 node
而言,能选择的异步模型只有一个,而 Python 就是太多选择了。另外 pypy+tornado+redis
可以随意虐各种长连接的场景,比如我给我厂写过的一个 push service。

其实异步模型最大的问题在于代码逻辑的割裂,因为是事件触发的,所以我们都是通过callback进行相关处理,于是代码里面就经常出现干一件事情,传一个callback,然后callback里面又传callback的情况,这样的结果就是整个代码逻辑非常混乱。

这个还真不是,如果说没有 ES6 的 JavaScript,可能真有 Callback hell,但这是 Python 啊!Python
早就实现了左值绑定唉,yield 那姿势比某些天天吹的语言不知道高到哪里去了,当然我说的是完整版的 Python3 yield。即便是不完整的
Python 2 yield 用于异步表达式求值也是完全足够的,tornado 的 gen.coroutine 啊。

同步形态写异步,在 Python 实力强的公司里面早普及了,这是个工程问题,并非语言问题。当然把这种事怪在 Python 身上,Python:怪我咯看

python没有原生的协程支持,虽然可以通过gevent,greenlet这种的上patch方式来支持协程,但毕竟更改了python源码。另外,python的yield也可以进行简单的协程模拟,但毕竟不能跨堆栈,局限性很大,不知道3.x的版本有没有改进。

无论是 Gevent 还是 Greenlet 均没修改 Python 源码,事实上这货已经成为了 Py2 coroutine 的标准,加上豆瓣开源出来的greenify,基本上所有的库都可以平滑的异步化,包括 MySQL 等 C 一级的 lib。自从用上这套技术后,豆瓣的 Python dev 各种爽得不要不要的。

当我第一次使用python开发项目,我是没成功安装上项目需要的包的,光安装成功mysql库就弄了很久。后来,是一位同事将他整个python目录打包给我用,我才能正常的将项目跑起来。话说,现在有了docker,是多么让人幸福的一件事情。

而部署python服务的时候,我们需要在服务器上面安装一堆的包,光是这一点就让人很麻烦,虽然可以通过puppet,salt这些自动化工具解决部署问题,但相比而言,静态编译语言只用扔一个二进制文件,可就方便太多了。

恰好我又是在开发基于 docker 的平台, docker 还真不是用来做部署这事的。首先, Python 是有 virtualenv
这个工具的,事实上对比包管理和包隔离,Python 比 Go 高得不知道哪里去了。Python 跟 Git 谈笑风生的时候, Go 的 dev
们还得考虑我怎样才能使得 import 的包稳定在一个版本上(当然现在有很多第三方方案)。Virtualenv + Pip 完全可以实现
Python 部署自动化,所以这个问题我认为是,工具链选取问题。毕竟是个十几年的老妖怪了,Python
啥情况没见过啊,各种打包工具任君选择,强行说 Python 部署不方便,Python:怪我咯看

python非常灵活简单,写c几十行代码才能搞定的功能,python一行代码没准就能解决。但是太简单,反而导致很多
同学无法对代码进行深层次的思考,对整个架构进行细致的考量。来了一个需求,啪啪啪,键盘敲完开速实现,结果就是代码越来越混乱,最终导致了整个项目代码
失控。

曾经知乎有个帖子问 Python 会不会降低程序员编程能力,
我只能说这真的很人有关。你不去思考深层次的东西怪语言不行是没道理的,那好,Go 里面 goroutine 是怎么实现的,一个带 socket 的
goroutine
最小能做到多少内存,思考过看任何语言都有自己的优势和劣势,都需要执行者自己去判断,一味的觉得简单就不会深入思考这是有问题的。另外,代码混乱我认为
还是工程上的控制力不够,豆瓣有超过10W行的 Python 实现,虽然不说很完美,大体上做到了不会混乱这么个目标。

还有,C 写几十行搞定的 Python 一行解决这绝对是重大 feature,生产力啊,人员配置啊,招人培养的成本啊,从工程上来说,Python 在这一块完全是加分项,不是每个项目都要求极致的并发,极致的效率,做工程很多时候都是要取舍的。

虽然java和php都是最好的编程语言(大家都这么争的),但我更倾向一门更简单的语言。而openresty,虽然性
能强悍,但lua仍然是动态语言,也会碰到前面说的动态语言一些问题。最后,前金山许式伟用的go,前快盘架构师葱头也用的go,所以我们很自然地选择了
go。

Openresty 用 lua 如果按照动态语言的角度去看,还真算不上,顶多是个简单点的 C。许式伟走的时候大多数都是
CPP,葱头目前我还不知道他创业用的是什么写的,不过他肯定没语言倾向。当年无论是 leo 还是 ufa,一个用 Python 一个用
Java, 他都是从工程实际来选择使用什么样的语言。

error,好吧,如果有语言洁癖的同学可能真的受不了go的语法,尤其是约定的最后一个返回值是error。

这其实是 Go style,无论是 go fmt 还是 error style,Go 其实是想抹平不同工程师之间的风格问题。不再为了一个缩进和大括号位置什么的浪费时间。这种方法并不是不好,只是我个人觉得没 rust 那种返回值处理友善。

GC,java的GC发展20年了,go才这么点时间,gc铁定不完善。所以我们仍然不能随心所欲的写代码,不然在大请求量下面gc可能会卡顿整个服务。所以有时候,该用对象池,内存池的一定要用,虽然代码丑了点,但好歹性能上去了。

1.4 开始 go 就是 100% 精确 GC 了,另外说到卡顿啊,完全和你怎么用对象有关,能内联绝不传引用大部分场景是完全足够的,这样 gc 的影响程度会最低。实在想用池……只能说为啥不选 Java。

天生的并行支持,因为goroutine以及channel,用go写分布式应用,写并发程序异常的容易。没有了蛋疼的callback导致的代码逻辑割裂,代码逻辑都是顺序的。

这是有代价的,goroutine 的内存消耗计算(当然1.3还是1.4开始得到了很大的改善,内存最小值限制已经没了),channel
跨线程带来的性能损耗(跨线程锁),还有对 goroutine 的控制力几乎为 0
等。总之这种嘛,算不上是杀手级特性,大家都有,是方便了一点,但也有自己的弊端。比如我们用 go 吧,经常就比较蛋疼 spawn 出去的
goroutine 怎么优美的 shutdown,反而有时候把事情做复杂化了。

性能,go的性能可能赶不上c,c++以及openresty,但真的也挺强悍的。在我们的项目中,现在单机就部署了一个go的进程,就完全能够胜任以前200个python进程干的事情,而且CPU和MEM占用更低。

我不严谨的实测大概 gevent+py2 能达到同样逻辑 go 实现的 30%~40%,pypy+tornado 能达到
80%~90%,混合了一些计算和连接处理什么的。主要还是看业务场景吧,纯粹的 CPU bound 当然是 go 好,纯粹的 IO bound
你就是用 C 也没用啊。

运维部署,直接编译成二进制,扔到服务器上面就成,比python需要安装一堆的环境那是简单的太多了。当然,如果有cgo,我们也需要将对应的动态库给扔过去。

我们现在根据 glibc 所处的 host 版本不同有2套编译环境,看上去是部署简单了,编译起来坑死你。另外虽然说 disk 便宜,这几行代码就几M了,集群同步部署耗时在某些情况下还真会出篓子。

开发效率,虽然go是静态语言,但我个人感觉开发效率真的挺高,直觉上面跟python不相上下。对于我个人来说,最好的
例子就是我用go快速开发了非常多的开源组件,譬如ledisdb,go-mysql等,而这些最开始的版本都是在很短的时间里面完成的。对于我们项目来
说,我们也是用go在一个月就重构完成了第一个版本,并发布。

Ⅱ python中yield和return究竟有什么区别,怎么用

常看到别人使用或讨论yield语法,能搜到的中文解释却不多,今天决心搞定yield,把暂时的理解贴到这里.

搞定yield之前: 叠代器(iterator)

发现yield: 生成器(constructor)

使用yield: 递归调用

1. iterator

叠代器最简单例子应该是数组下标了,且看下面的c++代码:

int array[10];

for ( int i = 0; i < 10; i++ )

printf("%d ", array[i]);

叠代器工作在一个容器里(array[10]),它按一定顺序(i++)从容器里取出值(array[i])并进行操作(printf("%d ", array[i])。

上面的代码翻译成python:

array = [i for i in range(10)]

for i in array:

print i,

for i in array干了什么(别乱想)?首先,array作为一个list是个容器,其次list这个内建类型有默认的next行为,python发现这些之后采 取的秘密的没被各位看到的动作是:拿出array这丫容器的叠代器,从里面next一下把值给i供for循环主体处置,for把这个值print了。

现在的问题是数据可以做容器叠代,代码可以吗?

怎么不行,碗碟可以用来放菜,wk们不就联想出用nt盛吗,当然我们的yield不会那么yellow + bt

2. constructor

怎么把函数变成constructor? 在函数体里有yield就行了!

def gen():
print 'enter'
yield 1
print 'next'
yield 2
print 'next again'

for i in gen():
print i

各位!python看到gen函数里出现yield,知道可以用next了,问题是怎么对代码这个容器玩next?

从容器里拿到iterator的时候它还什么也不是,处在容器入口处,对于数组来说就是下标为-1的地方,对于函数来说就是函数入口嘛事没干,但是万事俱备就欠next。

开始for i in g,next让itreator爬行到yield语句存在的地方并返回值,

再次next就再爬到下一个yield语句存在的地方并返回值,依次这样直到函数返回(容器尽头)。
您一定看出来上面代码的输出是:

enter
1
next
2
next again

如果没看出来请不要往下看了免得反被yield搞定。

3. 使用yield

yield的代码叠代能力不但能打断函数执行还能记下断点处的数据,下次next书接上回,这正是递归函数需要的。

例如中序遍历二叉树:

(应该是David Mertz写的)

def inorder(t):
if t:
for x in inorder(t.left):
yield x
yield t.label
for x in inorder(t.right):
yield x

for n in inorder(tree)

print n

当然yield这种代码next的能力还可以用在其它方面,发现拍案的在贴咯。

Ⅲ python yield怎么实现的

yield是生成器关键词,是在函数内使用的生成器语法(你也可以理解为是用在函数内的创建生成器的方法),让函数返回的是一个生成器而不再返回函数计算得到的结果。比如:

同样的迭代完再迭代则会报错

Ⅳ Python 3.6 有什么新特性

有哪些重要的新特性。

1. 格式化字符串字面量

PEP 498引入了 f-string,一种新型的字符串字面量。中文翻译为“格式化字符串字面量”。

这种字符串以 f 为前缀,类似 str.format() 方法所接受的字符串。其中的可替换字段用 {} 包裹起来,在运行时进行求值。

具体代码示例:

>>> width = 10
>>> precision = 4
>>> value = decimal.Decimal("12.34567")
>>> f"result: {value:{width}.{precision}}" # nested fields
'result: 12.35'
2. 变量注释语法

此前,Python 已加入了对函数变量类型进行注释的标准,也就是 type hint。而 Python 3.6 中则根据PEP 526的提议,加入了对更多变量类型注释的功能,包括类变量和实例变量。

具体代码示例:

captain: str # 未设置初始值
class Starship:
stats: Didct[str, int] = {}
与静态语言中的变量声明不同,Python 中的变量声明是为了更加方便地位第三方工具和库提供结构化的类型元数据。会使用到新语法的工具包括:mypy,pytype,PyCharm,等等。

3. 数字字面量使用下划线

对于较大的数字来说,位数太多可能不好判断值到底有多大。现在新版本中将允许你在数字字面量中使用下划线,提高可读性。

具体代码示例:

>>> 1_000_000_000_000_000
1000000000000000
>>> 0x_FF_FF_FF_FF
4294967295
4. 异步生成器

在上一个版本中,Python 引入了对原生协程的支持,并可使用 async 或 await 语法,但是有一个限制是没办法在同一个函数体中使用 await 和 yield 。这个限制在 3.6 版中取消了,因此以后将可以定义异步生成器。

具体代码示例:

async def ticker(delay, to):
"""Yield numbers from 0 to *to* every *delay* seconds."""
for i in range(to): yield i
await asyncio.sleep(delay)
使用新语法,可以让你的代码更简洁,运行速度更快。

5. 异步推导

推导(Comprehension)本身就是 Python中一个很棒的语法糖。在新版本中,它将得到一次重大升级。PEP 530提出了在列表、元组、字典推导或生成器表达式中使用 async for 语法。

这样就将原有各种推导式变成了可支持异步。

同时,推导式中还支持使用 await 表达式。

以上就是 3.6 版本中新增的 5 大特性:

格式化字符串字面量

变量注释语法

数字字面量使用下划线

异步生成器

异步推导

Ⅳ Python的yield问题

python yield from

defgenerator2():
foriinrange(10):
yieldidefgenerator3():
forjinrange(10,20):
yieldjdefgenerator():
foriingenerator2():
yieldi
forjingenerator3():
yieldj

==

defgenerator():
yieldfromgenerator2()
yieldfromgenerator3()

Ⅵ Python yield 语句

我在2x版本下测试下显式调用throw来抛出GeneratorExit异常是可以被捕获的

我查了一下文档,楼主你的理解可能错了,文档的意思是说迭代器调用close退出时如果处于暂停状态就会内部产生一个GeneratorExit异常,这个异常是不能捕获的,内部会转换成RuntimeError抛出

正常退出的话则产生StopIteration异常

测试代码如下

defmy_generator():
try:
yield'dosomething'
exceptValueError:
yield'dealingwiththeexceptions'
exceptGeneratorExit:
yield"Yes,Icanyieldavalue"
finally:
print"Ok,let'sclean"

gen=my_generator()
gen.next()#这行注释掉后则不会抛出异常
try:
gen.close()
exceptRuntimeError:
print"closeerror"

Ⅶ scrapy使用yield返回Request的步骤是怎么样的

Python的yield是一个比较特别的关键字。

>>>deftest_yield():
...foriinrange(3):
...yieldi
...
>>>test_yield()
<generatorobjecttest_yieldat0x01AB2C88>

很明显的看到,yield不同于return。return直接返回函数返回值。而包含yield的函数,不返回而是生成了一个对象。这个对象叫做生成器(generator)。实际上test_yield中的for循环并没有在调用test_yield函数时执行完毕,而是每次遇到yield都会停止在执行yield前,当你调用生成器的next方法时,yield就会执行,这时返回紧接着yield的变量。

>>>gen=test_yield()
>>>gen.next()
0
>>>gen.next()
1
>>>gen.next()
2
>>>gen.next()
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<mole>
StopIteration

可以看到,返回2时,生成器中的for循环已经执行完毕,函数中没有可执行的yield。这时再next就会抛出StopIteration的异常,以此表示生成器的结束。

实际上,生成器也可用循环进行迭代。

>>>foreachintest_yield():
...printeach
...
0
1
2

而且Python中xrange不同于range产生list,xrange产生的是一个生成器。

>>>range(3)
[0,1,2]
>>>xrange(3)
xrange(3)

在Scrapy中,Spider解析网页的方法中就用到yield。当然,不用yield也是可以的,但你需要返回一个包含从传入的Response中解析出的所有Request或是Item的list。

classDemoSpider(Spider):
name='demo'
...
defparse(self,response):
sel=Selector(response)
forurlinsel.xpath('//a/@href').extract():
yieldRequest(url)

或者

classDemoSpider(Spider):
name='demo'
...
defparse(self,response):
sel=Selector(response)
requests=[]
forurlinsel.xpath('//a/@href').extract():
requests.append(Request(url))
returnrequests

总之,要返回一个可迭代的对象。

那么,为何要存在yield这种东西?直接返回list不成吗?试想一下,如果需要返回包含成百上千个元素的list,想必会占用很多计算机资源以及时间。如果用yield就可以缓和这种情况了。


以上部分代码仅适用Python2。

Ⅷ python中的yield能嵌套吗

可以嵌套,给你个例子,用python3可以直接运行
#!/usr/local/bin/python3
#-*- coding:utf-8 -*-

def consum(man):
print("1111111111111111")
while True:
print("22222222222:%s need foods"%man)
bone = yield
print("33333333333:%s eat %s foods"%(man,bone))

def proct(obj):
print("444444444444");
while True:
r = yield
print("55555555555r==%s"%r);
for i in range(r):
print("proct:making food index is %s"%i);
obj.send(i)

if __name__ == "__main__":
con1 = consum("Fat")
con1.send(None)
con2 = proct(con1)
con2.send(None)
con2.send(2)
con2.send(4)
con2.send(6)

Ⅸ Python3的关键字有哪些

按照官方文档,关键字有

False class finally is return

None continue for lambda try

True def from nonlocal while

and del global not with

as elif if or yield

assert else import pass

break except in raise

Ⅹ 不合法的Python3变量名有

数字打头的标识符,标识符中出现“#”号等。
Python 语言的标识符必须以字母、下画线(_)开头,后面可以跟任意数目的字母、数字和下画线(_)。此处的字母并不局限于 26 个英文字母,可以包含中文字符、日文字符等。

热点内容
择吉日推算法 发布:2025-01-17 15:29:41 浏览:87
努比亚怎么查看wifi密码 发布:2025-01-17 15:29:36 浏览:202
简单游使用脚本 发布:2025-01-17 15:23:57 浏览:580
linuxcompare 发布:2025-01-17 15:13:24 浏览:433
不能显示隐藏的文件夹 发布:2025-01-17 15:13:24 浏览:530
学生作业管理系统源码 发布:2025-01-17 14:42:31 浏览:172
hue编译器 发布:2025-01-17 14:42:26 浏览:908
马自达编程 发布:2025-01-17 14:21:41 浏览:495
android语音demo 发布:2025-01-17 14:19:25 浏览:703
点歌机怎么选切换安卓系统 发布:2025-01-17 14:05:33 浏览:722