首页 > 解决方案 > 处理 Python 中可能同时出现的错误

问题描述

我刚开始学习 python,我想知道我的方法是否是处理可能同时出现的错误的最佳方法。

Input object is: actor = {"name": "John Cleese", "rank": "awesome"}

我定义了一个应该"X"从属性值返回单词的函数"Y"

def get_property(prop, poz):
    ln = actor[prop].split()[poz]
   return ln


#this is how I call my function
_prop = "fname"
_poz = 12

print("The actor's %s is %s" % (_prop, get_property(_prop, _poz)))

我的目标是,如果该属性不存在,则使用“名称”和/或如果该值不能拆分为与“_poz + 1”的值一样多的单词,则选择该属性值的第一个单词。

我的解决方案如下,如果有更好的方法,请告诉我。先感谢您!

# Handle all the exceptions!
#Setup
actor = {"name": "John Cleese", "rank": "awesome"}

#This function should return the "poz"th word of property "prop". If an  invalid property is passed then use "name". If an invalid index of the word in the value is passed then use return the first word. 

def get_property(prop, poz):
    ln = ""
    noerr = 0
    while noerr == 0:
        try:
            ln = actor[prop].split()[poz]
        except IndexError:
            poz = 0
        except KeyError:
            prop = "name"    
        else:
            noerr = 1
    return ln

#Test code
_prop = "fname"
_poz = 12

print("The actor's %s is %s" % (_prop, get_property(_prop, _poz)))

这些是预期的情况及其输出:

案例1:有效属性和有效词的索引

_prop = "name"
_poz = 1
get_property(_prop, _poz) = Cleese

案例2:有效属性和无效词的索引

_prop = "name"
_poz = 12
get_property(_prop, _poz) = John 

案例 3:无效属性和有效词的索引

_prop = "MIDDLEname"
_poz = 1
get_property(_prop, _poz) = Cleese

案例 4:无效的属性和无效的词索引

_prop = "b-rank"
_poz = 12
get_property(_prop, _poz) = John

标签: pythonexception

解决方案


你在做什么

“请求宽恕比请求许可更容易” EAFP

在您的代码中,您只需使用您获得的参数并希望一切正常(try)。如果不是这种情况 ( except),则相应地更改参数并再次尝试 ( while) 直到它起作用 ( else)。

所以基本上你正在做的是在之后验证你的输入。这带有很多额外的代码(try,except等)。但实际上,这是 Python 的首选编码风格

但是在您的情况下,尤其是作为初学者,您的方法有以下缺点

  • 您的代码变得更加复杂难以阅读,因为您在一个函数中使用了许多不同的技术(在一个循环 中try有多个)exceptwhile
    • 如果您可能忘记了一个案例,您将无法轻易发现!
  • 您的代码执行起来会变慢(在这种情况下您不会感觉到差异,但很高兴知道),例如:
    • 在最坏的情况下(IndexError+ KeyError)你必须通过你的while循环 3 次
  • 您的代码变得“不安全”,例如:
    • 如果actor字典被更改并且name密钥被删除会发生什么?您的代码将陷入无限循环,因为try-except构造每次都会捕获异常,而不是执行else案例。

你应该做什么

“在你跳跃之前先看看” LBYL

因此,在您的情况下,一个更好的解决方案是在您尝试使用它之前验证您的输入。

在您的情况下,您正在使用两种不同的数据结构dictlist):

  • 对于您的字典,您可以使用该get(key, default)方法安全地从字典中获取所需的值
  • len(list)对于您的拆分单词列表,您可以使用该方法检查是否有足够的单词

这些方法将帮助您完全避免异常。只需将逻辑添加到您的get_property函数中,以确保正确处理每个错误案例:

actor = {"name": "John Cleese", "rank": "awesome"}

def get_property(prob, pos, default="name"):
    values = actor.get(prob, actor[default]).split()
    return values[pos] if pos < len(values) else values[0]

test_values = [("name", 1), ("name", 12), ("MIDDLEname", 1), ("b-rank", 12)]
for prob, pos in test_values:
    print(f"{prob}, {pos} => {get_property(prob, pos)}")

这将产生输出:

name, 1 => Cleese
name, 12 => John
MIDDLEname, 1 => Cleese
b-rank, 12 => John

推荐阅读