使用__missing__方法实现映射表多格式主键

背景介绍

在python中,我们经常使用字典类型实现映射表的功能,通过字典的主键遍历获取对应的值,从而实现从一个值映射到另一个值的功能

但是这种映射是十分硬性的,例如,假如我的映射表为{‘1’:one,‘2’:two},这是一个阿拉伯数字对应映射成英语的过程,在查找映射表的过程中,我的主键输入‘1’可以得到值one,但如果我输入的是1(即并不是加上引号的字符串类型而是数值类型),python的字典类型就会抛出主键错误的提示,因为在原字典中,‘1’是作为字符串类型的主键,1是作为整形类型的数据,两者在计算机中的储存格式是不相同的

如果我们希望得到一张映射表,既可以通过字符串类型遍历取值,也能通过对应的数值类型取值,那么应该如何实现呢?__missing__可以提供解决方案

__missing__方法

对于python中的dict类型,当我们需要通过主键获取对应的值时,k是主键,dict是字典类型,可以有dict[k]或者dict.get(k),都是调用字典类型中的__getitem__方法,遍历查找字典中对指定主键所对应的值,当没有找到主键时,则返回KeyError

另一种情况是,当__missing__方法存在时,就会调用__missing__方法中设定的操作,例如defaultdict类就是这种运行原理如何统计csv文件中对象的数量(基于pandas)-优快云博客可以事先对不存在的字典主键赋予默认值,给在运行的过程带来方便

任务设定

为了让大家更好地理解__missing__方法,我们来简单设定一个任务,建立映射表{1:'one',2:'two',3:'three'},在建立映射的过程中,既可以使用1作为主键获取对应的值,也可以通过对应的字符串‘1’获取相应的值

代码实现

我们通过自定义类来实现,需要继承dict的类型

我们先来看看没有加__missing__方法的继承:

class UsualDict(dict):
    def get(self,key,default=None):
        try:
            return self[key]
        except KeyError:
            return default

其中,get()函数就是调用__getitem__方法获取主键对应的值

dd=UsualDict({1:'one',2:'two',3:'three'})
print(dd[1])

输出>>one
print(dd['1'])

输出>>KeyError: '1'

可见没有实现任务的要求,我们再来使用__missing__方法:

class UsualDict(dict):

    def __missing__(self,key):
        return self[int(key)]

    def get(self,key,default=None):
        try:
            return self[key]
        except KeyError:
            return default
print(dd['1'])

输出>>one

任务好像可以完成了

但是却有一个隐藏的漏洞

print(dd[5])
Traceback (most recent call last):
  File "d:\py-code\fluent_pyhton\1_24.py", line 33, in <module>
    print(dd[5])
  File "d:\py-code\fluent_pyhton\1_24.py", line 25, in __missing__
    return self[int(key)]
  File "d:\py-code\fluent_pyhton\1_24.py", line 25, in __missing__
    return self[int(key)]
  File "d:\py-code\fluent_pyhton\1_24.py", line 25, in __missing__
    return self[int(key)]
  [Previous line repeated 496 more times]
RecursionError: maximum recursion depth exceeded

错误提示语说递归的层级已经超过了最大的允许范围,这是为什么呢?

我们回到代码,具体看这一句

    def __missing__(self,key):
        return self[int(key)]

只要__getitem__方法没有得到主键的内容我们就调用__missing__方法,调用__missing__方法后的self[int(key)]又会调用__getitem__方法,那么只要key的int类型或者str类型都不存在于字典的主键中,那么两个方法之间就会无限进行递归调用,那么这个bug需要如何解决呢?

可以有以下继承方法:

class UsualDict(dict):

    def __missing__(self,key):
        if isinstance(key,int):
            raise KeyError(key)
        return self[int(key)]

    def get(self,key,default=None):
        try:
            return self[key]
        except KeyError:
            return default

通过isinstance方法判断key的类型是否属于int,即当__getitem__方法找不到主键调用__missing__方法时,首先判断key是否属于int,若属于int类型但又在字典主键中查找不到对应的值,则返回错误,否则,才进行key类型的转换

我们来看看是否还会出现递归的错误

dd=UsualDict({1:'one',2:'two',3:'three'})
print(dd[5])

系统进行了正确的错误输出 

Traceback (most recent call last):
  File "d:\py-code\fluent_pyhton\1_24.py", line 33, in <module>
    print(dd[5])
  File "d:\py-code\fluent_pyhton\1_24.py", line 24, in __missing__
    raise KeyError(key)
KeyError: 5

欢迎大家讨论交流~


从错误信息来看,Spring Boot 应用程序启动失败的原因在于 `EntityManagerFactory` 的创建过程中出现了问题。以下是分析和解决方案: --- ### 错误原因分析 1. **核心异常** 核心问题是 `Schema-validation: missing table [sys_authority]`,这表明 Hibernate 进行数据库表结构校验 (`schema validation`) 时发现缺少名为 `sys_authority` 的表。 2. **可能导致此问题的因素** - 数据库中确实不存在该表。 - 配置文件中的 `spring.jpa.hibernate.ddl-auto` 设置不正确。 如果设置为 `validate` 或者未配置,默认会启用 schema 校验模式。 - Spring Boot 没有成功生成所需的实体表(例如因为某些 SQL 执行失败)。 - 实体类映射有问题,导致 Hibernate 认为其需要对应的物理表却未能找到。 --- ### 解决方案 #### 方案一:检查并调整 `ddl-auto` 修改应用程序的配置文件(如 `application.properties` 或 `application.yml`),确保适当的 DDL 自动生成策略: ```properties # 允许Hibernate自动生成表结构 spring.jpa.hibernate.ddl-auto=update ``` - **说明**: - `none`: 禁止自动更新(默认值,适用于生产环境)。 - `create-drop`: 启动时创建、关闭时删除(测试场景常用)。 - `create`: 强制每次重启都重建所有表(仅用于开发阶段)。 - `update`: 自动更新现有表结构而不覆盖数据(推荐用于开发阶段)。 > 注意:如果使用了手动初始化脚本,则应避免将 `ddl-auto` 设为过于激进的选项(比如 `create` 和 `create-drop`)。 #### 方案二:确认实体类是否正确定义 验证是否存在与 `sys_authority` 表关联的 JPA Entity 类,并检查其注解声明是否完整无误。 示例代码如下: ```java @Entity @Table(name = "sys_authority") public class SysAuthority { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; // 添加字段及getter/setter... } ``` 如果没有这个实体类,请根据实际需求补充;如果有但仍然报错,请排查其他潜在问题,例如主键生成策略冲突等。 #### 方案三:跳过 Schema Validation (临时解决办法) 如果不希望强制进行 Schema 校验操作,可以禁用它: ```properties spring.jpa.properties.javax.persistence.validation.mode=none ``` 但是需要注意的是,这种方式只是绕过了验证步骤,并不会真正解决问题,因此只适合短期应急处理。 --- ### 总结 建议按照上述三种方式进行逐一排查,优先保证正确的数据库同步机制以及合理的配置选择。同时,在日常开发过程中也要养成良好的习惯——及时清理残留的历史版本依赖项并对重要的基础组件加以单元测试保障!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值