当前位置:首页 > 文章列表 > 文章 > python教程 > Python LiteralString 怎样约束拼接后的字符串

Python LiteralString 怎样约束拼接后的字符串

来源:17golang原创 2026-10-18 14:10:47 0浏览 收藏

我第一次把动态输入拼进敏感字符串时,最容易犯的错不是语法写错,而是把“看起来只是一个 str”的值交给了不该接收任意文本的接口。Python 的 LiteralString 可以把这条边界写进函数签名:字面量和由字面量组成的字符串可以通过,来源不明的普通 str 会被静态类型检查器拦下。

官方地址:https://docs.python.org/3/library/typing.html#typing.LiteralString

核心做法是:让 SQL、Shell 模板或其他敏感 API 只接收 LiteralString,把用户输入放到独立的参数位。LiteralString 只负责静态约束,运行时仍然是普通字符串,不能替代参数化查询、转义和权限控制。

LiteralString 与普通 str 的边界在哪里

LiteralString 在 Python 3.11 加入 typing,它不是运行时的新类,而是给静态类型检查器识别的特殊类型。可以把它理解成“已知由字符串字面量构成”的范围:字面量可以传入,另一个 LiteralString 也可以传入;一个只标注为 str 的变量则不能直接传入。

from typing import LiteralString

def execute_safe(statement: LiteralString) -> None:
    # 敏感 API 只接受可追溯到字面量的模板。
    print(statement)

literal_sql = "SELECT id FROM users"
dynamic_sql: str = "SELECT id FROM " + input("table: ")

execute_safe(literal_sql)   # 通过:来源是字符串字面量
execute_safe(dynamic_sql)   # 类型检查器应报告:普通 str 不是 LiteralString

这里的“拒绝”发生在检查阶段,不是 Python 运行时抛出的异常。PEP 675 把 LiteralString 放在具体字面量类型和普通 str 之间:它可以赋值给 str,但普通 str 不能反向赋值给 LiteralString。

字符串字面量、LiteralString、普通 str 与敏感 API 的静态类型边界说明图
图1:LiteralString 与普通 str 的类型边界说明图;这是静态结构图,不是运行截图。

哪些拼接仍然保留 LiteralString

标题里的“拼接”不是一律不允许。只要参与组合的值都属于字面量字符串或 LiteralString,类型检查器可以继续把结果视为 LiteralString。普通 str 一旦进入组合,结果就会退回普通 str。

from typing import LiteralString

def run_query(query: LiteralString) -> None:
    # 这里只展示类型边界;实际数据库调用仍应使用参数化接口。
    print(query)

base: LiteralString = "SELECT id FROM users"
suffix: LiteralString = " WHERE active = 1"
safe_query = base + suffix
run_query(safe_query)  # 通过:两部分都在 LiteralString 边界内

user_name: str = input("name: ")
unsafe_query = base + " WHERE name = '" + user_name + "'"
run_query(unsafe_query)  # 应被静态检查器拒绝

columns = ["id", "email"]
projection = ", ".join(columns)
run_query(projection)  # 具体结果取决于检查器对容器元素的推断

同样的规则适用于字面量分隔符的 join,以及只使用字面量字符串组成的格式化表达式。不要把“检查器接受了拼接”误读成“SQL 已经安全”:它只说明字符串来源边界满足类型契约。

动态数据应该留在参数位

更稳妥的工程习惯是把模板和数据分成两个参数。模板由代码维护,用户输入作为绑定值交给数据库驱动;这样既保留 LiteralString 的静态约束,也让真正执行查询的 API 处理数据转义。

from typing import LiteralString

def execute_query(query: LiteralString, params: tuple[object, ...]) -> None:
    # 模板和数据分离;真实项目中把它转交给支持参数绑定的驱动。
    print(query, params)

query: LiteralString = (
    "SELECT id, email FROM users WHERE name = ?"
)
name: str = input("name: ")
execute_query(query, (name,))  # 动态值留在参数位

# 不要把 name 拼回 query;那会把结果降级为普通 str。
bad_query = "SELECT id FROM users WHERE name = '" + name + "'"
# execute_query(bad_query, ())  # 类型检查器应提示边界被破坏

这类签名的保护资产是“代码模板和外部数据的分离”。如果敏感 API 还需要允许列名、排序方向等动态结构,就不要把它们直接拼进去,而是先用白名单把外部值映射到有限的字面量集合,再把映射后的结果交给检查器可识别的接口。

查询模板、参数化数据、用户输入和类型检查器之间的安全边界说明图
图2:敏感字符串与动态数据分离的防护边界说明图;这是静态结构图,不是执行结果截图。

Any、cast 和忽略诊断会怎样破坏边界

LiteralString 适合防止“善意代码误用敏感 API”,但它不是对抗恶意开发者的运行时防火墙。使用 Any、cast(LiteralString, value) 或忽略类型错误,都可能让普通字符串伪装成满足契约的值。

from typing import Any, LiteralString, cast

def execute_safe(statement: LiteralString) -> None:
    # 运行时无法区分 LiteralString 与 str,因此仍需真实安全控制。
    print(statement)

raw: str = input("statement: ")
untyped: Any = raw
lied = cast(LiteralString, raw)

execute_safe(untyped)  # Any 可能绕过静态检查
execute_safe(lied)     # cast 只是告诉检查器“相信我”

因此,审计时要同时看三层:敏感 API 的参数类型是否收窄到 LiteralString;动态值是否进入参数化接口;运行时是否仍有驱动、解析器、白名单或权限层的防护。没有类型检查器、没有注解,或把关键变量标成 Any 时,第一层就不会产生告警。

落地时的检查清单

  • 模板参数是否标注为 LiteralString,而不是宽泛的 str?
  • 用户输入是否保持在参数位,是否避免进入 SQL、Shell 或 HTML 模板?
  • 拼接链路中是否混入普通 str、Any 或不必要的 cast?
  • 运行时是否仍使用参数化查询、转义、白名单和最小权限?

我对 LiteralString 的实际判断是:它最有价值的地方不是替你做完安全工作,而是把“这个字符串不应来自任意外部文本”变成可审查的函数契约。只要把动态数据留在参数位,再用类型检查和运行时控制共同兜底,拼接后的字符串边界就会清楚很多。

相关问题

LiteralString 是运行时类型吗?不是。它只参与静态类型检查,运行时值仍然是普通 str。

两个 LiteralString 可以拼接吗?可以。字面量与 LiteralString 组合时,检查器可以保留这个兼容性;混入普通 str 后通常会退回普通 str。

用了 LiteralString 就不用参数化查询了吗?不用。LiteralString 是开发期的来源约束,参数化查询和运行时校验仍然是执行层的安全措施。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Python TypedDict 怎样标记部分必填字段Python TypedDict 怎样标记部分必填字段
上一篇
Python TypedDict 怎样标记部分必填字段
Python pathlib 怎样指定文本文件编码读取
下一篇
Python pathlib 怎样指定文本文件编码读取
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    523次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    580次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    607次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    557次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    377次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码