【问题标题】:Program does not accept argument Python程序不接受参数 Python
【发布时间】:2015-10-31 01:48:36
【问题描述】:

我正在创建一个接受算术表达式并首先将运算符推送到 stacl 的后缀计算器。

./pythonfilename 3 4 1 + - 用作我的输入。但是,由于没有显示输出,我尝试调试我的程序以查看为什么我的程序没有接受我的参数。 不会导致打印任何输出。我按 Ctrl+C 显示 Traceback Call,它指出 x = sys.stdin.readlines。

#!/usr/bin/python

import sys
import fileinput

class Stack:
    def __init__(self):
        self.items = []

    def isEmpty(self):
        return self.items == []

    def push(self,item):
        self.items.append(item)

    def pop(self):
        return self.items(pop)

    def peek(self):
        return self.items[len(self.items)-1]

    def size(self):
        return len(self.items)

    def is_number(line):
        try:
            float(line)
        except ValueError:
            return False        

def infixtoPostfix():
    initStack=Stack()
    x = sys.stdin.readlines() #read user input 
    for lines in x:#for lines in fileinput.input():
        for line in lines.strip().split(" "):
            if is_number(line):
                initStack.push(line)
                line = float(line)
            elif line =='+':
                firstNum = initStack.pop()
                secNum = initStack.pop()
                result = firstNum + secNum
                initStack.push(result)
                print initStack.peek()              

            elif line == '-':
                firstNum = initStack.pop()
                secNum = initStack.pop()
                result = firstNum - secNum
                initStack.push(result)
                print initStack.peek()

            elif line == '*':
                firstNum = initStack.pop()
                secNum = initStack.pop()
                result = firstNum * secNum
                initStack.push(result)
                print initStack.peek()
            elif line == "/":
                firstNum = initStack.pop()
                secNum = initStack.pop()
                result = firstNum / secNum
                initStack.push(result)
                print initStack.peek()
            elif line == "%":
                firstNum = initStack.pop()
                secNum = initStack.pop()
                result = firstNum % secNum
                initStack.push(result)
                print initStack.peek()

infixtoPostfix()

【问题讨论】:

    标签: python stdin postfix-notation


    【解决方案1】:

    从管道 (cat ... | python myprog.py) 读取的标准方法是

    import sys
    
    for line in sys.stdin:
        print ">", line
    

    line 将在此处包含最终的'\n'

    如果您想在命令行上接受参数 (python myprog.py 3 4 1 + -),您可以使用 sys.argv[1:]sys.argv[0] 包含 myprog.py)。

    要获得一致的输入词法分析,您需要首先检查sys.argv,然后拆分sys.stdin

    def lex_input():
        "Returns a list of tokens."
        tokens = []
        if len(sys.argv) > 1:
            tokens = sys.argv[1:]
        else:
            for line in sys.stdin:
                tokens += line.split()
        return tokens
    

    那么您只需更改您的 infixPostfix() 函数以使用此令牌数组(而不是在同一个函数中同时进行解析和评估)。

    ps:写单个子句的更简洁的方式是:

    elif token == '+':
        push(pop() + pop())
    

    但这取决于您要完成的工作..

    更新:完整的解决方案

    更新 2: 使用调试语句来可视化堆栈(为简洁起见,删除了 Stack 类以支持常规列表)

    import sys
    
    STACK = []
    push = STACK.append
    pop = STACK.pop
    
    OPERATIONS = {
        '+': lambda b, a: a + b,
        '-': lambda b, a: a - b,
        '*': lambda b, a: b * a,
        '/': lambda b, a: b / a,
    }
    
    def infixtoPostfix(tokens):
        print '%-15s %5s %-15s' % ('STACK before', 'token', 'STACK after')
        print '-'*15, '-'*5, '-'*15
    
        for token in tokens:
            print '%15s %5r' % (STACK, token),
    
            if token not in OPERATIONS:
                push(int(token))
            else:
                push(OPERATIONS[token](pop(), pop()))
    
            print '%15s' % STACK
    
    def lex_input():
        "Returns a list of tokens."
        tokens = []
        if len(sys.argv) > 1:
            tokens = sys.argv[1:]
        else:
            for line in sys.stdin:
                tokens += line.split()
        return tokens
    
    if __name__ == "__main__":
        infixtoPostfix(lex_input())
        # well formed programs should leave a single value on the STACK
        print "\nResult is:", STACK[0]
    

    测试:

    (dev) go|c:\srv> python rpn.py 3 4 1 + -
    STACK before    token STACK after
    --------------- ----- ---------------
                 []   '3'             [3]
                [3]   '4'          [3, 4]
             [3, 4]   '1'       [3, 4, 1]
          [3, 4, 1]   '+'          [3, 5]
             [3, 5]   '-'            [-2]
    
    Result is: -2
    

    (如果rpn.txt 包含3 4 1 + -cat rpn.txt | python rpn.py 将输出相同的内容)。

    如果你尝试一个语法错误的rpn程序,那么程序会抛出一个异常,例如:

    (dev) go|c:\srv> python rpn.py 3 4 + -
    STACK before    token STACK after
    --------------- ----- ---------------
                 []   '3'             [3]
                [3]   '4'          [3, 4]
             [3, 4]   '+'             [7]
                [7]   '-'
    Traceback (most recent call last):
      File "rpn.py", line 60, in <module>
        infixtoPostfix(lex_input())
      File "rpn.py", line 45, in infixtoPostfix
        push(OPERATIONS[token](pop(), pop()))
      File "rpn.py", line 26, in pop
        return STACK.pop()
    IndexError: pop from empty list
    

    在真正的编译器中会很糟糕,因为您不希望最终用户看到您的实现细节。相反,您希望向他们提供诊断错误消息,以及您的程序找到它的确切位置。

    在这种情况下,这并不难。我省略了打印堆栈的调试语句:

    def infixtoPostfix(tokens):
        # make a copy of the input, for use in error handling
        input_tokens = tokens[:]  
        try:
            for i, token in enumerate(tokens):
                if token not in OPERATIONS:
                    push(int(token))
                else:
                    push(OPERATIONS[token](pop(), pop()))
        except IndexError:
            print 'Detected Syntax Error at token no.:', i + 1  # people count from 1..
            print ' '.join(input_tokens)
            print '%s%s' % ('-' * (1 + len(' '.join(input_tokens[:i]))), '^')
            push('SYNTAX ERROR')  # the top of the stack contains the result of the current operation..
    

    需要对结果打印进行小改动,打印列表中的最后一个元素 (STACK[-1]),它是堆栈的顶部,而不是依赖于列表/堆栈末尾只有一个元素:

    if __name__ == "__main__":
        infixtoPostfix(lex_input())
        # well formed programs should leave a single value on the STACK
        print "\nResult is:", STACK[-1]
    

    如果我们为这个版本的程序提供语法错误:

    (dev) go|c:\srv> python rpn.py 34 4 + -
    Detected Syntax Error at token no.: 4
    34 4 + -
    -------^
    
    Result is: SYNTAX ERROR
    

    我们会收到一条正确的错误消息,并带有一个尖尖的“图形”,指示检测到错误的位置。

    我们可以走得更远,因为我们知道我们所有的操作都需要堆栈上的两个元素,并给出更详细的错误消息,例如:

    Syntax Error at token "-":  Stack underflow
       The "-" operation requires two stack arguments and the stack 
       contained only one:
    
            Stack      token
            ---------- -----
            [37]        '-'
    

    我将把它的实现留作练习。

    如您所见,即使在这个简单的示例中,错误处理代码也多于评估代码,这在编写简单的编译器时并不令人惊讶。

    【讨论】:

    • 在我第一次测试 cat test.txt 时,我还没有做出您建议的更改 | python something.py,我收到一个错误说 pop 没有定义。
    • 回溯(最近一次调用最后一次):-bash:意外标记附近的语法错误most' File "something.py", line 75, in &lt;module&gt; -bash: syntax error near unexpected token newline' s$ infixtoPostfix() > 文件“something.py”,第 43 行,infixtoPostfix -bash:意外标记File' firstNum = initStack.pop() -bash: syntax error near unexpected token (' File "something.py", line 17, in pop 附近出现语法错误
    • ps 可能有点太抽象了。它的意思是:“如果你将 push 和 pop 定义为简单的函数(因为你只使用一个堆栈),那么你可以简化评估”。这只是您关于标记化问题的一个旁白。
    • 看起来我们在不同层次上进行交流,所以我根据我的 cmets 用完整的解决方案更新了我的答案。 (我还使 Stack 成为 list 的子类,因为 list 的大部分功能都是共享/相似的)。
    • 不错的解决方案比约恩。但是,我仍然想修复我的代码。我设法通过在第 17 行将 self.items.(pop) 更改为 self.items.pop() 来修复全局名称 pop 的错误。但是,当我运行我的代码时,我最终得到了一个不同的 pop 错误Indexerror:从空列表中弹出。知道我在这里可能做错了什么吗?
    【解决方案2】:

    ./pythonfilename 3 4 1 + -

    实际上 3 4 1 + - 作为参数而不是作为输入传递。

    如果你想从文件中读取,请使用 open('filename')

    使用 ./pythonfilename '3 4 1 + -'

    x = [sys.argv[1]]

    代替 x = sys.stdin.readlines()

    但是你的代码只处理单个输入作为参数

    【讨论】:

    • 我很抱歉。这是传递参数的正确方法吗?我实际上是在尝试使用 cat 传递参数
    • 为什么不将输入文件作为程序参数传递? ./pythonfilename 文件名 .这是最常见的约定。
    • 是的,我希望两者兼得。如果未传递文件名,则显示读取控制台中传递的参数
    • 所以使用 ./pythonfilename '3 4 1 + -' x = [sys.argv[1]] 代替 x = sys.stdin.readlines() 但是你的代码只处理单个输入作为论据
    猜你喜欢
    • 2017-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-10
    • 1970-01-01
    • 2012-10-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多