5.5 用Visitor模式多级遍历
对于一个单组来说,用基本遍历就足够了。但如果你需要遍历某个文件或某个组内所有的对象怎么办?
在HDF5的世界里,此类问题通过Visitor遍历解决。HDF5不再提供给你迭代器,而是你需要提供一个回调函数,HDF5会遍历每个对象并调用它。调用时会传入一个或两个参数。
5.5.1 以名字访问
你的入口点是Group类的visit方法。让我们创建一个简单文件来测试它:
我们可以给visit提供一个任意的回调函数,这个函数需要接受一个参数,就是对象的名字:
访问对象的先后顺序是随机的,只能保证当visit进入子组时,在没有遍历完全部成员前不会跑去下一个子组。比如,top_group_1下所有的成员都被列在一起,top_group_2也是如此。
你不需要访问整个文件,visit可以在子组上工作:
visitor模式和标准的Python遍历有点区别,但是一旦你掌握了它的用法,你会发现它的能力很强大。比如下面这两句简单的语句就能将文件中的所有对象做成一个列表:
提示
和文件中所有对象的名字一样,提供给visit的名字是一个“文本”字符串(Python 2中是Unicode,Python 3中是str)。写回调函数时请记住这一点。
5.5.2 多个链接和visit
当然,我们知道HDF5文件不仅是一个简单的树。硬链接在组内共享对象时很有用,那它跟visit合作得好不好呢?
让我们在刚刚探索过的子组(top_group_1)内添加一个硬链接,然后再次运行visit看看会发生什么:
不错。/top_group_2组被有效加载到/top_group_1/hardlink上,并且能被visit正确浏览。
现在让我们试点不一样的。我们删除上一个硬链接,并尝试让visit访问sub_dataset_1两次:
发生了什么?这次我们没看到输出sub_dataset_1。
根据设计,不管有多少个链接指向该对象,文件内每个对象只会被访问一次。这消除了无限循环的可能,以防止某些“聪明人”可能会这样做:
代价就是我们之前在讨论硬链接时介绍过的。对于对象来说没有什么“本名”或“真名”。所以如果有多个链接指向你的数据集,visit提供的名字可能不是你期望的那个。
5.5.3 访问对象
根据提供给你的回调函数的名字,你就可以用getitem获取组内对象:
但痛苦的是visit提供的name参数是一个相对路径,你的函数必须知道它正在遍历哪个组才能正确工作。上面的例子仅当它遍历grp时才能正常工作。
谢天谢地HDF5提供了一个更通用的方式解决这个问题。有一个visititems方法会提供一个相对名字和一个受遍历对象的实例:
由于每次遍历都会打开被访问的对象,所以这个函数会产生一些额外开销。你最好仅在你真的需要访问每个对象时才使用visititems,比如,你需要调查其特征的时候。
另一种方式是使用Python内建的工具functools.partial。比如这里有一个简单函数,可以打印组内每个对象的绝对路径:
用这种技术,你就能避免将你需要遍历的组“硬嵌入”你的回调函数。
5.5.4 遍历中止:一个简单的搜索策略
访问对象时有一种简单的方法退出。你可能注意到我们上面的printname函数没有显式的返回值,这对于Python意味着函数返回None。如果你返回任何其他的东西,visit或visititems方法都会立即停止并返回该值。
假设我们需要找到一个具有某个指定特征值的数据集:
我们将用于查找该对象的函数提供给visititems:
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论