Python:如何判断一个对象是否类似于文件?

5
我正在为我的应用编写一些单元测试(使用unittest模块),并希望编写一个可以验证我调用的方法返回一个“类文件”对象的东西。由于这不是一个简单的isinstance调用,我想知道确定这一点的最佳实践是什么?
因此,概述如下:
possible_file = self.dao.get_file("anotherfile.pdf")
self.assertTrue(possible_file is file-like)

也许我需要关注这个文件对象实现了哪些特定的接口,或者支持哪些让它类似于文件的方法?
谢谢,
R
3个回答

7
由于文件式对象的不同用途具有不同的要求,因此没有关于何为“足够类似文件”的“官方定义”——例如,某些用途只需要readwrite方法,而其他用途则需要一些行读取方法的子集……或者需要fileno方法,这甚至无法由标准库中提供的“非常类似文件”的StringIOcStringIO模块提供。这绝对是一个“灰色地带”的问题,而不是黑白分明的分类!
因此,您需要确定您需要哪些方法。如果您使用的是Python 2.6或更高版本,则建议使用abstractmethod装饰器定义自己的FileLikeEnoughForMe 抽象基类,并使用isinstance检查该对象是否属于该类:这是现在推荐的习惯用法,而不是一堆hasattr检查,后者会更加复杂,也不如前者易读(当然,后者需要增加检查这些属性是否实际上是方法等检查)。

嗨Alex,谢谢你的指点,这是有趣的东西,尽管我还在努力理解它。你建议只在单元测试中使用它,还是应该将其作为管理应用程序内类似文件对象的一般方法? - Richard J
@Richard,我自己在Python中使用ABCs的生产环境中还是初学者(尽管与Haskell类型类、C++的抽象基类、Java接口等的类比有所帮助;-),因此我不能(尚未)在这种情况下坚定地推荐它们或否认它们。我认为它们会很好(再次通过我非常了解的替代方案的类比),但我需要更多实际的应用经验才能真正自信。但是,出于测试目的,我已经知道它们是“猫的睡衣”,也就是说,确实非常优秀和有用。 - Alex Martelli
请勿在注释中使用代码标记! - Richard J
@Richard,你看过http://docs.python.org/library/abc.html上的代码示例吗?特别是`MyIterable`示例及其对`__subclasshook__`的重写--它展示了如何检查某些方法是否存在(虽然这只是一个简化的示例,没有检查它们是否为方法)。一般来说,这不是使用ABCs的最佳方式,因为缺乏任何显式注册(或子类化)会剥夺您验证**意图**(著名的“draw方法问题”)的关键优势,但如果您正在检查存在性,那么在2.6+中就可以这样做。 - Alex Martelli

4
经典的Python思维方式是“宁愿请求原谅,也不要征得许可”。换句话说,不要检查,捕获由写入引起的异常。
新的方法是使用IO抽象基类进行isinstance检查。当人们意识到鸭子类型很棒,但有时确实需要实例检查时,就引入了这种方法。
在您的情况下(单元测试),您可能希望尝试并查看:
thingy = ...
try:
    thingy.write( ... )
    thingy.writeline( ... )
    ...
    thingy.read( )
except AttributeError:
    ...

2
在单元测试环境中,尝试写入文件可能不是合适的做法。 - Ned Batchelder
+1 对于古典和文艺复兴思维模式。 - Wayne Werner
@Ned:真的吗?如果你正在实现一个类似文件的类,那么你肯定应该测试它是否确实写下了你给它的内容?但是如果你真的不想这样做,那么你可以使用hasattr - Katriel
@Ned,那不是要看文件写入实际在做什么吗?也就是说,单元测试应该在测试完毕后进行“清理”,以便确认程序的这部分确实有写入吗? - Wayne Werner
@Wayne,@katrielalex:是的,您可能想要写入它,而且根据文件类型,您可能会自动清除。我的意思是,典型编程中使用的逻辑(请求原谅)可能不适用于单元测试,这取决于测试的目的是什么。就这些。 - Ned Batchelder
谢谢你!我正在弄清楚ABC,结合另一个答案看起来这是正确的方法。我会继续阅读... - Richard J

2

检查返回的对象是否提供你正在寻找的接口。例如:

self.assert_(hasattr(possible_file, 'write'))
self.assert_(hasattr(possible_file, 'read'))

1
除非你确定想要这样做,否则不要这样做。 - Katriel
是的,我不会这样做。但他要求一种检查某个东西是否类似于文件的方法,而不是将其用作文件。 - gruszczy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接