Python 2 raw_input()与Python 3 input()有什么区别
raw_input() 与 input() 两个函数,其中 raw_input() 将键盘输入完整作为原始字符串返回,而 input() 会在内部隐式调用 eval() 对输入内容进行动态求值;到了 Python 3,危险的自动求值机制被彻底废弃,旧版 raw_input() 被移除,其原有的安全读取功能直接由 Python 3 的 input() 继承,并固定返回原生 Unicode 字符串。
核心区别概览与函数映射关系
对于初学者与从旧版本迁移代码的开发者而言,混淆输入函数不仅会导致程序逻辑异常,更可能埋下严重的系统安全漏洞。Python 语言在由 2.x 向 3.x 版本演进的过程中,针对输入接口做出了“去除隐式求值、强化数据安全”的重构。
| 函数名称 | 支持环境 | 底层运行逻辑 | 返回值数据类型 | 安全性评价 | 典型处理方式 |
|---|---|---|---|---|---|
raw_input() |
Python 2.x | 读取输入并剥离末尾换行符,原样返回文本 | str(8 位字节串) |
安全 无注入风险 | 需手动使用 int() 等显式转换类型 |
input() |
Python 2.x | 等价于 eval(raw_input()) 动态计算 |
取决于输入计算结果的动态类型 | 极高危 存在任意代码执行漏洞 | 易受恶意输入攻击,现代开发坚决弃用 |
input() |
Python 3.x | 完全继承旧版 raw_input() 的安全机制 |
str(原生 Unicode 字符串) |
安全 纯数据输入 | 纯文本直接使用,数值需配合显式转换 |
raw_input() |
Python 3.x | 该函数已被完全删除,调用抛出异常 | 不适用(抛出 NameError) |
不适用 | 代码迁移时直接全局替换为 input() |
通过下方的结构关系图,可以直观理清两个版本之间输入函数的废弃、继承与演进逻辑:
Python 2 中 raw_input() 与 input() 的机制差异
在 Python 2 环境中,设计者最初设想:为开发者提供一个“直接输入文本”的函数(raw_input),同时提供一个“能够直接识别数字和数据结构”的便捷函数(input)。然而,这种设计带来了严重的安全与逻辑缺陷。
1. raw_input() 的原样读取机制
raw_input() 是纯粹的标准输入流读取工具。它会等待用户在控制台键入字符,直至按下回车键。该函数会剥离行尾的换行符 \n,并将剩余内容直接包装为一个标准的 8 位字符串(str)返回给调用者。
# Python 2 环境演示 raw_input()
text = raw_input("请输入内容: ")
print type(text) # 输出: <type 'str'>
print repr(text) # 无论输入何种内容,均原样以字符串输出
例如,当用户在提示符后键入 123 时,raw_input() 返回的是字符串 '123';键入 1 + 2 时,返回的是字符串 '1 + 2'。它绝不会尝试去计算或解析输入内容,因此数据输入与代码执行边界清晰。
2. Python 2 input() 的隐式动态求值漏洞
与 raw_input() 不同,Python 2 中的 input() 并不是一个独立实现的输入解析器,它的底层逻辑完全等价于:
# Python 2 中 input() 的底层等价形式
def input(prompt=None):
return eval(raw_input(prompt))
这意味着任何通过 input() 键入的内容,都会被直接放入 Python 表达式解析器中进行计算。这一机制引发了三大严重问题:
- 输入字符串必须加引号:如果用户希望输入一个普通单词(如
hello),直接输入会导致 Python 尝试寻找名为hello的变量,进而抛出NameError: name 'hello' is not defined。用户必须繁琐地手动键入"hello"。 - 数据类型不稳定:如果程序期望获取一个数值,用户输入
100得到整型,输入[1, 2]得到列表,输入3.14得到浮点型。如果用户输入了不合法的表达式,程序将直接崩溃。 - 灾难性的代码执行安全风险:由于
eval()拥有完整的表达式求值权限,若恶意攻击者在终端输入系统调用代码(例如__import__('os').system('rm -rf /')),Python 会立即执行该系统命令,从而引发严重的系统越权与破坏。
Python 3 统一为 input() 的设计理念与类型特征
基于 Python 哲学中“显式优于隐式(Explicit is better than implicit)”与“安全性高于微弱便利性”的原则,Python 3 对控制台输入体系做出了彻底重塑:
1. 剔除隐式求值,确立纯文本安全契约
在 Python 3 中,旧版具备自动执行表达式特性的 input() 被彻底废除。取而代之的是:将原 raw_input() 的行为重命名为 input(),并完全移除了 raw_input 这一函数标识符。
在 Python 3 中执行 data = input(),无论用户在键盘上输入什么字符(数字、字母、符号、Python 代码甚至换行符),程序一律将其视为字面文本,绝不进行隐式求值。
2. 返回值底层类型由字节串升级为 Unicode
除了执行机制的变化,返回值的底层类型系统也迎来了关键升级:
- Python 2 的 raw_input():返回的是 8 位的
str类型,其实质等价于字节串(Byte String)。若终端包含中文字符,获取到的实质是一串未经解码的机器字节(例如 UTF-8 或 GBK 编码序列),进行切片、计数或拼接时极易发生乱码。 - Python 3 的 input():返回的是原生支持 Unicode 的
str字符串。Python 解释器在接收到终端输入流时,会自动依据系统当前的控制台编码(如 UTF-8)完成无缝解码。中文字符在长度计算、切片与匹配时均被作为统一的字符单元处理,彻底规避了中文乱码陷阱。
3. 规范的数据类型显式转换范式
在 Python 3 中,由于 input() 始终返回字符串,当业务场景需要数值或其他结构时,开发者必须显式进行类型转换,并配合异常处理确保程序稳健:
import ast
# 场景一:转换为整数(结合异常处理)
raw_age = input("请输入年龄: ")
try:
age = int(raw_age)
print("年龄记录成功:", age)
except ValueError:
print("输入格式错误:请输入有效的纯数字!")
# 场景二:转换为浮点数
raw_price = input("请输入单价: ")
try:
price = float(raw_price)
print("商品价格:", price)
except ValueError:
print("输入格式错误:请输入有效的数值!")
# 场景三:安全解析字面量结构(如输入列表 [1, 2, 3] 或字典)
# 注意:严禁使用 eval(input())!应当使用 ast.literal_eval()
raw_list = input("请输入数据列表: ")
try:
parsed_data = ast.literal_eval(raw_list)
print("解析得到的数据类型:", type(parsed_data))
except (ValueError, SyntaxError):
print("输入格式错误:必须为合法的 Python 字面量结构!")
跨版本兼容处理与工程迁移指南
在进行项目维护或代码重构时,开发者经常面临两种典型需求:一是编写同时兼容 Python 2 和 Python 3 的跨环境运行脚本;二是从旧版 Python 2 代码库向 Python 3 迁移。针对这两种场景,有明确的标准解决方案。
1. 编写跨版本兼容输入代码
如果脚本必须同时在尚未退役的 Python 2 嵌入式环境与现代 Python 3 环境下运行,可以在模块头部使用内置异常捕获机制进行函数重绑定:
# 跨版本兼容标准范式(推荐放在公共工具模块或脚本顶部)
try:
# 若在 Python 2 环境中,raw_input 存在,将其重命名为 input
input = raw_input
except NameError:
# 若在 Python 3 环境中,raw_input 不存在会抛出 NameError
# 此时无需处理,直接使用 Python 3 原生的 input 即可
pass
# 后续业务逻辑中统一使用 input(),在两个版本下均表现为安全返回字符串
username = input("请输入用户名: ")
print("输入结果:", username)
在 Python 2 中,通过 input = raw_input 语句,用安全的 raw_input 覆盖掉了原有危险的 input;而在 Python 3 中,直接沿用原生的 input。这种写法无需引入第三方库,语法简洁且执行效率极高。
2. 遗留项目迁移排查清单
在将旧工程升级至 Python 3 时,绝不能简单地依赖文本替换,需要依据以下清单逐一排查:
-
排查历史代码中的 raw_input():
这类函数直接转换为 Python 3 的
input()即可,行为完全等价。使用官方迁移工具2to3时,工具会自动将所有raw_input(...)重写为input(...)。 -
重点审计历史代码中的 input():
如果 Python 2 旧代码中调用了
input(),说明原作者可能依赖了其自动转换为整数或列表的副作用。如果直接迁移为 Python 3 的input(),原本获取到的整数将变成字符串,进而导致后续算术运算抛出TypeError。 -
替换危险的 eval 逻辑:
若旧代码中确实需要输入列表、字典等结构,切勿为了保持兼容而写出
eval(input())。必须统一重构为ast.literal_eval(input()),从根源上阻断代码注入途径。
总结与开发守则
从 Python 2 的 raw_input() 与 input() 到 Python 3 的唯一定义,这一演进深刻反映了现代编程语言对系统安全与接口一致性的追求。
- 核心结论:Python 3 的
input()实质就是 Python 2 的raw_input(),原 Python 2input()的隐式求值机制已被彻底废除。 - 类型守则:现代 Python 的输入结果永远是纯文本 Unicode 字符串,绝不隐式转换类型。
- 安全红线:永远不要对未经校验的控制台输入使用
eval();数值转换用int()/float()配合异常捕获,结构解析使用ast.literal_eval()。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









