目前,我有一个应用程序,它使用cmd.Cmd模块作为命令行界面,tab-completion完美地工作.
现在,我想sys.stdout用另一个对象替换(例如,为了捕获正在写的内容.)
在理论上,以下片段应该是完全透明的,因为对Std对象的每个get/set操作都被重定向到actial sys.__stdout__.
class Std(object):
def __getattribute__(self, name):
if name in ('__getattribute__', '__setattr__'):
return object.__getattribute__(self, name)
else:
return getattr(sys.__stdout__, name)
def __setattr__(self, name, value):
setattr(sys.__stdout__, name, value)
sys.stdout = Std()
Run Code Online (Sandbox Code Playgroud)
例如,sys.stdout.fileno()仍将打印1.但是,readline标签完成Cmd.cmd现在不再有效...
好的,让我们继承文件.(stdout是一个文件对象.)
class Std(file):
def __init__(self):
pass
def __getattribute__(self, name):
if name in ('__getattribute__', '__setattr__'):
return object.__getattribute__(self, name)
else:
return getattr(sys.__stdout__, name)
def __setattr__(self, name, value):
setattr(sys.__stdout__, name, value)
sys.stdout = Std()
Run Code Online (Sandbox Code Playgroud)
现在我得到:
Traceback (most recent call last):
File "./shell.py", line 61, in <module>
print '#1'
ValueError: I/O operation on closed file
Run Code Online (Sandbox Code Playgroud)
但是,以下断言不会失败:
assert not sys.stdout.closed
Run Code Online (Sandbox Code Playgroud)
不知怎的,我猜,Python过度优化了某些东西,绕过了Std.write.
如何在不失去readline支持的情况下更换stdout应该怎么办?
乔纳森
-编辑-
我也试图替换sys.stdin.将其传递给cmd.Cmd不起作用,因为raw_input用于readline支持,而Python的raw_input不接受文件描述符.它回退到分配给sys.stdin的pty.
当我创建一个新的pty(通过os.openpty()),并将该对赋值给sys.stdin/out时,通过该pty的readline自动完成工作完美,但同样,当包装在代理对象中时,它可以工作,但是没有自动完成.
试图理解readline的来源,但这并不容易:http: //svn.python.org/projects/python/branches/release25-maint/Modules/readline.c
我不确切知道为什么替换sys.stdout不起作用,但在任何情况下,您都可以通过将自己的文件对象传递给cmd.Cmd.
这是一个示例脚本(部分借自PyMOTW),演示了制表符补全:
import sys, cmd
class Std(object):
def __getattribute__(self, name):
if name in ('__getattribute__', '__setattr__'):
return object.__getattribute__(self, name)
else:
return getattr(sys.__stdout__, name)
def __setattr__(self, name, value):
setattr(sys.__stdout__, name, value)
class HelloWorld(cmd.Cmd):
FRIENDS = [ 'Alice', 'Adam', 'Barbara', 'Bob' ]
def do_greet(self, person):
"Greet the person"
if person and person in self.FRIENDS:
greeting = 'hi, %s!' % person
elif person:
greeting = "hello, " + person
else:
greeting = 'hello'
print greeting
def complete_greet(self, text, line, begidx, endidx):
if not text:
completions = self.FRIENDS[:]
else:
completions = [f for f in self.FRIENDS
if f.startswith(text)]
return completions
def do_EOF(self, line):
return True
if __name__ == '__main__':
HelloWorld(stdout=Std()).cmdloop()
Run Code Online (Sandbox Code Playgroud)
就您的目的而言,这是一种更好的处理方式,因为它确保您只会捕获实例Cmd产生的输出。
请注意,您传入的文件对象也可用作stdout实例的属性Cmd。
| 归档时间: |
|
| 查看次数: |
1779 次 |
| 最近记录: |