【问题标题】:StringIO and compatibility with 'with' statement (context manager)StringIO 和与 'with' 语句的兼容性(上下文管理器)
【发布时间】:2012-08-07 05:19:45
【问题描述】:

我有一些带有遗留函数的遗留代码,该函数将文件名作为参数并处理文件内容。代码的工作副本如下。

我想要做的不是必须将我生成的一些内容写入磁盘才能使用这个遗留功能,所以我虽然可以使用StringIO 创建一个对象来代替物理文件名。但是,这不起作用,如下所示。

我认为StringIO 是解决这个问题的方法。谁能告诉我是否有办法使用这个遗留函数并在参数中传递一些不是磁盘上的文件但可以被遗留函数处理的东西?旧版函数确实有 with 上下文管理器处理 filename 参数值。

我在谷歌遇到的一件事是:http://bugs.python.org/issue1286,但这对我没有帮助......

代码

from pprint import pprint
import StringIO

    # Legacy Function
def processFile(filename):
    with open(filename, 'r') as fh:
        return fh.readlines()

    # This works
print 'This is the output of FileOnDisk.txt'
pprint(processFile('c:/temp/FileOnDisk.txt'))
print

    # This fails
plink_data = StringIO.StringIO('StringIO data.')
print 'This is the error.'
pprint(processFile(plink_data))

输出

这是FileOnDisk.txt中的输出:

['This file is on disk.\n']

这是错误:

Traceback (most recent call last):
  File "C:\temp\test.py", line 20, in <module>
    pprint(processFile(plink_data))
  File "C:\temp\test.py", line 6, in processFile
    with open(filename, 'r') as fh:
TypeError: coercing to Unicode: need string or buffer, instance found

【问题讨论】:

    标签: python python-2.x with-statement contextmanager


    【解决方案1】:

    StringIO 实例已打开的文件。另一方面,open 命令只接受文件名,以返回打开的文件。 StringIO 实例不适合作为文件名。

    另外,您不需要关闭StringIO 实例,因此也不需要将其用作上下文管理器。虽然关闭实例会释放分配的内存,但让垃圾收集器获取对象也是如此。无论如何,contextlib.closing() context manager 可以负责关闭该对象,如果您想确保在释放内存的同时仍持有对该对象的引用。

    如果您的所有旧代码都可以采用文件名,那么StringIO 实例就不是可行的方法。请改用tempfile module 生成临时文件名。

    这是一个使用上下文管理器确保临时文件在之后被清理的示例:

    import os
    import tempfile
    from contextlib import contextmanager
    
    @contextmanager
    def tempinput(data):
        temp = tempfile.NamedTemporaryFile(delete=False)
        temp.write(data)
        temp.close()
        try:
            yield temp.name
        finally:
            os.unlink(temp.name)
    
    with tempinput('Some data.\nSome more data.') as tempfilename:
        processFile(tempfilename)
    

    您还可以切换到io 模块(在Python 2 和3 中提供)提供的更新的Python 3 基础架构,其中io.BytesIOStringIO.StringIO / cStringIO.StringIO 的更强大的替代品。该对象确实支持用作上下文管理器(但仍不能传递给open())。

    【讨论】:

    • @mike:由于创建时的 delete=False 参数,命名的临时文件将不会在关闭后立即被删除 — 阅读 docs .从 temp.close() 就在 yield temp.name 声明之前,这似乎是相当明显的......
    • you don't need to close a StringIO instance ;但是为什么会有一个close() 为StringIO 提供的方法呢?在这里查看这个问题stackoverflow.com/q/9718950/10204932。顺便说一句,很好的解释。
    • @Genius:更多的是让被垃圾收集的对象达到完全相同的效果。但是是的,调用.close() 将清除为内存中文件数据分配的内存缓冲区。
    【解决方案2】:

    这个是基于contextmanager的python doc

    它只是用简单的上下文包装了StringIO,当exit被调用时,它会返回到屈服点,并正确关闭StringIO。这避免了制作临时文件的需要,但是对于大字符串,这仍然会占用内存,因为 StringIO 缓冲了该字符串。 它适用于大多数您知道字符串数据不会很长的情况

    from contextlib import contextmanager
    
    @contextmanager
    def buildStringIO(strData):
        from cStringIO import StringIO
        try:
            fi = StringIO(strData)
            yield fi
        finally:
            fi.close()
    

    那么你可以这样做:

    with buildStringIO('foobar') as f:
        print(f.read()) # will print 'foobar'
    

    【讨论】:

    • 这可以用标准库来完成:“with closing(StringIO(.... data ....)) as f:”
    【解决方案3】:

    你可以定义自己的开放函数

    fopen = open
    def open(fname,mode):
        if hasattr(fname,"readlines"): return fname
        else: return fopen(fname,mode)
    

    但是想要在完成后调用 __exit__ 并且 StringIO 没有退出方法...

    你可以定义一个自定义类来使用这个打开

    class MyStringIO:
         def __init__(self,txt):
             self.text = txt
         def readlines(self):
              return self.text.splitlines()
         def __exit__(self):
              pass
    

    【讨论】:

    • 不幸的是,这并不能解决问题,因为它必须在遗留函数中
    • 只要它在同一个文件中,这个打开是否会覆盖它?
    • @jdi 我认为如果在遗留函数之前定义它可能会起作用,即在导入遗留模块时。
    • 其实让遗留模块接受自定义打开的唯一方法是先定义新的open,然后导入遗留模块,然后:legacy.open = open。因为遗留模块正在使用自己的范围。
    • 我开始提出另一个答案,但很快意识到这只是问题的一半,您的第二个示例涵盖了这个问题。您可以建议使用 tempfile.SpooledTenporaryFilemax_size=10e8 或其他更高的值。这将是一个类似文件的对象,在后台使用 StringIO,并且已经有一个上下文管理器。
    猜你喜欢
    • 2017-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-15
    • 2021-10-15
    • 2017-03-29
    • 1970-01-01
    相关资源
    最近更新 更多