简体   繁体   中英

Stop Python script from shutting down on small errors

I have a Python socket server. In this socket server, when a new client connects and successfully authenticates themselves, it'll grab their json encoded information from the database. When it decodes it, it goes to a variable. Sometimes in the object, a key doesn't exist. I'll get a KeyError and the whole script will shut down. For example:

A client sends a packet to the server The server handles it like this:

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

If "exampleKey" doesn't exist in the user's info (hey, it happens, like if I added a new key to the info for a new packet to handle something else and the user's info hasn't been updated yet), the whole script shuts down. I know I could easily do try, except but I often call keys throughout the script and I think it would look messy having a bunch of try and excepts everywhere, don't you think? Is there an easier way to just make it so Python gives off a warning about it but doesn't shut down, similar to how PHP does it?

Also, the client is a seperate class.

Use exception handling; to catch the exceptions; they exist for the sole reason that the normal program would be simpler, without a need for constant error checking. Also to get an optional key from dictionary you can use the get method

def handleReceiveThisPacket(self, data):
    # returns None if key not found
    myInfo = self.info.get('exampleKey')

    # returns 42 if key not found
    myInfo = self.info.get('exampleKey', 42)

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

You can create your own MyDict class that wraps the KeyError and logs out warnings:

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

In [33]: d = MyDict()

In [34]: d['test']
Attempted to get value for missing key test.

Or in short (just for default values):

from collections import defaultdict

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

None

This example returns None as default value for missing keys, but you can customize it.

First of all, the PHP language made many bad design decisions, this is just one of them. Be happy that python detects and handles these problems in a nice way. I personally always wrote PHP code that never created any warnings. Once you have warnings it's hard to distinguish what's acceptable and what's a real problem.

Second, you can handle the problem several ways:

  • You can handle these exceptions in an upper layer (1 or 2, instead of a dozen)
  • You can use a defaultdict .
  • You can use a utility function.

Example:

def getkey(d, k):
  try:
    return d[k]
  except KeyError:
    return ""

Note that all these solution have the serious flaw that they make your code brittle. You won't detect all the possible typos you can make for the keys.

I think the most clear way would be to fill your data set with values for the missing keys, so you don't have to do any error handling.

You may check if something is in a collection using the in operator:

>>> 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

Also, dict s have a .get(key, default=None) method .

Catch the exception. This link explains exception handling in Python. Put a try... except KeyError... around the relevant code.

Alternatively, use the dictionary method get. myInfo = self.info.get('exampleKey', default_value) won't raise a KeyError, and will return default_value if 'exampleKey' isn't in myInfo.

A third option would be to check if the key is in the dictionary first: if 'exampleKey' in self.info: myInfo = self.info['exampleKey'] .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM