跳到正文
本地阅读 · 类型、运算及控制流

类型、运算及控制流

计算机基础 · Python基础

前置知识:环境与第一个程序

本章目录

本章学习目标

  • 区分数据类型与浮点误差
  • 用条件表达业务规则并处理缺失
  • 用循环累计指标且明确分母

一、类型决定操作含义

变量是指向对象的名字,类型属于对象;x=3 后再写 x="3" 合法,但相加行为会变化。常用类型包括整数 int、浮点 float、布尔 bool、字符串 str 和缺失占位 None。订单编号即使全由数字组成,也常应保存为字符串,因为它没有算术意义,而且可能带前导零;金额通常需要数值类型。把所有输入都转换成数字会丢失数据含义。

Python 整数可随需要扩展精度,不像固定宽度数组整数那样直接溢出,但占用内存和计算成本仍然存在。float 通常采用二进制双精度,多数十进制小数无法精确表示,因此 0.1+0.2==0.3 为假并非加法坏了。math.isclose 使用相对和绝对容差;接近零时必须考虑绝对容差。财务对账如果要求精确到分,可用整数分或 Decimal,并事先定义舍入规则,而不是在最终输出时随意格式化掩盖误差。

二、除法与比较需要精确定义

/ 是真除法,// 是向下取整除法,% 是取余;-3//2 得到负二,并非向零截断。百分比应先确定分子分母再相除,比如两笔付款占三笔订单的比例是三分之二,显示百分数才乘一百。不要把“增长两个百分点”和“增长百分之二”混为一谈,前者是比例的绝对差,后者是相对变化。

None 不是零也不是空字符串,判断缺失通常用 is None。if value 会把零、空容器、空字符串和 None 都视为假,如果零收入是有效数据,这种判断会误删记录。条件需要匹配业务含义,比如 value is not None and value>=0;短路机制保证缺失时不会继续比较大小。链式比较 0<=rate<=1 清楚表达取值范围,但它不能直接用于多元素 NumPy 数组,数组条件将在后续章节学习。

三、把业务口径翻译成分支

本章订单包含金额、状态和退款:只有状态为 paid 或 refunded 的订单进入净额统计,cancelled 不进入;退款已经发生但金额记录缺失的订单要报告异常,不能自动按零算。分支顺序很重要,先处理缺失和非法值,再应用业务规则,避免先减法而产生 TypeError。if/elif/else 每次最多执行一个分支,多个独立 if 则可能都执行。

用三条记录手算:已付款一百无退款,已退款八十退二十,已取消五十,净额是一百加六十等于一百六十,纳入的订单数为二。平均净额八十的分母是被纳入订单数;如果平均每名注册用户收入,分母应改成用户数。代码只会按你写的计数累加,不会自动理解指标名称。写程序前把纳入条件和分母写成一句话,是数据分析的重要步骤。

四、循环、跳过与提前结束

for 从可迭代对象逐个取元素,range(n) 给出从零到 n 前一位的整数。continue 跳过当前记录的剩余工作;break 停止整个循环。清洗订单时遇到 cancelled 通常只应 continue,而不是 break,否则后面正常订单永远不会处理。while 适合条件驱动的重复,但要保证状态变化,否则会无限循环。

累计值和计数值通常在循环之前初始化。把 total=0 放在循环内部会每次重置,最后只得到最后一笔金额。空输入时循环一次也不执行,平均值分母为零,应显式返回 None 或说明“没有有效订单”,不应返回零并让读者误以为真实均值为零。循环中修改正在遍历的列表可能跳过元素,先构造新列表或遍历副本更容易验证。

五、反例驱动的验证

配套代码不仅计算正常记录,也加入 None、取消订单和空有效集合。先预测每条记录是被纳入还是跳过,再运行检查计数与净额。把 paid 改为未知状态时,程序应按约定拒绝或报告,不能让未知值自动落入“其他都有效”的分支。状态值来自外部文件时可能带空格或大小写不同,规范化应在清洗步骤完成,不要在每个指标中重复临时补救。

面试中解释控制流,不只是说“if 判断、for 循环”。需要指出输入类型、有效条件、短路对缺失值的保护、空输入的约定和分母口径。训练这些习惯后,写 SQL 的 CASE、WHERE 和 pandas 布尔筛选会更自然;三种语言的写法不同,但分析规则必须相同。对于计算精度,先说明计量单位和容差,再选择 float、Decimal 或整数分。

完整示例与实际输出

import math
orders=[(100,"paid",0),(80,"refunded",20),(50,"cancelled",0),(None,"paid",0)]
total=0; count=0; missing=0
for amount,status,refund in orders:
    if amount is None:
        missing += 1
        continue
    if status not in {"paid","refunded"}:
        continue
    if not 0 <= refund <= amount:
        raise ValueError("invalid refund")
    total += amount-refund; count += 1
average=total/count if count else None
assert (total,count,missing,average)==(160,2,1,80)
assert math.isclose(0.1+0.2,0.3)
assert -3//2 == -2
print("total/count/missing/average",total,count,missing,average)
print("float exact equality",0.1+0.2==0.3)

实际运行通过CPU Python execution.

total/count/missing/average 160 2 1 80.0
float exact equality False

五道自测:先回答,再核对

01 · 编号 '0012' 为什么不一定应转整数?

查看提示

编号有没有算术意义?

查看参考答案

转整数会丢掉前导零;编号应按标识符处理。

02 · None 与零在 if value 中有何区别?

查看提示

看真值而非业务。

查看参考答案

都被判为假,但 None 表示缺失,零可为有效值,应显式区分。

03 · -3//2 的结果是多少?

查看提示

向下取整。

查看参考答案

-2。

04 · 处理取消订单用 continue 和 break 有何差异?

查看提示

后续记录是否继续?

查看参考答案

continue 只跳过本条;break 会结束循环,可能漏掉后续有效订单。

05 · 空订单集的平均净额该如何处理?

查看提示

分母为零。

查看参考答案

明确给出 None/无有效订单,不应除零或把无数据解释为真实零均值。

两项动手任务

任务 1 · 统计 [0,None,10,-3,20] 中非缺失且非负的均值,保留有效零值。

提示

筛选规则是 is not None 和 >=0。

完整参考解答与检查方式

有效值为零、十、二十,均值十;分母为三。

values=[0,None,10,-3,20]
valid=[v for v in values if v is not None and v>=0]
result=sum(valid)/len(valid) if valid else None
assert valid==[0,10,20] and result==10
print(result)

任务 2 · 两天转化率从 0.10 变为 0.12,计算百分点变化和相对增长。

提示

一个用差,一个用差除以基期。

完整参考解答与检查方式

增加二个百分点,相对增长百分之二十;用 isclose 检查浮点结果。

import math
before,after=0.10,0.12
points=(after-before)*100
relative=(after-before)/before
assert math.isclose(points,2) and math.isclose(relative,0.2)
print(f"{points:.1f} percentage points; {relative:.0%} relative growth")

官方资料与掌握状态

完成两项任务后,按独立完成程度记录。状态会尽量保存在当前浏览器,可导出备份。

动手任务记录

掌握状态与复习

关掉资料独立完成后记 A;提示后完成记 B;需要重学记 C。

记录尽量保存在当前浏览器,建议定期导出备份。