Can I redirect the stdout in python into some sort of string buffer?

前端 未结 9 1714
野趣味
野趣味 2020-11-22 06:23

I\'m using python\'s ftplib to write a small FTP client, but some of the functions in the package don\'t return string output, but print to stdout.

9条回答
  •  忘掉有多难
    2020-11-22 06:45

    This method restores sys.stdout even if there's an exception. It also gets any output before the exception.

    import io
    import sys
    
    real_stdout = sys.stdout
    fake_stdout = io.BytesIO()   # or perhaps io.StringIO()
    try:
        sys.stdout = fake_stdout
        # do what you have to do to create some output
    finally:
        sys.stdout = real_stdout
        output_string = fake_stdout.getvalue()
        fake_stdout.close()
        # do what you want with the output_string
    

    Tested in Python 2.7.10 using io.BytesIO()

    Tested in Python 3.6.4 using io.StringIO()


    Bob, added for a case if you feel anything from the modified / extended code experimentation might get interesting in any sense, otherwise feel free to delete it

    Ad informandum ... a few remarks from extended experimentation during finding some viable mechanics to "grab" outputs, directed by numexpr.print_versions() directly to the ( upon a need to clean GUI and collecting details into debugging-report )

    # THIS WORKS AS HELL: as Bob Stein proposed years ago:
    #  py2 SURPRISEDaBIT:
    #
    import io
    import sys
    #
    real_stdout = sys.stdout                        #           PUSH  ( store to REAL_ )
    fake_stdout = io.BytesIO()                      #           .DEF FAKE_
    try:                                            # FUSED .TRY:
        sys.stdout.flush()                          #           .flush() before
        sys.stdout = fake_stdout                    #           .SET  to use FAKE_
        # ----------------------------------------- #           +    do what you gotta do to create some output
        print 123456789                             #           + 
        import  numexpr                             #           + 
        QuantFX.numexpr.__version__                 #           + [3] via fake_stdout re-assignment, as was bufferred + "late" deferred .get_value()-read into print, to finally reach -> real_stdout
        QuantFX.numexpr.print_versions()            #           + [4] via fake_stdout re-assignment, as was bufferred + "late" deferred .get_value()-read into print, to finally reach -> real_stdout
        _ = os.system( 'echo os.system() redir-ed' )#           + [1] via real_stdout                                 + "late" deferred .get_value()-read into print, to finally reach -> real_stdout, if not ( _ = )-caught from RET-d "byteswritten" / avoided from being injected int fake_stdout
        _ = os.write(  sys.stderr.fileno(),         #           + [2] via      stderr                                 + "late" deferred .get_value()-read into print, to finally reach -> real_stdout, if not ( _ = )-caught from RET-d "byteswritten" / avoided from being injected int fake_stdout
                           b'os.write()  redir-ed' )#  *OTHERWISE, if via fake_stdout, EXC <_io.BytesIO object at 0x02C0BB10> Traceback (most recent call last):
        # ----------------------------------------- #           ?                              io.UnsupportedOperation: fileno
        #'''                                                    ? YET:        <_io.BytesIO object at 0x02C0BB10> has a .fileno() method listed
        #>>> 'fileno' in dir( sys.stdout )       -> True        ? HAS IT ADVERTISED,
        #>>> pass;            sys.stdout.fileno  -> 
        #>>> pass;            sys.stdout.fileno()-> Traceback (most recent call last):
        #                                             File "", line 1, in 
        #                                           io.UnsupportedOperation: fileno
        #                                                       ? BUT REFUSES TO USE IT
        #'''
    finally:                                        # == FINALLY:
        sys.stdout.flush()                          #           .flush() before ret'd back REAL_
        sys.stdout = real_stdout                    #           .SET  to use POP'd REAL_
        sys.stdout.flush()                          #           .flush() after  ret'd back REAL_
        out_string = fake_stdout.getvalue()         #           .GET string           from FAKE_
        fake_stdout.close()                         #                .close()
        # +++++++++++++++++++++++++++++++++++++     # do what you want with the out_string
        #
        print "\n{0:}\n{1:}{0:}".format( 60 * "/\\",# "LATE" deferred print the out_string at the very end reached -> real_stdout
                                         out_string #                   
                                         )
    '''
    PASS'd:::::
    ...
    os.system() redir-ed
    os.write()  redir-ed
    /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
    123456789
    '2.5'
    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    Numexpr version:   2.5
    NumPy version:     1.10.4
    Python version:    2.7.13 |Anaconda 4.0.0 (32-bit)| (default, May 11 2017, 14:07:41) [MSC v.1500 32 bit (Intel)]
    AMD/Intel CPU?     True
    VML available?     True
    VML/MKL version:   Intel(R) Math Kernel Library Version 11.3.1 Product Build 20151021 for 32-bit applications
    Number of threads used by default: 4 (out of 4 detected cores)
    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
    >>>
    
    EXC'd :::::
    ...
    os.system() redir-ed
    /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
    123456789
    '2.5'
    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    Numexpr version:   2.5
    NumPy version:     1.10.4
    Python version:    2.7.13 |Anaconda 4.0.0 (32-bit)| (default, May 11 2017, 14:07:41) [MSC v.1500 32 bit (Intel)]
    AMD/Intel CPU?     True
    VML available?     True
    VML/MKL version:   Intel(R) Math Kernel Library Version 11.3.1 Product Build 20151021 for 32-bit applications
    Number of threads used by default: 4 (out of 4 detected cores)
    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
    
    Traceback (most recent call last):
      File "", line 9, in 
    io.UnsupportedOperation: fileno
    '''
    

提交回复
热议问题