【问题标题】:How to use StringIO in Python3?如何在 Python3 中使用 StringIO?
【发布时间】:2012-08-08 12:16:55
【问题描述】:

我使用的是 Python 3.2.1,但无法导入 StringIO 模块。我用 io.StringIO 并且它可以工作,但我不能像这样将它与 numpygenfromtxt 一起使用:

x="1 3\n 4.5 8"        
numpy.genfromtxt(io.StringIO(x))

我收到以下错误:

TypeError: Can't convert 'bytes' object to str implicitly  

当我写 import StringIO 时,它说

ImportError: No module named 'StringIO'

【问题讨论】:

    标签: python python-3.x io


    【解决方案1】:

    当我写 import StringIO 时,它说没有这样的模块。

    来自What’s New In Python 3.0

    StringIOcStringIO 模块已消失。相反,导入io 模块并使用 io.StringIOio.BytesIO 获取文本和数据 分别。

    .


    修复一些 Python 2 代码以使其在 Python 3 中也能正常工作的一种可能有用的方法(警告购买者):

    try:
        from StringIO import StringIO ## for Python 2
    except ImportError:
        from io import StringIO ## for Python 3
    

    注意:此示例可能与问题的主要问题无关,仅作为一般解决缺少的 StringIO 模块时需要考虑的内容。 要获得更直接的解决方案,请发送消息 @ 987654330@,见this answer

    【讨论】:

    • 值得一提的是,这些并不相同,因此如果您单独进行此更改,您最终可能会得到TypeErrors(字符串参数预期,得到“字节”)。你需要仔细区分python 3中的btyes和str(unicode)。
    • 对于像我这样的新手:from io import StringIO 意味着您将其称为 StringIO(),而不是 io.StringIO()。
    • 如何真正兼容 Python 2 和 3:from io import StringIO
    • 这对于 python 3 中的 numpy.genfromtxt() 来说是完全错误的。请参考 Roman Shapovalov 的回答。
    • @nobar:后者。最初的问题使用 python 3.x,模块 StringIO 已经消失,应该改用 from io import BytesIO。在 python 3.5 @ eclipse pyDev + win7 x64 上测试了自己。如果我错了,请告诉我谢谢。
    【解决方案2】:

    就我而言,我使用过:

    from io import StringIO
    

    【讨论】:

      【解决方案3】:

      在 Python 3 上,numpy.genfromtxt 需要一个字节流。使用以下内容:

      numpy.genfromtxt(io.BytesIO(x.encode()))
      

      【讨论】:

        【解决方案4】:

        感谢 OP 的提问,以及 Roman 的回答。我不得不搜索一下才能找到这个;我希望以下内容对其他人有所帮助。

        Python 2.7

        见:https://docs.scipy.org/doc/numpy/user/basics.io.genfromtxt.html

        import numpy as np
        from StringIO import StringIO
        
        data = "1, abc , 2\n 3, xxx, 4"
        
        print type(data)
        """
        <type 'str'>
        """
        
        print '\n', np.genfromtxt(StringIO(data), delimiter=",", dtype="|S3", autostrip=True)
        """
        [['1' 'abc' '2']
         ['3' 'xxx' '4']]
        """
        
        print '\n', type(data)
        """
        <type 'str'>
        """
        
        print '\n', np.genfromtxt(StringIO(data), delimiter=",", autostrip=True)
        """
        [[  1.  nan   2.]
         [  3.  nan   4.]]
        """
        

        Python 3.5:

        import numpy as np
        from io import StringIO
        import io
        
        data = "1, abc , 2\n 3, xxx, 4"
        #print(data)
        """
        1, abc , 2
         3, xxx, 4
        """
        
        #print(type(data))
        """
        <class 'str'>
        """
        
        #np.genfromtxt(StringIO(data), delimiter=",", autostrip=True)
        # TypeError: Can't convert 'bytes' object to str implicitly
        
        print('\n')
        print(np.genfromtxt(io.BytesIO(data.encode()), delimiter=",", dtype="|S3", autostrip=True))
        """
        [[b'1' b'abc' b'2']
         [b'3' b'xxx' b'4']]
        """
        
        print('\n')
        print(np.genfromtxt(io.BytesIO(data.encode()), delimiter=",", autostrip=True))
        """
        [[  1.  nan   2.]
         [  3.  nan   4.]]
        """
        

        旁白:

        dtype="|Sx",其中 x = { 1, 2, 3, ...} 中的任何一个:

        dtypes. Difference between S1 and S2 in Python

        "|S1 和 |S2 字符串是数据类型描述符;第一个表示数组包含长度为 1 的字符串,第二个表示长度为 2...."

        【讨论】:

          【解决方案5】:

          您可以使用six 模块中的StringIO

          import six
          import numpy
          
          x = "1 3\n 4.5 8"
          numpy.genfromtxt(six.StringIO(x))
          

          【讨论】:

            【解决方案6】:

            Roman Shapovalov 的代码应该可以在 Python 3.x 和 Python 2.6/2.7 中运行。这里又是一个完整的例子:

            import io
            import numpy
            x = "1 3\n 4.5 8"
            numpy.genfromtxt(io.BytesIO(x.encode()))
            

            输出:

            array([[ 1. ,  3. ],
                   [ 4.5,  8. ]])
            

            Python 3.x 的解释:

            • numpy.genfromtxt 采用字节流(一个类似文件的对象,被解释为字节而不是 Unicode)。
            • io.BytesIO 接受一个字节串并返回一个字节流。另一方面,io.StringIO 会接受一个 Unicode 字符串并返回一个 Unicode 流。
            • x 被分配了一个字符串文字,在 Python 3.x 中是一个 Unicode 字符串。
            • encode() 获取 Unicode 字符串 x 并从中生成一个字节字符串,从而为 io.BytesIO 提供一个有效参数。

            Python 2.6/2.7 的唯一区别是x 是一个字节串(假设from __future__ import unicode_literals 没有使用),然后encode() 取出字节串x 仍然输出相同的字节串其中。所以结果是一样的。


            由于这是 SO 关于StringIO 的最受欢迎的问题之一,这里有一些关于导入语句和不同 Python 版本的更多解释。

            以下是接受字符串并返回流的类:

            • io.BytesIO(Python 2.6、2.7 和 3.x)- 采用字节字符串。返回一个字节流。
            • io.StringIO(Python 2.6、2.7 和 3.x)- 采用 Unicode 字符串。返回一个 Unicode 流。
            • StringIO.StringIO (Python 2.x) - 采用字节字符串或 Unicode 字符串。如果是字节串,则返回一个字节流。如果是 Unicode 字符串,则返回 Unicode 流。
            • cStringIO.StringIO (Python 2.x) - StringIO.StringIO 的更快版本,但不能接受包含非 ASCII 字符的 Unicode 字符串。

            注意StringIO.StringIO 导入为from StringIO import StringIO,然后用作StringIO(...)。要么这样,要么你先使用import StringIO,然后使用StringIO.StringIO(...)。模块名和类名恰好是相同的。这种方式类似于datetime

            使用什么,取决于您支持的 Python 版本:

            • 如果您只支持 Python 3.x: 只需使用 io.BytesIOio.StringIO,具体取决于您使用的数据类型。

            • 如果您同时支持 Python 2.6/2.7 和 3.x,或者正在尝试将代码从 2.6/2.7 转换到 3.x: 最简单的选择仍然是使用 io.BytesIOio.StringIO。尽管StringIO.StringIO 很灵活,因此似乎更适合 2.6/2.7,但这种灵活性可能会掩盖 3.x 中出现的错误。例如,我有一些代码使用 StringIO.StringIOio.StringIO 取决于 Python 版本,但我实际上是在传递一个字节字符串,所以当我开始在 Python 3.x 中测试它时它失败了,必须修复.

              使用io.StringIO 的另一个优点是支持通用换行符。如果将关键字参数newline='' 传递给io.StringIO,它将能够在\n\r\n\r 中的任何一个上分割行。我发现StringIO.StringIO 尤其会在\r 上绊倒。

              请注意,如果您从six 导入BytesIOStringIO,您将在Python 2.x 中获得StringIO.StringIO,在Python 3.x 中从io 获得相应的类。如果您同意我前面段落的评估,这实际上是一种您应该避免使用six 而只是从io 导入的情况。

            • 如果您支持 Python 2.5 或更低版本和 3.x: 对于 2.5 或更低版本,您将需要 StringIO.StringIO,因此您不妨使用 six。但是要意识到同时支持 2.5 和 3.x 通常非常困难,因此您应该考虑尽可能将支持的最低版本升级到 2.6。

            【讨论】:

              【解决方案7】:

              为了从here做例子 使用 Python 3.5.2,你可以重写如下:

              import io
              data =io.BytesIO(b"1, 2, 3\n4, 5, 6") 
              import numpy
              numpy.genfromtxt(data, delimiter=",")
              

              更改的原因可能是文件的内容是数据(字节),在以某种方式解码之前不会生成文本。 genfrombytes 可能比 genfromtxt 更好。

              【讨论】:

                【解决方案8】:

                这是 Python 3 的另一个示例。它将使用两个函数将两个数字相加,然后使用 CProfile 保存.prof 文件。然后它将使用pstats.Stats 和```StringIO`` 加载保存文件,将数据转换为字符串以供进一步使用。

                main.py

                import cProfile
                import time
                import pstats
                from io import StringIO
                
                def add_slow(a, b):
                    time.sleep(0.5)
                    return a+b
                
                def add_fast(a, b):
                    return a+b
                
                prof = cProfile.Profile()
                
                def main_func():
                    arr = []
                    prof.enable()
                    for i in range(10):
                        if i%2==0:
                            arr.append(add_slow(i,i))
                        else:
                            arr.append(add_fast(i,i))
                    prof.disable()
                    #prof.print_stats(sort='time')
                    prof.dump_stats("main_funcs.prof")
                    return arr
                
                main_func()
                stream = StringIO();
                stats = pstats.Stats("main_funcs.prof", stream=stream); 
                stats.print_stats()
                stream.seek(0)
                print(16*'=',"RESULTS",16*'=')
                print (stream.read())
                

                用法:

                python3 main.py
                

                输出:

                ================ RESULTS ================
                Tue Jul  6 17:36:21 2021    main_funcs.prof
                
                         26 function calls in 2.507 seconds
                
                   Random listing order was used
                
                   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
                       10    0.000    0.000    0.000    0.000 {method 'append' of 'list' objects}
                        5    2.507    0.501    2.507    0.501 {built-in method time.sleep}
                        5    0.000    0.000    2.507    0.501 profiler.py:39(add_slow)
                        5    0.000    0.000    0.000    0.000 profiler.py:43(add_fast)
                        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
                
                

                评论:我们可以观察到,在上面的代码中,time.sleep 函数耗时大约 2.507 秒。

                【讨论】:

                  【解决方案9】:

                  我希望这能满足您的要求

                  import PyPDF4
                  import io
                  
                  pdfFile = open(r'test.pdf', 'rb')
                  pdfReader = PyPDF4.PdfFileReader(pdfFile)
                  pageObj = pdfReader.getPage(1)
                  pagetext = pageObj.extractText()
                  
                  for line in io.StringIO(pagetext):
                      print(line)
                  

                  【讨论】:

                    猜你喜欢
                    • 2013-11-12
                    • 2015-09-12
                    • 2020-04-30
                    • 2014-04-14
                    • 1970-01-01
                    • 1970-01-01
                    • 2021-08-29
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多