如何记录Python交互式环境中的所有操作?

10 投票
4 回答
12045 浏览
提问于 2025-04-17 05:53

我想要实时访问解释器的输入、错误信息和标准输出。最好是把这些信息写入一个文件,这样我就可以在每次输入解释器命令后检查文件的变化。例如,在一个解释器会话中:

>>> 5 * 7
35
>>> print("Hello, world!")
Hello, world!
>>> "Hello, world!"
'Hello, world!'

我希望在日志文件中看到以下内容:

> 5 * 7
35
> print("Hello, world!")
Hello, world!
> "Hello, world!"
'Hello, world!'

格式并不重要;重要的是我可以在文件中搜索关键词,以便在会话中触发互动事件。

到目前为止,我在尝试实现这个目标时学到的内容:

Python的 code 模块让我可以创建一个 InteractiveConsole 对象,我可以重新定义它的 raw_input 方法来记录到文件,像这样:

import code
class LoggedConsole(code.InteractiveConsole):
  def __init__(self, locals):
    super(LoggedConsole, self).__init__(locals)
    self.file = open('consolelog.dat', 'a')

  def __del__(self):
    self.file.close()

  def raw_input(self, prompt=""):
    data = input(prompt)
    self.file.write(data+'\n')
    return data

此外,InteractiveConsole 还使用一个内置的 write 方法来记录错误,我可以重新定义它为:

def write(self, data):
  sys.stderr.write(data)
  self.file.write(data+'\n')

我还了解到,以下代码片段可以记录所有的标准输出:

class Tee(object):
  def __init__(self):
    self.file = open('consolelog.dat', 'a')
    self.stdout = sys.stdout

  def __del__(self):
    sys.stdout = self.stdout
    self.file.close()

  def write(self, data):
    self.file.write(data)
    self.stdout.write(data)

sys.stdout = Tee()

我尝试把这些东西结合起来,创建一个 LoggedConsole 对象,并把 Tee 传给它的 locals。

console = LoggedConsole(locals={sys.stdout:LoggedExec()})
console.interact()

(我之前没有传过 locals,所以可能这里做得不对,但我没有收到错误信息。)

总之,这将打开一个新的交互式控制台,并在关闭后记录所有输入和错误,但不记录输出。我在这方面纠结了很久,感觉快要成功了,但又不太确定。

另外,有没有办法让这一切在会话 进行中 就发生?目前所有的记录都是在会话结束后进行的。

谢谢你的时间,抱歉文字有点多。

编辑:我希望能在标准的Python解释器中实现这个功能,以便于移植。

编辑2:Jaime的代码片段非常有效,可以记录我需要的所有内容。不过,有没有办法让它实时记录,而不是等会话结束后再记录?

编辑3:我搞定了 :). 最终的有效代码片段:

import code
import sys

class Tee(object):
  def __init__(self, log_fname, mode='a'):
    self.log = open(log_fname, mode)

  def __del__(self):
    # Restore sin, so, se
    sys.stdout = sys.__stdout__
    sys.stdir = sys.__stdin__
    sys.stderr = sys.__stderr__
    self.log.close()

  def write(self, data):
    self.log.write(data)
    self.log.flush()
    sys.__stdout__.write(data)
    sys.__stdout__.flush()

  def readline(self):
    s = sys.__stdin__.readline()
    sys.__stdin__.flush()
    self.log.write(s)
    self.log.flush()
    return s

  def flush(foo):
    return

sys.stdout = sys.stderr = sys.stdin = Tee('consolelog.dat', 'w')

console = code.InteractiveConsole()
console.interact()

4 个回答

4

你可以简单地使用unix的script命令,试试这个:

script -a filename.txt
python
>> print("hi")
hi
>> exit()
exit

filename.txt会记录你在这个会话中做的所有事情,内容大概是这样的:

Script started on Sat Dec 14 11:18:41 2013
python
>> print('hi')
hi
>> exit()
exit

Script done on Sat Dec 14 11:18:59 2013
4

请查看Doug Hellmann的这篇关于Virtualenv的文章,里面介绍了如何记录一个iPython会话:

如果你习惯在交互式命令行中工作,但希望在关闭会话后能记录下你做过的事情以便将来参考,你可以使用iPython的记录功能把会话内容写入一个文件。要启动记录功能,可以使用控制命令%logstart,具体操作可以参考列表5。输出的文件是一个Python源文件,所以等你实验完后,可以很方便地整理一下,把它变成一个“真正的”模块。

In [6]: %logstart
Activating auto-logging. Current session state plus future input saved.
Filename       : ipython_log.py
Mode           : rotate
Output logging : False
Raw input log  : False
Timestamping   : False
State          : active

In [7]: a = 5

In [8]: b = 6

In [9]: c = a * b

In [10]: c

Out[10]: 30

In [11]: d = [ a, b, c]

In [12]: d

Out[12]: [5, 6, 30]

In [13]: %logstop
8

我只在python2.7中测试过这个。手头没有python3。

import code
import sys

class Tee(object):

  def __init__(self, log_fname, mode='a'):
    self.log = open(log_fname, mode)

  def __del__(self):
    # Restore sin, so, se
    sys.stdout = sys.__stdout__
    sys.stdir = sys.__stdin__
    sys.stderr = sys.__stderr__
    self.log.close()

  def write(self, data):
    self.log.write(data)
    sys.__stdout__.write(data)

  def readline(self):
    s = sys.__stdin__.readline()
    self.log.write(s)
    return s

# Tie the ins and outs to Tee.
sys.stdout = sys.stderr = sys.stdin = Tee('consolelog.dat', 'w')

console = code.InteractiveConsole()
console.interact()

撰写回答