前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python递归中使用协程yield

Python递归中使用协程yield

作者头像
HHTjim 部落格
发布2022-09-26 10:42:03
3770
发布2022-09-26 10:42:03
举报
文章被收录于专栏:HHTjim'S 部落格

Python递归中使用协程yield

作者:matrix 被围观: 2,068 次 发布时间:2019-06-11 分类:Python | 无评论 »

这是一个创建于 1177 天前的主题,其中的信息可能已经有所发展或是发生改变。

修改递归函数用于遍历目录中文件。

普通操作

代码语言:javascript
复制
def recursive_open_file(path):
    rel = []
    path_dir = os.listdir(path)  # 获取当前路径下的文件名,返回List
    for s in path_dir:
        new_dir = os.path.join(path, s)  # 将文件命加入到当前文件路径后面
        if os.path.isfile(new_dir):  # 如果是文件
            if os.path.splitext(new_dir)[1] == ".txt":  # 判断是否是txt
                rel.append(new_dir)
        else:
            rel = rel + recursive_open_file(new_dir)
    return rel

# print(type(recursive_open_file(dir))) # <class 'list'>

调试yield

想用协程目的是为了想让程序找到相关文件之后中断挂起然后返回数据,避免一次性加载全部资源在内存中。

之前是想的太简单,没用过果真是不知道。

错误版本
代码语言:javascript
复制
def recursive_open_file(path):
    path_dir = os.listdir(path)  # 获取当前路径下的文件名,返回List
    for s in path_dir:
        new_dir = os.path.join(path, s)  # 将文件命加入到当前文件路径后面
        if os.path.isfile(new_dir):  # 如果是文件
            if os.path.splitext(new_dir)[1] == ".txt":  # 判断是否是txt
                yield new_dir
        else:
            yield recursive_open_file(new_dir)

#执行
for i in recursive_open_file(dir):
    print(i) #无法获取文件路径

说明:

yield recursive_open_file(new_dir)返回给外部调用层的数据为<generator object recursive_open_file at 0x10f7765e8> ,不是想要的String!!

正常版本

内部再迭代下就好了 🙈

代码语言:javascript
复制
def recursive_open_file(path):
    path_dir = os.listdir(path)  # 获取当前路径下的文件名,返回List
    for s in path_dir:
        new_dir = os.path.join(path, s)  # 将文件命加入到当前文件路径后面
        if os.path.isfile(new_dir):  # 如果是文件
            if os.path.splitext(new_dir)[1] == ".txt":  # 判断是否是txt
                yield new_dir
        else:
            for i in recursive_open_file(new_dir):
                yield i

PHP协程递归同理

代码语言:javascript
复制
function openDirectory($path)
{
    $dir = dir($path);
    while (false != ($entry = $dir->read())) {
        if ($entry != "." && $entry != "..") {
            $n_path = $path . DIRECTORY_SEPARATOR . $entry;
            if (is_dir($n_path)) {
                foreach (openDirectory($n_path) as $i){
                    yield $i;
                }
            } else {
                yield $n_path;
            }
        }
    }
}

//调用执行
$dir = '/Users/panc/Desktop/Python/testfile';
foreach (openDirectory($dir) as $item){
    print_r($item);
    print_r("\n");
}

协程send操作

按照廖雪峰的协程教程的生产者-消费者模式:

代码语言:javascript
复制
def consumer():
    r = ''
    while True:
        n = yield r
        if not n:
            return
        print('[CONSUMER] Consuming %s...' % n)
        r = '200 OK'

def produce(c):
    c.send(None)#启动
    n = 0
    while n < 5:
        n = n + 1
        print('[PRODUCER] Producing %s...' % n)
        r = c.send(n)
        print('[PRODUCER] Consumer return: %s' % r)
    c.close()#关闭

c = consumer()
produce(c)

笔记:

c = consumer()不会执行consumer函数,因为内部有yield关键字,consumer函数是生成器generator对象。

通过多个断点调适可以看到yield处的代码会中断执行,然后切换到起调函数的位置继续执行

yield r相似于return返回数据,返回给send()方法返回值。

send(n)操作是把n发送给yield r的返回值

c.send(None)用于启动consumer函数,程序会进入while True循环,在yield处中断

这里yield操作相比较递归遍历那头来说更加麻烦些,因为执行的时候会在两个函数之间相互切换,互相发送数据,需要send方法来启动生成器generator对象。consumer内部因为是while true,所以记得要关闭c.close()

参考:

https://www.liaoxuefeng.com/wiki/1016959663602400/1017968846697824

https://github.com/Earthson/RecGen

https://blog.csdn.net/mieleizhi0522/article/details/82142856

https://blog.51cto.com/xtceetg/1874982

PEACE~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Python递归中使用协程yield
    • 普通操作
      • 调试yield
        • PHP协程递归同理
          • 协程send操作
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档