<p>对我来说,这是一个固执己见的答案,检查文件类对象的属性以执行所需的操作是<strong>一种确定对象类型的python方法,因为这是pythonic的本质<a href="https://en.wikipedia.org/wiki/Duck_typing">duck tests/duck-typing</a>:</p>
<blockquote>
<p>Duck typing is heavily used in Python, with the canonical example being file-like classes (for example, <code>cStringIO</code> allows a Python string to be treated as a file). </p>
</blockquote>
<p><a href="https://docs.python.org/2/glossary.html#term-duck-typing">Or from the python docs’ definition of duck-typing</a></p>
<blockquote>
<p>A programming style which does not look at an object’s type to determine if it has the right interface; instead, the method or attribute is simply called or used (“<em>If it looks like a duck and quacks like a duck, it must be a duck.</em>”) By emphasizing interfaces rather than specific types, well-designed code improves its flexibility by allowing polymorphic substitution. Duck-typing avoids tests using <code>type()</code> or <code>isinstance()</code>. (Note, however, that duck-typing can be complemented with abstract base classes.) Instead, it typically employs <code>hasattr()</code> tests or EAFP programming.</p>
</blockquote>
<p>如果您非常强烈地认为仅仅检查接口的适用性是不够的,那么您可以对<code>basestring</code>或{<cd2>}进行反向测试,以测试所提供的对象是否是类似路径的。根据您的python版本,测试会有所不同。在</p>
<pre><code>is_file_like = not isinstance(fp, basestring) # python 2
is_file_like = not isinstance(fp, str) # python 3
</code></pre>
<p>在任何情况下,对于您的上下文管理器,我会继续创建一个完整的对象,如下面所示,以便包装您所寻找的功能。在</p>
^{2}$
<p>然后像这样使用它:</p>
<pre><code>with SpiffyContextGuard(obj, 'hamlet.txt', 'w', True) as f:
f.write('Oh that this too too sullied flesh\n')
fp = open('hamlet.txt', 'a')
with SpiffyContextGuard(obj, fp, 'a', False) as f:
f.write('Would melt, thaw, resolve itself into a dew\n')
with SpiffyContextGuard(obj, fp, 'a', True) as f:
f.write('Or that the everlasting had not fixed his canon\n')
</code></pre>
<p>如果要使用try/catch语义检查类型适合性,还可以将要公开的文件操作包装在上下文保护器上:</p>
<pre><code>class SpiffyContextGuard(object):
def __init__(self, spiffy_obj, file, mode, closefd=True):
self.spiffy_obj = spiffy_obj
self.fp = self.file_or_path = file
self.mode = mode
self.closefd = closefd
def seek(self, offset, *args):
try:
self.fp.seek(offset, *args)
except AttributeError:
self.fp = open(self.file_or_path, mode)
self.fp.seek(offset, *args)
# define wrappers for write, read, etc., as well
def __enter__(self):
return self
def __exit__(self, type_, value, traceback):
generated = '\n'.join(self.spiffy_obj.gen_file())
self.write(generated)
if self.closefd:
self.fp.__exit__()
</code></pre>