侧边栏壁纸
  • 累计撰写 218 篇文章
  • 累计创建 59 个标签
  • 累计收到 5 条评论

Python 前向引用的问题

barwe
2024-09-05 / 0 评论 / 0 点赞 / 546 阅读 / 1,172 字
温馨提示:
本文最后更新于 2024-09-05,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

考虑以下情况:

class AuditLog(models.Model):
    pass

class AuditDetail(models.Model):
    audit_log = models.ForeignKey(AuditLog, on_delete=models.CASCADE, related_name="_details")
    
log = AuditLog.objects.first()
detail = AuditDetail.objects.first()

AuditDetail 类上直接定义了 audit_log 字段,所以 detail.audit_log 可以直接获得 类型提示

对应的,log._details 是框架隐式添加的,它默认是 Any 类型。

为了给 log._details 加上类型提示,我们可以给 AuditLog 类直接添加一个属性方法:

class AuditLog(models.Model):
    @property
    def details(self):
        return self._details.all()

但是这样获得的 log.details 仍然是无类型提示的(它的实际类型是 QuerySet[AuditDetail])。

我们可以显式标注返回值类型:

class AuditLog(models.Model):
    @property
    def details(self) -> QuerySet[AuditDetail]:
        return self._details.all()

这时存在一个问题:AuditDetail 类是在 AuditLog 类后面定义的,AuditDetail 类中需要引用 AuditLog 类作为外键关联模型。

上述代码实际上使用了未定义的变量,这种困境叫做 前向引用问题,即两个类互相引用,前一个类不能直接引用后一个类。

解决办法:

1、使用 字符串注解(Python 3.7+)

从 Python 3.7 开始,可以直接用字符串来表示类型:

class AuditLog(models.Model):
    @property
    def details(self) -> QuerySet["AuditDetail"]:
        return self._details.all()

2、使用 __future__ 模块(Python 3.6)

from __future__ import annotations

class AuditLog(models.Model):
    @property
    def details(self) -> QuerySet[AuditDetail]:
        return self._details.all()

注意:from __future__ import annotations 必须放在文件的第一行。

3、使用 TypeUnion(≤ Python 3.5)

略,还是升级 Python 版本吧。

0

评论区