为什么捕获异常会关闭打开的文件(有上下文和无上下文)?

2024-10-01 07:26:18 发布

您现在位置:Python中文网/ 问答频道 /正文

我在写一篇文章。它是两个应用程序之间的挂钩。问题是有一个应用程序已经更新,现在它使用yaml而不是json作为配置文件。你知道吗

最小示例

import os 
import yaml
import json

config = {
    'version': "2.0.2",
    'journals': {
        "default": "/test/yaml/bhla"
    },
    'editor': os.getenv('VISUAL') or os.getenv('EDITOR') or "",
    'encrypt': False,
    'template': False,
    'default_hour': 9,
    'default_minute': 0,
    'timeformat': "%Y-%m-%d %H:%M",
    'tagsymbols': '@',
    'highlight': True,
    'linewrap': 79,
    'indent_character': '|',
}
with open("jrnl.yaml", 'w') as f:
    yaml.safe_dump(config, f, encoding='utf-8', allow_unicode=True, default_flow_style=False)

这将创建一个yaml文件,您将在其中运行代码。你知道吗

问题

我首先编写了这个简单的补丁,以允许我的钩子同时使用json和yaml。你知道吗

JRNL_CONFIG_PATH = "jrnl.yaml"

with open(JRNL_CONFIG_PATH, "r") as f:
    try:
        JRNL_CONFIG = json.load(f)
    except json.JSONDecodeError:
        JRNL_CONFIG = yaml.load(f, Loader=yaml.FullLoader)
TAGS_SYMBOL = JRNL_CONFIG.get("tagsymbols", "@")

但令人惊讶的是,当捕捉到错误时,f被关闭,因为JRNL_CONFIG将返回None并产生以下错误:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-141-bc1ef847563b> in <module>()
----> 1 JRNL_CONFIG.get("tagsymbols", "@")

AttributeError: 'NoneType' object has no attribute 'get'

问题

  1. 为什么捕获异常会关闭打开的文件(有上下文和无上下文)?你知道吗
  2. 捕捉json错误并仍然能够将文件解析为yaml的最佳方法是什么?你知道吗

测试

  • 无法按名称传递文件,因为配置文件可能没有扩展名(.json.yaml
  • 这是一个工作,但它远不是优雅的。。。你知道吗
try:
    f = open(JRNL_CONFIG_PATH, "r")
    JRNL_CONFIG = json.load(f)
except json.JSONDecodeError:
    f = open(JRNL_CONFIG_PATH, "r")
    JRNL_CONFIG = yaml.load(f, Loader=yaml.FullLoader)
finally:
    f.close()

编辑1

问题1为什么捕获异常会关闭打开的文件(有上下文和无上下文)?

@jedwards

问题2捕捉json错误并仍然能够将文件解析为yaml的最佳方法是什么?

@chepner


Tags: 文件pathimportconfigjsonfalsedefaultyaml
3条回答

无需同时尝试json.loadyaml.load,因为YAML是JSON的超集,yaml.load将解析json.load可以解析的任何内容。你知道吗

JRNL_CONFIG_PATH = "jrnl.json"

with open(JRNL_CONFIG_PATH, "r") as f:
    JRNL_CONFIG = yaml.load(f, Loader=yaml.FullLoader)

TAGS_SYMBOL = JRNL_CONFIG.get("tagsymbols", "@")

问题不是文件正在关闭(不是),而是当您尝试使用回退时,文件指针不再位于预期位置(文件的开头):

with open("some.yaml") as f:
    try:
        print("before", f.tell())
        data = json.load(f)
    except json.JSONDecodeError:
        print("after", f.tell())
        print("is closed:", f.closed)

这里,^{}方法返回文件指针的位置。你知道吗

一种解决方案是重置except块内的文件指针:

with open("some.yaml") as f:
    try:
        JRNL_CONFIG = json.load(f)
    except json.JSONDecodeError:
        f.seek(0)
        JRNL_CONFIG = yaml.load(f, Loader=yaml.FullLoader)

关于:

with open(JRNL_CONFIG_PATH, "r") as f:
    data = f.read()
    try:
        JRNL_CONFIG = json.loads(data)
    except json.JSONDecodeError:
        JRNL_CONFIG = yaml.load(data, Loader=yaml.FullLoader)
TAGS_SYMBOL = JRNL_CONFIG.get("tagsymbols", "@")

相关问题 更多 >