InteractiveConsole.raw_input覆盖不起作用

时间:2015-12-17 01:04:52

标签: python

当使用code.InteractiveConsole作为基类时,使用raw_input的覆盖并且只写入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,并且与没有参数的Windows上相同。在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 value\n'
>>> sys.stdin = a
>>> input()
'Local value'
>>> input('Data: ')
Data: 'Local value'

列表是在InteractiveInterpreter个实例中创建的,不仅仅是考虑用这样的乐趣替换sys.stdin。 那里没有使用io.StringIO基类。并且'数据:'被打印(跟踪)但没有换行,因为它无法触发BasicTrigger的数据 - 此时它只是一个重定向。

无论如何,该类型错误的触发真的很奇怪。感谢您的支持。

1 个答案:

答案 0 :(得分:0)

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

如果您希望自定义代码也提供,那么您需要做更多工作。仅在input中提供替换raw_inputlocals函数仅适用于简单情况,其中所有输入请求代码都在交互式会话中提供。如果输入是在导入的模块中完成的(它仍然具有普通的内置而不是替换),它将无法工作。

相反,当您在会话中运行代码时,我建议将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
>>> 

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