生成函数以将python类转换为json可转储对象。

json-syntax的Python项目详细描述


json语法

在json兼容结构和本机python之间转换的python库 使用可自定义规则的类。

用例

如果你和作者一样,你试着编写一个编码函数,试图 通过在运行时查询类型进行编码和解码,可以调用 asdict。这对生成json很有用,但在尝试解码相同的json时,它会变得粗略。

此外,我们在python 3中有注释!即使你不使用类型检查器,只要 标记字段类型使复杂的数据结构更易于理解。

这个库的目标是那些具有复杂json模式的项目 使用库结构,如attrs

  • 它通过注释利用了渐进式键入的摘要" rel="nofollow">渐进式键入,输入和数据类
  • 它期望使用类型静态地描述类
    • 但是可以提供回退来处理运行时描述的数据
    • 它提供钩子规范化传统输入
  • 用自己的规则扩展库变得很简单
    • 操作和规则只是函数
    • 可以对编码器和解码器进行pickle
  • 库本身没有依赖项
    • 它实际上不读或写json

支持的类型

  • 原子包括noneboolintfloatstr
    • 浮点数可以可选地表示为字符串。
  • decimal.decimal类,表示为自身或字符串形式。
  • datetime.datedatetime.datetime类,以ISO8601形式表示。
  • 初步支持datetime.timedelta作为ISO8601时间段。
  • 枚举的子类,由字符串名称表示。
    • 另外,如果只在 代码
  • 类型。可选的[e]类型允许用jsonnull替换值。
  • 集合包括typing.list[e]typing.tuple[e,…]typing.set[e]键入.frozenset[e]
    • ..文本,表示一个同质元组,本质上是 冻结列表。
  • typing.dict[k,v]类型允许json对象表示同质的dict
    • 限制:键必须是字符串、整数、枚举或日期。
  • 使用attrs.attrsdataclasses.dataclass实现的python类是 表示为json dicts和
  • 命名元组通过typing.named tuple和异构元组通过typing.tuple
    • 不过,您应该考虑将它们转换为dataclass
  • typing.union[a,b,c]规则将通过检查识别替代类型。

此外,dataclassattrs类支持钩子,让您完全定制 它们的json表示。

用法

这个例子也在单元测试中实现。首先,让我们声明一些类。

importjson_syntaxassynfromdataclassesimportdataclass# attrs works toofromdecimalimportDecimalfromdatetimeimportdatefromenumimportEnum@dataclassclassAccount:user:strtransactions:List['Trans']# Forward references work!balance:Decimal=Decimal()classTransType(Enum):withdraw=0deposit=1@dataclassclassTrans:type:TransTypeamount:Decimalstamp:date

接下来我们将建立一个规则集并使用它来构造一个编码器。标准规则集 函数是一个单行函数,有一些合理的骑。在这里,我们决定是因为 一些中间服务不能可靠地保留十进制值,我们将 用json表示为字符串。

>>>rules=syn.std_ruleset(decimals=syn.decimals_as_str)>>>encode_account=rules.python_to_json(typ=Account)>>>decode_account=rules.json_to_python(typ=Account)

规则集检查类型和动词,搜索其规则列表,然后使用 第一个处理该类型和动词以产生动作的人。

例如,attrs_classes是一个规则,可以识别动词python_to_jsonjson_to_python并接受任何用@attr.s@dataclass修饰的类

它将扫描字段并询问规则集如何对它们进行编码。所以当它看到 account.useratoms规则将匹配并报告将astr转换为json 只需在其上调用str即可完成。它返回的动作 成为str内置组件。

因此attrs_classes将在account和要转换的操作上构建一个属性列表 它们,并构造一个动作来表示它们。

>>>sample_value=Account(...'bob',[...Trans(TransType.withdraw,Decimal('523.33'),date(2019,4,4))...],Decimal('77.00')...)>>>encode_account(sample_value){'user':'bob','transactions':[{'type':'withdraw','amount':'523.33','stamp':'2019-04-04'}],'balance':'77.00'}

编码和解码

所有这一切的目的都是为了让您的首选json库能够可靠地使用:

withopen('myfile.json','r')asfh:my_account=decode_account(json.load(fh))withopen('myfile.json','w')asfh:json.dump(encode_account(my_account))

使用泛型类型

通常,输入模块simple提供大写字母类型名称,显然 对应于内部类型。有关更详细的介绍,请参见类型

并将内容类型指定为方括号中的参数。

因此我们有:

  • 列表列表[e]
  • 设置设置[e]
  • 元组元组[e,…]是特例!
  • 冻结集冻结集[e]
  • dictdict[k,v]

元组是一个特例。在python中,它们通常用于表示"frozenlist",因此 元组[e,…](the..省略号对象)表示所有元素都具有该类型 e

它们还用于表示未命名的记录。在这种情况下,您可以使用 元组[a,b,c,d]或任何类型。通常最好使用数据类

标准规则不支持:

  1. 使用抽象类型,如iterablemapping
  2. 使用类型变量。
  3. 任何类型的可调用、协同程序、文件句柄等。
  4. < > >

    活接头

    联合类型允许您呈现转换器将尝试使用的替代类型 序列,例如typing.union[mytype,int,myenum]

    这在联合规则中实现,称为2 无差别工会。这意味着模块不会向 值,例如某种显式标记。

    从python转换为json时,检查通常只使用isinstance, 但是当从json转换为python时,检查可能是检查字符串和dict。 字段.

    因此,不明确的值,特别是json表示,可能会混淆解码器。 有关详细信息,请参阅锐边部分。

    挂钩

    我们将首先检查解码和编码挂钩。这些让我们完全重写json 应用常规逻辑之前的表示。

    假设我们的帐户类用于命名余额字段余额,我们需要 支持传统用户。

    @dataclassclassAccount:@classmethoddef__json_pre_decode__(cls,value):if'bal'invalue:value=dict(value)value['balance']=value.pop('bal')returnvaluedef__json_post_encode__(self,value):returndict(value,bal=value['balance'])...

    解码该值时,将执行以下步骤:

    1. <代码>\uu js用{user':'bob','bal':'77.0',…}调用on廑u pre廑u decode廑 返回{user':'bob','balance':'77.0',…}
    2. 解码器针对userbalance和其他字段调用
    3. 生成的字典被传递到帐户(**result)以构造实例。
    4. < > >

      在编码过程中,会发生相反的顺序:

      1. 实例的字段被读取并传递给编码器。
      2. 这些值组合成一个dict
      3. {user':'bob','balance':'77.0',…}和 可以将字段名调整为bal
      4. < > >

        json类型检查挂钩

        类型检查只在json语法中使用,以支持类型union;简而言之, 联合规则将检查某些json,以查看存在哪个变体。

        如果未定义类型检查挂钩,则在 标准检查完成。(标准检查试图确定是否需要 字段存在并具有正确的类型。)

        如果您掌握的信息可以更快地确定类型,则勾选功能会有所帮助。

        回到我们的帐户示例,假设我们决定支持多个帐户类型 通过一个特殊的字段。这是更快和更强大的。

        classAbstractAccount:@classmethoddef__json_check__(cls,value):returnisinstance(value,dict)andvalue.get('class')==cls.__name__@dataclassclassAccountA(AbstractAccount):...encode_account=rules.lookup(typ=Union[AccountA,AccountB,AccountC],verb='python_to_json')

        添加自定义规则

        有关自定义规则的详细信息,请参见示例,但通常规则只是 功能。比如说,你的类型有类方法来编码和解码,这个 在许多情况下就足够了:

        defmy_rule(verb,typ,ctx):ifissubclass(typ,MyType):ifverb=='json_to_python':returntyp.decoderelifverb=='python_to_json':returntyp.encoder

        如果您的规则需要标准类型的编码器或解码器,它可以调用 ctx.lookup(动词=动词,类型=子类型)。json syntax.action v1中定义的helper函数 旨在保持不变,以便自定义规则可以重用它们。

        调试复杂结构

        (可能需要更多文档和一些测试用例。)

        由于json语法试图将python类型直接转换为json,因此 写出模棱两可的结构。为了避免这种情况,有一个方便的is廑u digulary方法:

        # This is true because both are represented as an array of numbers in JSON.rules.is_ambiguous(typ=Union[List[int],Set[int]])@dataclassclassAccount:user:straddress:str# This is true because such a dictionary would always match the contents of the account.rules.is_ambiguous(typ=Union[Dict[str,str],Account])

        这样做的目的是让您检查单元测试,以确保数据可以 根据您的具体情况可靠地表达出来。

        在内部,它使用模式动词来表示json模式,因此 有助于理解json语法如何表示数据:

        print(rules.lookup(typ=MyAmbiguousClass,verb='show_pattern'))

        锐边

        规则集缓存编码器。如果要更改设置,请构造新的规则集。

        编码器和解码器很少检查。尤其是在翻译时 从python到json,假设python类是正确的。编码器和 解码器在调用构造函数如strint时可能会掩盖一些细微的问题。 为你。而且,根据设计,如果要从json转换为python,则假定 希望能够容忍额外的数据。

        所有与打字有关的东西。它有点神奇,有点不是为这个而设计的。 我们有一个指南,可以尝试帮助您

        联合类型。您可以使用typing.union允许成员成为 但也有一些注意事项。您应该使用 规则集警告您这些。

        原子规则接受特定类型。目前,原子类型的规则(intstrbooldatefloatdecimal)必须声明为这些类型。用 多重继承,不清楚应适用规则

        检查比转换器更严格。例如,检查int将检查 该值是一个整数,而转换器只需对其调用int。因此 输入wheremytype将通过,但union[mytype,dummy]将失败。(音符 可选的是要查找的特殊情况,不存在此问题。

        数字是硬的。请参阅名为floatsfloats\u nan_strdecimals的规则, decimals_as_str了解有关如何使数字可靠传输的详细信息。没有规则 分数或复数,因为没有通过json传输它们的规范方法。

        维护

        这个包是通过诗歌工具来维护的。一些有用的命令:

        1. 设置:诗歌安装
        2. 运行测试:诗歌运行pytest测试/
        3. 重新格式化:诗歌运行黑色json语法/tests/
        4. < > >

          设置毒性

          您需要pyenv,然后安装pythons:

          importjson_syntaxassynfromdataclassesimportdataclass# attrs works toofromdecimalimportDecimalfromdatetimeimportdatefromenumimportEnum@dataclassclassAccount:user:strtransactions:List['Trans']# Forward references work!balance:Decimal=Decimal()classTransType(Enum):withdraw=0deposit=1@dataclassclassTrans:type:TransTypeamount:Decimalstamp:date
          0

          一旦在首选的python中安装了tox,运行它就是tox

          (注意:poetry install现在正在插入tox,因为pip已经更改:现在 每次尝试在pip wheel metadata中创建dist。我在查那个目录,但是 很有可能有一些新的配置变量要搜索。)

          注释

          1:编写编码器似乎很容易,因为 python有完整的信息。标准的json模块提供了一个钩子 您对一个对象进行编码,并使用另一个钩子来识别具有特殊 属性。这可以很好地工作,但是您必须对所有非json类型进行编码。 使用dict包装器使进程反向工作。

          2:有区别的联合有一个标识变量的标记,例如 指示成功和有效负载或某个错误的状态代码。严格来说,所有工会 如果执行不同的代码路径,则必须以某种方式进行区分。在联合中 规则,判别式是python中的类信息,以及json的结构。 数据。一个不那么讨人喜欢的描述是,这是一个"差"的歧视 联合。

          欢迎加入QQ群-->: 979659372 Python中文网_新手群

          推荐PyPI第三方库


热门话题
添加组件后,java JTable为空   java将json发送到php并插入mysql,但返回null   java Spring引导JNDI CommonJ资源   从不同PC创建和合并后的Java servlet问题   java如何在使用findelements时从xpath获取文本   java使用spring boot使用gmail smtp发送电子邮件   java在不使用pojo、bean或getter和setter的情况下获取Json标题的Json数组   Java中的OpenFile对话框将null作为响应   JavaBuilder模式。扩展接口   java中无需替换的数据结构选取   java如何评价Encog中的预测神经网络   java如何在安卓中使用实际的HttpURLConnection进行单元测试?   java使用XML配置禁用WebSocket中的CSRF保护   java如何通过hibernate从多表查询中获取数据?   mysql如何在java中获取更新的行Id   java AEM/CQ组件单一组件/有限组件   java FFmpeg Javacv延迟问题   显示整数数组的java不起作用