Python 变量与类型

要点

赋值把名字绑定到对象,两个名字可以指向同一个列表。不可变值的重新绑定与可变对象的原地修改需要分开理解。

1. 变量:贴在对象上的标签

Python 变量没有类型,对象才有。赋值是把名字绑定到对象:

x = 42        # 名字 x 指向 int 对象 42
x = "hello"   # 现在 x 指向 str 对象 —— 完全合法

与 Go/Java 的区别:int x = 42 把盒子填成整数,之后只能装整数;而 Python 的 x 只是一个可反复改贴的标签。

a = [1, 2, 3]
b = a          # b 与 a 指向同一个列表
b.append(4)
print(a)       # [1, 2, 3, 4] —— 同一对象被两个名字观察

⚠️ 这是 Python 新手第一大陷阱:赋值复制的是引用。需要独立副本时用 b = a.copy() 或 b = list(a)。

动态类型的代价是错误晚发现,所以现代 Python 靠类型注解找回编译期体验(见第 4 节)。


2. 六种常见基础类型

类型示例可变说明
int42, 0x2A, 1_000_000否任意精度,不会溢出
float3.14, 1e-3否双精度浮点,注意精度误差
str"hello", '单引号'否Unicode 字符串,不可变
boolTrue, False否是 int 的子类(True == 1)
NoneNone—空值唯一实例,判等用 is
bytesb"x00xff"否字节序列,处理二进制数据

不可变(immutable) 意味着任何”修改”操作都返回新对象:

s = "python"
s.upper()        # 返回 'PYTHON',s 本身不变
s = s.upper()    # 必须重新绑定才"改变" s

print(10 / 3)    # 3.3333333333333335 真除法,永远得 float
print(10 // 3)   # 3 整除
print(10 % 3)    # 1 取余
print(2 ** 100)  # 1267650600228229401496703205376 大整数无上限

浮点精度是 IEEE 754 的固有行为:0.1 + 0.2 == 0.3 结果为 False。金额计算用 decimal.Decimal,科学计算用 float。


3. f-string:现代格式化的唯一答案

Python 3.12 起 f-string 支持嵌套引号与多行表达式,日常输出仍是首选的字符串插值方案:

name, price, qty = "机械键盘", 399.5, 2

1. 基本插值:{表达式}
print(f"{name} 单价 {price} 元")

1. 表达式直接计算
print(f"合计 {price * qty:.2f} 元")       # 合计 799.00 元

1. 对齐与填充:{值:填充符 对齐 宽度}
print(f"|{name:<10}|")      # 左对齐,宽 10
print(f"|{price:>10.1f}|")  # 右对齐,宽 10,保留 1 位小数
print(f"|{name:*^10}|")     # 居中,* 填充

1. 调试三件套:= 语法输出表达式本身
print(f"{price=}, {qty=}")  # price=399.5, qty=2

1. 千分位与百分号
print(f"{1234567:,}")     # 1,234,567
print(f"{0.856:.1%}")     # 85.6%

多行 f-string 与嵌套引号(3.12 新能力):

data = {"user": {"name": "ada"}}
print(f"用户名: {data["user"]["name"]}")  # 3.12 起允许内部再用双引号

3.14 新增 t-string(PEP 750):t"..." 语法与 f-string 同形,但返回的不是 str,而是可延迟处理的模板对象——渲染交给库决定,适合 HTML 转义、SQL 参数化等防注入场景:

title = "<script>攻击</script>"
template = t"<h1>{title}</h1>"   # 模板对象,不会立即拼接
1. 由渲染库(如 html 支持库)决定如何转义 title 后再输出

入门阶段记住”f-string 直接出字符串、t-string 出模板对象”即可,详见字符串格式化字典。

旧写法 % 与 str.format() 只需能读懂,新代码一律 f-string(需要防注入的模板渲染交给 t-string 生态)。


4. 类型注解:给动态类型上保险

注解不影响运行时,但编辑器、mypy/pyright、FastAPI 都依赖它:

# 变量注解(多在复杂初始化处使用)
count: int = 0
tags: list[str] = []
config: dict[str, str] = {}

1. 函数注解是刚需
def repeat(text: str, times: int = 2) -> str:
    return text * times

1. 可能为空 → 管道联合类型(3.10+ 标准写法)
def find_user(uid: int) -> str | None:
    ...

类型演进对照(旧代码里会遇到,新代码用右列):

旧写法(3.8 及以前)3.10+ 写法(3.12 仍推荐)
Optional[str]str | None
Union[int, str]int | str
List[str]list[str]
Dict[str, int]dict[str, int]
Type[X]type[X]

💡 注解是”承诺”而非”强制”:def f(x: int) 传字符串不会在运行时报错,需靠 uvx mypy . 或 Pylance 静态检查兜底。


5. 类型转换与真值判断

int("42"), float("3.5"), str(99), bool("")   # 显式转换
int("4A")          # ValueError —— 转换失败抛异常而非返回垃圾值

1. 真值测试:以下都为 False
falsy = [0, 0.0, "", [], {}, set(), None, False]

习惯写法是利用真值语义,而不是与空值硬比较:

items: list[str] = []
if items:            # 推荐:非空列表即真
    print("有数据")

name: str | None = None
if name:             # 同时排除 None 和 ""
    print(name.strip())

最佳实践

类型注解描述预期契约,运行时仍可收到不符合约定的值。判断“缺失”用 is None,判断“为空”可用相应长度或真值;0、空串与 None 不能因都为假就无条件视为同一业务情况。

浮点近似比较要设置符合场景的相对或绝对容差,精确可表示值与特定协议也可能需要精确比较。f-string、format 和日志的延迟格式化各有用途,不必统一禁用。练习分别输入 None、0 和空串,确认不会误用默认值。


常见问题

Q1: 为什么 b = a 之后改 b,a 也变了?

A: a、b 是同一对象的两个标签(第 1 节)。可变对象(list/dict/set)共享引用;int/str 等不可变对象”看似复制”是因为修改只能产生新对象。

Q2: 注解错了运行时为什么没报错?

A: 注解默认只存进 __annotations__,解释器不校验。运行时强校验交给 Pydantic(见 typing 注解全表)。


练习与实践

正文验证:绑定、不可变值与格式化

下面程序是本页关键对象模型与 f-string 规则的独立版本。验证脚本会直接提取这个 Markdown 代码块,用隔离的 Python 容器执行;它不覆盖类型检查器、第三方库或本页其他示例。

a = [1]
b = a
b.append(2)
assert a == [1, 2]

b = [9]
assert a == [1, 2] and b == [9]

name, price, qty = 'keyboard', 399.5, 2
assert f'{price * qty:.2f}' == '799.00'
assert f'{name:*>10}' == '**keyboard'
assert 0.1 + 0.2 != 0.3
print('python-bindings: alias, rebinding, f-string, float')

练习一:类型观察

  1. 在 REPL 中依次执行 type(1)、type(True)、isinstance(True, int),解释输出
  2. 构造 a = [1, 2],用三种方式创建独立副本并逐一验证

练习二:格式化报告

  1. 给定 items = [("键盘", 399.5, 2), ("鼠标", 129, 5)]
  2. 用 f-string 输出右对齐的三列表格,金额保留两位、千分位
  3. 合计行用 = 调试语法打印各变量

评估标准:输出形如 | 键盘 | 399.50 | 2 |,且 uvx mypy 对练习代码零报错。


相关文档

  • 📄 函数与类 — 把类型注解扩展到面向对象设计
  • 📄 数据结构速查 — list/dict/set/tuple 全操作
  • 📄 typing 注解全表 — 泛型、Protocol、TypedDict 进阶
暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇