4

我在 Python 中有这个有点复杂的命令行函数(让我们称之为myFunction()),我正在努力将它集成到图形界面中(使用 PySide/Qt)。

GUI 用于帮助选择输入和显示输出。然而,myFunction它被设计成一个独立的命令行功能,它偶尔会打印出进度。

我的问题是:如何拦截这些print调用并在 GUI 中显示它们?我知道可以修改myFunction()以发送processEvents()到 GUI,但我会失去myFunction()在终端中执行的能力。

理想情况下,我想要类似于 Ubuntu 的图形软件更新程序的东西,它有一个小型嵌入式终端外观小部件,显示apt-get在终端中执行时会显示的内容。

4

4 回答 4

8

您可以重定向标准输出并在之后恢复。例如:

import StringIO
import sys

# somewhere to store output
out = StringIO.StringIO()

# set stdout to our StringIO instance
sys.stdout = out

# print something (nothing will print)
print 'herp derp'

# restore stdout so we can really print (__stdout__ stores the original stdout)
sys.stdout = sys.__stdout__

# print the stored value from previous print
print out.getvalue()
于 2013-06-12T14:13:39.450 回答
2

用一个劫持标准输出的函数包装它:

def stdin2file(func, file):
  def innerfunc(*args, **kwargs):
    old = sys.stdout
    sys.stdout = file
    try:
      return func(*args, **kwargs)
    finally:
      sys.stdout = old
  return innerfunc

然后只需提供一个类似对象的文件,它支持write()

class GUIWriter:
  def write(self, stuff):
    #send stuff to GUI

MyFunction = stdin2file(MyFunction, GUIWriter())

包装器也可以变成装饰器:

def redirect_stdin(file):
  def stdin2file(func, file):
    def innerfunc(*args, **kwargs):
      old = sys.stdout
      sys.stdout = file
      try:
        return func(*args, **kwargs)
      finally:
        sys.stdout = old
    return innerfunc
  return stdin2file

声明时使用它MyFunction()

@redirect_stdin(GUIWriter())
def MyFunction(a, b, c, d):
  # any calls to print will call the 'write' method of the GUIWriter
  # do stuff
于 2013-06-12T14:15:31.840 回答
1

所有打印都是通过 完成sys.stdout的,这是一个普通的类似文件的对象:iirc,它需要一个方法write(str)。只要您的替代品有这种方法,就很容易陷入困境:

import sys

class CaptureOutput:
    def write(self, message):
        log_message_to_textbox(message)

sys.stdout = CaptureOutput()

实际内容由log_message_to_textbox您决定。

于 2013-06-12T14:10:59.167 回答
1

这是一个使用 contextmanager 的 Python 3 模式,它既封装了猴子补丁技术,又确保sys.stdout在发生异常时恢复。

from io import StringIO
import sys
from contextlib import contextmanager


@contextmanager
def capture_stdout():
    """
    context manager encapsulating a pattern for capturing stdout writes
    and restoring sys.stdout even upon exceptions

    Examples:
    >>> with capture_stdout() as get_value:
    >>>     print("here is a print")
    >>>     captured = get_value()
    >>> print('Gotcha: ' + captured)

    >>> with capture_stdout() as get_value:
    >>>     print("here is a print")
    >>>     raise Exception('oh no!')
    >>> print('Does printing still work?')
    """
    # Redirect sys.stdout
    out = StringIO()
    sys.stdout = out
    # Yield a method clients can use to obtain the value
    try:
        yield out.getvalue
    finally:
        # Restore the normal stdout
        sys.stdout = sys.__stdout__
于 2018-03-09T16:17:14.260 回答