第2章:Variables and Simple Data Types

用名字绑定模型理解变量,掌握字符串、数字、常量、注释和 Python 风格。

学习目标

  • 能解释 Variables Are Labels 的绑定模型,分析重新赋值后多个名字分别指向哪个对象
  • 能实现包含 string methods、f-string、removeprefix/removesuffix 与 whitespace 规范化的输入清洗链
  • 能比较 integer 与 float 表达式,判断 multiple assignment、constants、comments 和 Zen of Python 的使用边界

为什么“变量是标签”比“变量是盒子”更准确

运行message = "draft"时,Python先创建字符串对象,再让名字message引用它。赋值不是声明一个固定类型槽位,也不是把对象内容复制进名字。之后执行backup = message,两个名字可以指向同一个对象;再执行message = "published"只会重绑定message,不会把backup所见的旧字符串改掉。

先预测三步赋值后两个名字各打印什么,再操作下图。这个模型会在第3–4章解释list alias与copy,在第8章解释参数传递,在第9章解释instance attribute;若现在仍把名字当盒子,后续可变对象行为会显得随机。

分步1 / 3

逐步执行三个赋值语句

message = "draft"
backup = message
print(message, backup)
 
message = "published"
print(message, backup)  # published draft

变量名只能包含字母、数字和下划线,不能以数字开头,也不能使用Python关键字。选择能表达意图的名字,例如unread_messages而不是um;NameError常来自拼写不一致或在绑定前读取名字。第三版改进了错误提示,但仍要从异常类型、行号和候选拼写理解根因。

Strings:转换返回新值,原对象不变

string既能保存单引号,也能保存双引号;选择外层引号以减少转义。title()upper()lower()strip()等string methods都返回新字符串。若没有赋值或传给下一个函数,结果会被丢弃:name.strip()不会原地改变name

分步1 / 3

选择一个字符串转换

raw_url = "  https://example.com/report.txt  "
clean_url = raw_url.strip()
host_and_path = clean_url.removeprefix("https://")
stem = host_and_path.removesuffix(".txt")
 
print(f"raw={raw_url!r}")
print(f"normalized={stem!r}")

f-string在运行时求值花括号内的表达式,适合把变量组成可读消息。!r使用repr形式,能让tab、newline和边界whitespace显形;这比直接print更适合排查清洗错误。 插入tab,\n插入newline,但展示格式不应和领域数据混为一体。

removeprefix()removesuffix()不是strip()的替代品。strip("https://")把参数视为“可从两端移除的字符集合”,并不要求完整前缀匹配,可能误删合法字符。需要精确协议或扩展名时使用专用方法,且先判断大小写、空值与重复前缀策略。

字符串清洗也需要输入契约

不要把多个string methods随意串起来后假定所有输入都合理。先写出允许的scheme、是否区分大小写、空白输入如何处理、重复prefix是错误还是只移除一次,以及normalized value是否允许为空。例如removeprefix("https://")只移除一次且大小写敏感;如果业务同时接受HTTP和HTTPS,就应明确分支或使用URL parser,而不是再堆一组strip调用。

清洗与验证也不是同一动作。strip()可以规范边界whitespace,却不能证明URL、用户名或文件扩展名合法。保留raw value用于错误反馈,生成normalized value用于后续比较,再由独立validation返回具体失败原因。这样日志能回答用户实际输入了什么,测试也能分别覆盖转换规则和拒绝规则。

Numbers:先判断运算语义,再看显示结果

Python的integer可以按可用内存增长,不受固定32位范围限制;float通常采用二进制浮点,像0.1这样的十进制小数无法精确表示。+ - * /含义直观,但/总返回float,//执行floor division,**表示幂。运算优先级不确定时使用括号表达意图。

分步1 / 3

选择一个数值表达式并先预测

universe_age = 14_000_000_000
x, y, z = 0, 0, 0
MAX_WORKERS = 8
 
print(universe_age)
print(x, y, z)
print(0.1 + 0.2)
print(7 / 2, 7 // 2, 2 ** 8)

numeric underscores只提高源码可读性,14_000_000_000与不加下划线的整数值相同。Multiple Assignment要求右侧提供相同数量的值,适合一起初始化相关名字,但不要为了短而把无关状态挤在一行。Python没有阻止重新绑定的真正常量关键字,Constants使用全大写命名约定表达“不要修改”,代码评审和测试负责维护这项约定。

内部数值与显示格式是两层协议

数值对象负责计算,f-string格式负责展示。f"{ratio:.2f}"把输出限制为两位小数,但不会让底层float突然变成十进制精确值;逗号分组、百分号和宽度同样只影响文本表示。后续若还要计算,应继续传递numeric value,不要把格式化字符串再解析回来,否则会引入locale、舍入和单位错误。

边界输入需要同时检查值域和类型语义:worker数量必须是正integer,百分比可能允许float,金额应选择Decimal或整数最小单位。把这些决定写在靠近输入边界的位置,并在输出处明确舍入策略。一个看似简单的print若隐藏了单位、精度或舍入规则,下一章放进list批量处理后会放大成系统性错误。

Comments 与 Zen of Python:解释决策,不复述语法

comment以#开始。高价值注释说明为什么选择某个阈值、为何规避一个已知边界,或引用外部约束;# 将x加1只复述x += 1,代码改变后还容易过期。能通过清晰名字和小函数表达的意图,优先写进代码结构。

运行import this会显示Zen of Python。它不是互不冲突的硬规则,而是一组设计张力:Explicit is better than implicit提醒API把重要行为写出来,Simple is better than complex鼓励先选简单方案,Readability counts要求代码为下一位读者优化。当“简短”导致隐含状态和难以测试时,应选择更明确的版本。

本章的clean code不是追求某种固定格式,而是让name binding、字符串转换和数值假设可观察。变量名表达角色,f-string明确输出边界,constant convention提示稳定配置,comment记录不能从代码直接读出的原因。后续章节会把这些习惯扩展到list、function、class和项目结构。

本章回顾:从绑定到可读代码

  1. Variables Are Labels:赋值建立name binding,重新赋值不会自动修改其他名字。
  2. string methods返回新对象;f-string组成消息,whitespace与prefix/suffix处理必须选择正确语义。
  3. integer精确保存整数,float存在二进制近似;预测表达式时同时关心value与type。
  4. Multiple Assignment提高相关初始化可读性,Constants是大写约定而非运行时保护。
  5. comments解释原因,Zen of Python提供可读、明确和简单之间的设计方向。

练习

问题 1:执行 status = "draft"; snapshot = status; status = "ready" 后两个名字分别是什么?为什么?

问题 2:实现URL规范化,要求只删除两端空白、开头的https://和结尾的.json,同时保留原始输入。

问题 3:为什么价格计算不应直接依赖 0.1 + 0.2 == 0.3?给出两种策略。

术语表

名词解释

本章出现的专业名词,用大白话再讲一遍。

name binding
string method
f-string
floating-point approximation
constant convention

讨论

评论区加载中…