任务是从带有GET请求的API中获取一些JSON数据。如果由于任何原因该位置不可用,请读取缓存文件。否则,编写缓存文件以供以后使用。
以下功能可以工作,但由于以下原因,功能很笨拙:
try/except,很难读HTTPError和JSONDecodeErrorwith),因为在try/except子句中还有一个嵌套级别你有什么改进的想法吗?
def fetch_list(location=MY_LOCATION, cache_file=CACHE_FILE):
"""Goes to the default location and returns
a python list
"""
http = urllib3.PoolManager()
try:
r = http.request("GET",
location)
raw_data = r.data.decode("utf-8")
data = json.loads(raw_data)
except (urllib3.exceptions.HTTPError, JSONDecodeError):
logger.error("Cannot access Intranet List Location - fetching cache")
try:
data = json.loads(open(cache_file).readlines())
except (IOError, JSONDecodeError):
logger.error("Cache File not found or broken")
raise
else:
with open(cache_file, "w") as f:
f.write(raw_data)
return data发布于 2018-07-17 16:54:00
如果您的logger对象是从logging模块派生的,那么使用logger.exception,它也会记录跟踪信息。docs (上文链接)还具体说明了这种行为:
异常信息被添加到日志记录消息中。此函数只应从异常处理程序调用。
您可以避免嵌套尝试-除了块,只需在第一个异常中使用pass,并将写缓存放在第一个try块本身中:
def fetch_list(location=MY_LOCATION, cache_file=CACHE_FILE):
"""Goes to the default location and returns a python list.
"""
try:
http = urllib3.PoolManager()
request = http.request("GET", location)
raw_data = request.data.decode("utf-8")
data = json.loads(raw_data)
with open(cache_file, "w") as cache:
cache.write(raw_data)
return data
except (urllib3.exceptions.HTTPError, JSONDecodeError) as exc:
logger.exception("Cannot access Intranet List Location - fetching cache")
try:
data = json.loads(open(cache_file).readlines())
return data
except (IOError, JSONDecodeError):
logger.exception("Cache File not found or broken")
raise发布于 2018-07-19 10:00:37
当前,您将所有异常抛出代码放入一个大型try-block中:
try:
r = http.request("GET",
location)
raw_data = r.data.decode("utf-8")
data = json.loads(raw_data)
except (urllib3.exceptions.HTTPError, JSONDecodeError):乍一看,它是不可见的,可能有一个UnicodeDecodeError,您没有捕捉到它(故意?)。一次处理一个语句的可能异常可能会增加可读性。
从Web检索数据和缓存数据对我来说似乎是两个不同的问题,应该由不同的函数来处理。在这里,装饰师可能是一个合适的解决方案。
处理
因此,来自Web的不可用值可以通过装饰器的特定异常来处理。
#! /usr/bin/env python3
from functools import wraps
from json import JSONDecodeError, dump, load, loads
from logging import getLogger
from urllib3 import PoolManager
from urllib3.exceptions import HTTPError
LOCATION = 'http://ip.jsontest.com/'
CACHE = '/home/neumann/cache.json'
LOGGER = getLogger('MyLogger')
class DataNotRetrievable(Exception):
"""Indicates that the required data was not retrievable
from the endpoint and a cached value is required.
"""
pass
def json_cache(filename):
"""Chaches return value of the wrapped funtion to the respective file."""
def decorator(function):
"""Actual decorator."""
@wraps(function)
def wrapper(*args, **kwargs):
"""Wraps the decorated function."""
try:
json = function(*args, **kwargs)
except DataNotRetrievable:
LOGGER.exception('Could not retrieve data from website.')
with open(filename, 'r') as cache:
return load(cache)
with open(filename, 'w') as cache:
dump(json, cache)
return json
return wrapper
return decorator
@json_cache(CACHE)
def fetch_list(location=LOCATION):
"""Goes to the default location and returns a python list."""
pmgr = PoolManager()
try:
response = pmgr.request("GET", location)
except HTTPError:
raise DataNotRetrievable()
try:
text = response.data.decode()
except UnicodeDecodeError:
raise DataNotRetrievable()
try:
return loads(text)
except JSONDecodeError:
raise DataNotRetrievable()
if __name__ == '__main__':
print(fetch_list())https://codereview.stackexchange.com/questions/199698
复制相似问题