Python脚本遇到小错误时不会停止运行

69 阅读3分钟

在使用Python socket服务器时,有时会出现以下情况:当一个新的客户端连接并成功通过认证后,服务器会从数据库中获取其json编码的信息。在解码过程中,将信息存储到一个变量中。有时,对象中可能不存在某个键,这会导致出现KeyError异常,并导致整个脚本关闭。

例如,客户端向服务器发送数据包,服务器会以如下方式处理:

def handleReceiveThisPacket(self, data):
    myInfo = self.info['exampleKey']
    return self.send(myInfo)

如果"exampleKey"在用户的的信息中不存在(这种情况可能会发生,例如,当为新数据包添加了一个新键来处理其他内容,而用户的的信息尚未更新时),则整个脚本将关闭。虽然可以使用try、except语句来捕获异常,但在脚本中经常调用键,这样做会导致代码杂乱,到时就会有许多try和except语句。因此,有没有一种更简单的方法,让Python发出警告而不会关闭脚本,类似于PHP的处理方式? 而且,客户端是一个单独的类。

2、解决方案

方法一:使用异常处理

使用异常处理来捕获异常;为了让常规程序更简单,不需要经常检查错误,因此异常处理才存在。此外,可以使用get方法从字典中获取可选键。

def handleReceiveThisPacket(self, data):
    # 如果未找到键,则返回None
    myInfo = self.info.get('exampleKey')

    # 如果未找到键,则返回42
    myInfo = self.info.get('exampleKey', 42)

    try:
        return self.send(myInfo)
    except Exception as e:
        print("Oops an exception occurred")
        print(e)

方法二:创建自定义字典类

可以创建自己的MyDict类,该类包装KeyError并记录警告:

import logging

log = logging.getLogger(__name__)

class MyDict(dict):
    def __getitem__(self, key):
        try:
            return super(MyDict, self).__getitem__(key)
        except KeyError:
            log.warning('Attempted to get value for missing key %s.', str(key))
            return None

d = MyDict()
d['test']
# 输出 Attempted to get value for missing key test.

或者简单地说(仅针对默认值):

from collections import defaultdict

c = defaultdict(lambda: None)
c['test']
# 输出 None

此示例返回None作为缺失键的默认值,但可以自定义它。

方法三:在更高层次处理异常

首先,PHP语言做出了许多错误的设计决策,这只是其中之一。要为Python能够以一种好的方式检测并处理这些问题而感到高兴。通常写PHP代码时,从不创建任何警告。一旦有警告,就很难区分什么是可以接受的,什么是真正的错误。

其次,可以通过多种方式处理此问题:

  • 可以在更高层次(1或2而不是12)处理这些异常。
  • 可以使用defaultdict。
  • 可以使用实用函数。
def getkey(d, k):
    try:
        return d[k]
    except KeyError:
        return ""

请注意,所有这些解决方案都有一个严重缺陷,那就是它们会使代码变得脆弱。无法检测到键的所有可能错别字。认为最清晰的方法是使用值填充数据集以替换缺少的键,这样就无需进行任何错误处理。

方法四:使用in操作符检查集合中是否存在元素

可以使用in操作符检查集合中是否存在某个元素:

import json
o = json.loads('{"a": 1}')
"a" in o  # 输出 True
"b" in o  # 输出 False

o = dict(a=1)
"a" in o  # 输出 True
"b" in o  # 输出 False

o = (1,2,3)
1 in o  # 输出 True
4 in o  # 输出 False

此外,字典有一个.get(key, default=None)方法。