首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >通过HTTP获取数据并缓存JSON将生成一个文件

通过HTTP获取数据并缓存JSON将生成一个文件
EN

Code Review用户
提问于 2018-07-17 16:38:22
回答 2查看 913关注 0票数 4

任务是从带有GET请求的API中获取一些JSON数据。如果由于任何原因该位置不可用,请读取缓存文件。否则,编写缓存文件以供以后使用。

以下功能可以工作,但由于以下原因,功能很笨拙:

  • 嵌套的try/except,很难读
  • 很难找出错误是什么(为了避免进一步嵌套,我同时捕获了HTTPErrorJSONDecodeError
  • 我不敢使用上下文管理器来打开文件(with),因为在try/except子句中还有一个嵌套级别

你有什么改进的想法吗?

代码语言:javascript
运行
复制
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
EN

回答 2

Code Review用户

回答已采纳

发布于 2018-07-17 16:54:00

如果您的logger对象是从logging模块派生的,那么使用logger.exception,它也会记录跟踪信息。docs (上文链接)还具体说明了这种行为:

异常信息被添加到日志记录消息中。此函数只应从异常处理程序调用。

您可以避免嵌套尝试-除了块,只需在第一个异常中使用pass,并将写缓存放在第一个try块本身中:

代码语言:javascript
运行
复制
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
票数 3
EN

Code Review用户

发布于 2018-07-19 10:00:37

有选择地处理异常

当前,您将所有异常抛出代码放入一个大型try-block中:

代码语言:javascript
运行
复制
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的不可用值可以通过装饰器的特定异常来处理。

代码语言:javascript
运行
复制
#! /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())
票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/199698

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档