使用try ... except处理变长命令元组

时间:2013-11-02 20:39:40

标签: python python-3.x exception-handling

我正在编写一个Python 3脚本,用于制作林业木材计数表。

工人们将向计算机操作员标记每棵树的日志中的物种,直径和高度。然后,计算机操作员将输入如下命令:

OAK 14 2

表示该程序应该增加直径为14英寸,高度为2个对数的橡树的数量。

但是,工人有时也会同时调用多个相同类型的树。所以程序也必须能够处理这个命令:

OAK 16 1 2

这意味着我们将计数增加了两倍。

我设置解析器的方式是:

key=cmdtup[0]+"_"+cmdtup[1]+"_"+cmdtup[2]
        try:
            trees[key]=int(trees[key])+int(cmdtup[3])
        except KeyError:
            trees[key]=int(cmdtup[3])
        except IndexError:
            trees[key]=int(trees[key])+1

如果程序被命令存储它之前没有存储的树,则KeyError将关闭,并且处理程序将设置dict条目而不是增加它。如果省略第三个参数,则会引发IndexError,并且处理程序会将其视为第三个参数为1。

但是,如果我们同时处于这两种情况,就会出现问题;程序还没有听说过橡树,操作员没有指定计数。 KeyError关闭,但随后生成了自己的IndexError,并且当异常处理程序中发生异常时,Python不喜欢它。

我认为最简单的方法是简单地删除一个或另一个,并以其他方式完成其功能。不过,我想知道是否有更优雅的Pythonic方法。有吗?

3 个答案:

答案 0 :(得分:0)

我会做这样的事情:

def parse(cmd, trees):
    res = cmd.split() # split the string by spaces, yielding a list of strings
    if len(res) == 3: # if we got 3 parameters, set the fourth to 1
        res.append(1)
    for i in range(1,4): # convert parameters 1-3 to integers
        res[i] = int(res[i])
    key = tuple(res[x] for x in range(3)) # convert list to tuple, as lists cannot be dictionary indexes
    trees[key] = trees.get(key,0) + res[3] # increase the number of entries, creating it if needed

trees={}

# test data
parse("OAK 14 2", trees)
parse("OAK 16 1 2", trees)
parse("OAK 14 2", trees)
parse("OAK 14 2", trees)

# print result
for tree in trees:
    print(tree, "=", trees[tree])

产生

('OAK', 16, 1) = 2
('OAK', 14, 2) = 3

一些注意事项:

  • 这里没有错误处理,你应该处理当一个数字值不是或者输入错误的情况时
  • 而不是字符串,我使用元组作为字典索引

答案 1 :(得分:0)

如果密钥不在字典中,您可以使用collections.Counter,它返回0而不是KeyError

<强> Counter Documentation:

  

Counter个对象有一个字典界面,除了它们为丢失的项目返回零计数而不是提出KeyError

这样的事情:

from collections import Counter

counts = Counter()

def update_counts(counts, cmd):
    cmd_list = cmd.split()
    if len(cmd_list) == 3:
        tree = tuple(cmd_list)
        n = 1
    else:
       *tree, n = tuple(cmd_list)
    counts[tree] += n

同样的说明适用于uselpa的答案。 Counter的另一个好处是,如果您想要查看每周计数,您只需执行sum(daily_counts)之类的操作。

如果您从命令列表开始,

Counter的效果会更好:

from collections import Counter
from itertools import repeat

raw_commands = get_commands() # perhaps read a file
command_lists = [c.split() for c in raw_commands]

counts = Counter(parse(command_lists))

def parse(commands):
    for c in commands:
        if len(c) == 3:
            yield tuple(c)
        elif len(c) == 4
            yield from repeat(tuple(c[0:2]), times=c[3])

从那里你可以使用上面的update_counts函数添加新树,或者你可以开始在另一个文本文件中收集命令,然后在第二天生成第二个Counter对象,下一个一周等等。

答案 2 :(得分:0)

最后,最好的方法是简单地删除IndexError处理程序,将cmdtup更改为列表,然后插入以下内容:

if len(cmdtup) >= 3:
    cmdtup.append(1)