InteractiveConsole.raw_input覆盖无效



使用代码时。InteractiveConsole作为基类,具有raw_input和write-only的重写,使用write方法。

>>> input()
''
>>> input("data? ")
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: bad argument type for built-in operation

空输入源于通常的控制台窗口(sys.stdin而不是覆盖)。

这些是覆盖:

def raw_input(self, p = ""):
    ''' input function:
            - runs a new thread to simulate input
            sys.stdin is not invoked anymore '''
    sys.stdout = StdOut # break capture, the idle is frozen.
    self.interrupt()
    #print("caught shell input", p)
    self.fire("stdin", self, p)
    self.inline = p
    pos = -1
    while pos < 0:
        time.sleep(0.1)
        pos = self.indata.find("n")
        if pos < 0:
            l = len(self.indata)
            if l:
                pos = l
    self.inline = ">>> "
    self.fire("inputcleared", self, self.inline)
    data = self.indata[:pos]
    self.indata = self.indata[pos+1:]
    self.updateListing(p+""+data+"n") 
    sys.stdout = self.out # start capture again, the idle continues.
    return data
def write(self, data):
    ''' stderr simulation:
            fires stderr event '''
    self.updateListing(data) 
    self.fire("stderr", self, data)

将方法添加到控制台实例的本地时,它仅适用于控制台命名空间。到目前为止,我在Windows上的Python 3.5上测试了这一点。编辑:奇怪的是,当使用参数时,我在控制台上的Ubuntu-Python3.4+上得到了提到的TypeError,与没有参数的窗口上的TypeError相同。在Ubuntu-Python3.5+上,TypeError不会引发。再次编辑:我的写覆盖似乎在Ubuntu-Python3.4上不起作用。那里发生了什么:S

这个列表可以让了解我们发现的解决方案

>>> class BasicTrigger(object):
    instantValue = "Local value"
    def read(self, length = 0):
        return self.instantValue+"n"
    def readline(self):
        return self.instantValue
>>> a = BasicTrigger()
>>> a.read()
'Local valuen'
>>> sys.stdin = a
>>> input()
'Local value'
>>> input('Data: ')
Data: 'Local value'

该列表是在InteractiveInterpreter实例中创建的,请考虑不要简单地用这种乐趣替换sys.stdin。io.StringIO基类没有在那里使用。"Data:"被打印(跟踪)出来了,但没有换行符,因为它无法触发BasicTrigger中的数据——在这一点上,它只是一个重定向。

无论如何,TypeError的触发真的很奇怪。感谢您的支持。

code.InteractiveConsole类的raw_input方法仅用于控制台自己的输入(例如,要运行的下一行代码)。对于您在控制台中运行的代码所请求的输入,它不会被调用。

如果你想让你的自定义代码也提供这些,你需要做更多的工作。仅在locals中提供替代inputraw_input函数将仅适用于简单的情况,其中所有输入请求代码都在交互式会话中提供。如果输入是在一个导入的模块中完成的(它仍然有正常的内置模块,而不是替换模块),它将不起作用。

相反,我建议在会话中运行代码时,用其他类似文件的对象替换sys.stdin。这里有一个快速而肮脏的实现,它用一个版本覆盖runcode方法,该版本在控制台中运行代码时交换sys.stdin,但在其余时间不交换:

class CustomInputConsole(code.InteractiveConsole):
    def __init__(self, input_file):
        code.InteractiveConsole.__init__(self) # old style class, so can't use super() here
        self.input_file = input_file
    def raw_input(self, prompt=""):
        self.write(prompt)
        line = self.input_file.readline()
        if line:
            return line.rstrip("n")
        raise EOFError()
    def runcode(self, _code):
        try:
            old_stdin = sys.stdin
            sys.stdin = self.input_file
            code.InteractiveConsole.runcode(self, _code)
        finally:
            sys.stdin = old_stdin

下面是一个快速演示,使用io.BytesIO的实例作为输入文件:

>>> con = CustomInputConsole(io.BytesIO("""input()
1+2
"""))
>>> con.interact()
Python 2.7.10 (default, May 23 2015, 09:44:00) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(CustomInputConsole)
>>> 3
>>> 

请注意,从类似文件的对象获取的输入不会被回显,如果您想要,您需要将其添加到文件对象的逻辑中。

最新更新