02|用变量和类型系统管理项目数据
场景引入:客户信息登记表
假设你正在为一个社区活动搭建报名系统。每位参与者需要录入姓名、年龄、联系方式、是否为会员等信息。这些信息各不相同——有的是文字,有的是数字,有的是”是或否”。如何在程序中表达并管理这些多样化的数据?
这就引出了两个基础问题:
- 怎样在程序中为数据命名并引用它?——变量
- 程序如何区分”文字”和”数字”这类不同性质的数据?——数据类型
变量:给数据贴上标签
在 Python 中,用 = 号即可创建变量:
participant = "赵青"
reg_age = 27
contact_fee = 39.9
is_member = True
这里创建了四个变量。= 是赋值运算符,含义是”将右侧的值绑定到左侧的名称上”。注意,这与数学中的等号含义不同。
变量的值可以随时更新:
reg_age = 27
print(reg_age) # 27
reg_age = 28
print(reg_age) # 28
reg_age = reg_age + 1
print(reg_age) # 29
Python 还支持同时为多个变量赋值:
lat, lng, alt = 39.9, 116.4, 50
print(lat, lng, alt) # 39.9 116.4 50
# 交换两个变量的值——Python 独有的简洁语法
lat, lng = lng, lat
print(lat, lng) # 116.4 39.9
变量命名规范
必须遵守:
- 只能包含字母、数字和下划线
_ - 不能以数字开头
- 不能使用 Python 保留关键字(如
if、for、class) - 区分大小写:
Total和total是两个不同的变量
推荐遵守:
- 使用有描述性的名称:
order_count优于oc - 采用蛇形命名法(snake_case):
max_retry_count - 常量用全大写:
TAX_RATE = 0.13
# 合法命名
order_total = 299
_internal_flag = True
item2 = "backup"
# 非法命名(会报错)
# 2nd_item = "error" # 数字开头
# order-total = 299 # 包含连字符
# class = "Python" # 使用了关键字
动态类型机制
Python 是动态类型语言。变量不需要预先声明类型,同一个变量可以在不同时间绑定不同类型的值:
payload = 100
print(type(payload)) # <class 'int'>
payload = "json_data"
print(type(payload)) # <class 'str'>
payload = [1, 2, 3]
print(type(payload)) # <class 'list'>
这种灵活性提高了编码速度,但也要求开发者自觉关注变量中存储的数据类型。
基本数据类型
整数(int)
整数是不带小数点的数值,可以是正数、负数或零:
stock_count = 500
temperature_offset = -15
empty_slot = 0
# Python 支持任意精度整数
large_id = 98765432101234567890
print(large_id) # 正常输出,无溢出
# 常用算术运算
print(20 + 7) # 加法:27
print(20 - 7) # 减法:13
print(20 * 7) # 乘法:140
print(20 / 7) # 除法:2.857142857142857(结果始终是浮点数)
print(20 // 7) # 整除:2
print(20 % 7) # 取余:6
print(2 ** 8) # 幂运算:256
需要特别注意:/ 运算的结果始终是浮点数,即使能整除也如此:
print(21 / 7) # 3.0(不是 3)
print(21 // 7) # 3(整除才返回整数)
浮点数(float)
带小数点的数值:
latitude = 31.2304
voltage = -3.7
unit_price = 12.50
# 科学计数法
light_speed = 3e8 # 3 * 10^8
micro_unit = 5.2e-6 # 0.0000052
精度陷阱——每个开发者都需要了解:
print(0.1 + 0.2) # 0.30000000000000004
这不是 Python 的缺陷,而是 IEEE 754 二进制浮点数标准的固有特性。所有主流语言都存在同样的问题。在需要精确计算(如财务系统)的场景中,应使用 decimal 模块:
from decimal import Decimal
print(Decimal("0.1") + Decimal("0.2")) # 0.3(精确结果)
print(Decimal("19.99") * Decimal("100")) # 1999.00
注意:创建 Decimal 时应传入字符串而非浮点数,Decimal(0.1) 会把浮点数的误差带进去。
运算优先级遵循数学惯例:** > * / // % > + -。不确定优先级时,用括号明确表达意图:
print(3 + 4 * 5) # 23(先乘后加)
print((3 + 4) * 5) # 35(括号优先)
字符串(str)
字符串是文本数据,用引号界定。单引号和双引号效果完全相同:
city = '深圳'
greeting = "Welcome to the platform"
mixed = "It's a valid string" # 双引号内可包含单引号
alt = 'She said: "OK"' # 单引号内可包含双引号
引号内需要嵌入同类引号时,使用转义字符 \:
escaped = 'It\'s a valid string'
print(escaped) # It's a valid string
常用转义字符:
| 转义字符 | 含义 |
|---|---|
\n | 换行 |
\t | 制表符 |
\\ | 反斜杠本身 |
\' | 单引号 |
\" | 双引号 |
在字符串前加 r 可创建原始字符串,跳过所有转义处理:
print('folder\name') # \n 被解释为换行
print(r'folder\name') # 输出:folder\name
多行文本用三引号表示:
sql_template = """
SELECT order_id, amount
FROM transactions
WHERE status = 'completed'
ORDER BY created_at DESC
"""
print(sql_template)
布尔值(bool)
布尔值只有两个:True 和 False(首字母必须大写):
has_permission = True
is_expired = False
# 通常由比较运算产生
print(10 > 5) # True
print(10 < 5) # False
print(10 == 10) # True(双等号表示比较)
print(10 != 7) # True(!= 表示不等于)
# 布尔运算
print(True and False) # False(两者都为 True 才返回 True)
print(True or False) # True(至少一个为 True 即返回 True)
print(not True) # False(取反)
在条件判断中,以下值等价于 False:
0和0.0- 空字符串
"" None- 空容器
[]、{}、()
其余值均等价于 True。
空值(None)
None 是 Python 中表示”无值”的特殊对象。它不等于 0,也不等于空字符串:
pending_result = None
print(pending_result) # None
print(type(pending_result)) # <class 'NoneType'>
print(None == 0) # False
print(None == "") # False
print(None is None) # True
None 常用于表示”变量尚未被赋予有效值”或”函数没有显式返回值”。
类型速查表
| 类型 | 关键字 | 示例 | 典型场景 |
|---|---|---|---|
| 整数 | int | 42, -7, 0 | 计数、索引 |
| 浮点数 | float | 3.14, 1e10 | 测量值、坐标 |
| 字符串 | str | "data", 'log' | 文本处理 |
| 布尔值 | bool | True, False | 逻辑判断 |
| 空值 | NoneType | None | 缺省标记 |
类型转换
不同类型之间有时需要互相转换。Python 提供了一组内置转换函数:
# int() —— 转为整数
print(int(7.89)) # 7(直接截断小数,非四舍五入)
print(int("256")) # 256
print(int(True)) # 1
# float() —— 转为浮点数
print(float(7)) # 7.0
print(float("9.81")) # 9.81
# str() —— 转为字符串
print(str(256)) # "256"
print(str(9.81)) # "9.81"
# bool() —— 转为布尔值
print(bool(0)) # False
print(bool(42)) # True
print(bool("")) # False
print(bool("content")) # True
类型转换在实际场景中非常常见:
# 字符串与数字不能直接拼接
quantity = 5
# print("订购数量:" + quantity) # TypeError
# 需要先将数字转为字符串
print("订购数量:" + str(quantity))
用 type() 函数可以查看任意值的类型:
print(type(42)) # <class 'int'>
print(type(3.14)) # <class 'float'>
print(type("hello")) # <class 'str'>
print(type(True)) # <class 'bool'>
print(type(None)) # <class 'NoneType'>
并非所有转换都合法:
# 以下操作会抛出 ValueError
# int("hello") # 非数字字符串无法转为整数
# int("3.14") # 含小数点的字符串不能直接转为整数
# float("xyz")
# 正确做法:先转 float 再转 int
print(int(float("3.14"))) # 3
字符串处理技术
字符串是程序中使用频率最高的类型之一。Python 为字符串提供了丰富的操作方法。
索引与切片
字符串中每个字符都有一个从 0 开始的位置编号:
domain = "github"
# g i t h u b
# 正向: 0 1 2 3 4 5
# 反向: -6 -5 -4 -3 -2 -1
print(domain[0]) # g
print(domain[5]) # b
print(domain[-1]) # b
print(domain[-3]) # h
切片语法 [start:stop] 提取子串(包含 start,不包含 stop):
domain = "github"
print(domain[0:3]) # "git"
print(domain[3:6]) # "hub"
print(domain[:3]) # "git"(省略 start,从头开始)
print(domain[3:]) # "hub"(省略 stop,到末尾)
print(domain[-3:]) # "hub"
print(domain[:]) # "github"(完整复制)
理解切片的一种方式是想象索引指向字符之间的”缝隙”:
+---+---+---+---+---+---+
| g | i | t | h | u | b |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
常用方法
raw_input = " Welcome To The Platform "
# 大小写转换
print(raw_input.upper()) # " WELCOME TO THE PLATFORM "
print(raw_input.lower()) # " welcome to the platform "
print(raw_input.title()) # " Welcome To The Platform "
# 去除空白
print(raw_input.strip()) # "Welcome To The Platform"
print(raw_input.lstrip()) # "Welcome To The Platform "
print(raw_input.rstrip()) # " Welcome To The Platform"
# 查找与替换
print(raw_input.find("Platform")) # 18
print(raw_input.replace("Platform", "System"))
print(raw_input.count("e")) # 3
# 类型判断
print("python".isalpha()) # True(全部由字母组成)
print("2048".isdigit()) # True(全部由数字组成)
print("abc123".isalnum()) # True(字母或数字组成)
print(" ".isspace()) # True(全部由空白组成)
print("Hello".startswith("He")) # True
print("Hello".endswith("lo")) # True
# 拆分与合并
csv_line = "id,product,price"
fields = csv_line.split(",")
print(fields) # ['id', 'product', 'price']
segments = ['usr', 'local', 'bin']
full_path = "/".join(segments)
print(full_path) # "usr/local/bin"
拼接与重复
protocol = "https"
host = "api.example.com"
url = protocol + "://" + host
print(url) # "https://api.example.com"
separator = "=" * 40
print(separator) # "========================================"
print(len(url)) # 23
字符串格式化
将变量值嵌入字符串的技术称为格式化。Python 提供三种方式。
f-string(推荐,Python 3.6+):
product = "机械键盘"
price_val = 349.5
stock_qty = 120
print(f"商品:{product},单价:{price_val},库存:{stock_qty}")
# 商品:机械键盘,单价:349.5,库存:120
# 表达式嵌入
print(f"折扣价:{price_val * 0.85:.2f}")
# 折扣价:297.08
# 对齐与宽度
for item, cost in [("键盘", 349), ("鼠标", 129), ("显示器", 2499)]:
print(f"{item:8} => {cost:>8d} 元")
format() 方法:
print("{}的库存为{}件".format("键盘", 120))
print("{0}和{1},{1}和{0}".format("键盘", "鼠标"))
print("{product}单价{price}元".format(product="键盘", price=349))
% 格式化(旧式):
print("商品:%s,单价:%d元" % ("键盘", 349))
日常开发中,始终优先使用 f-string——它最简洁、最直观、性能也最优。
字符串的不可变性
Python 中的字符串是不可变对象。一旦创建,无法修改其中的单个字符:
tag = "python"
# tag[0] = "P" # TypeError: 'str' object does not support item assignment
# 需要创建新字符串
tag_upper = "P" + tag[1:]
print(tag_upper) # "Python"
# 或使用 replace 方法
tag_new = tag.replace("p", "P")
print(tag_new) # "Python"
print(tag) # "python"(原字符串不变)
所有字符串操作方法都返回新字符串,不会修改原始对象。
字符编码基础
计算机底层只处理数字,文字需要通过编码方案映射为数值:
- ASCII:最早的标准,128 个字符,仅覆盖英文字母和基本符号
- Unicode:统一编码标准,覆盖全球所有语言的字符
- UTF-8:Unicode 的变长编码实现,是当前互联网的通用编码
Python 3 默认使用 Unicode:
text_cn = "你好世界"
print(len(text_cn)) # 4(按字符计数)
print(ord('A')) # 65
print(ord('Z')) # 90
print(chr(65)) # A
print(chr(9733)) # ★(五角星字符)
输入与输出
print() 进阶
# 输出多个值,默认以空格分隔
print("status", "code", 200)
# status code 200
# 自定义分隔符
print("2026", "03", "12", sep="/")
# 2026/03/12
# 自定义结尾符(默认是换行 \n)
print("loading", end="... ")
print("done")
# loading... done
input() 获取用户输入
input() 从键盘读取一行输入,返回值始终是字符串:
visitor = input("请输入您的姓名:")
print(f"欢迎,{visitor}")
如果需要获取数值,必须进行类型转换:
# 直接使用 input 的返回值做数学运算会报错
# qty = input("数量:")
# total = qty * 10 # TypeError
qty = int(input("数量:"))
unit = float(input("单价:"))
total = qty * unit
print(f"合计:{total:.2f} 元")
综合示例:运费计算器
print("====== 运费计算器 ======")
origin = input("发货城市:")
dest = input("收货城市:")
weight_kg = float(input("包裹重量(kg):"))
base_rate = 8.0
per_kg_rate = 3.0
if weight_kg <= 1:
shipping = base_rate
else:
shipping = base_rate + (weight_kg - 1) * per_kg_rate
print(f"\n从 {origin} 到 {dest}")
print(f"包裹重量:{weight_kg} kg")
print(f"运费合计:{shipping:.2f} 元")
if shipping > 20:
print("提示:运费较高,建议合并寄送")
elif shipping > 10:
print("提示:运费适中")
else:
print("提示:运费经济实惠")
拓展:数值运算的实用技巧
# 使用 divmod() 同时获取商和余数
hours, minutes = divmod(135, 60)
print(f"135 分钟 = {hours} 小时 {minutes} 分钟")
# 135 分钟 = 2 小时 15 分钟
# abs() 取绝对值
temperature_change = -8.5
print(f"温度变化幅度:{abs(temperature_change)} 度")
# max() / min() 取极值
readings = [23.1, 19.8, 27.3, 22.0]
print(f"最高温:{max(readings)},最低温:{min(readings)}")
# 使用下划线作为数字分隔符(提高可读性,不影响值)
budget = 1_000_000
print(budget) # 1000000
本章回顾
| 要点 | 内容 |
|---|---|
| 变量 | 用 = 将值绑定到名称,支持动态类型 |
| 整数 int | 任意精度,支持 + - * / // % ** 运算 |
| 浮点数 float | 带小数点的数值,注意二进制精度限制 |
| 字符串 str | 不可变文本,支持索引、切片、丰富的方法 |
| 布尔值 bool | True / False,用于逻辑判断 |
| 空值 None | 表示无值状态 |
| 类型转换 | int() / float() / str() / bool() |
| 格式化 | 推荐 f-string:f"值为{variable}" |
| 输入输出 | print() 输出 / input() 输入(返回字符串) |
拓展:常用字符串操作速查
在实际项目中,以下操作组合非常常见,值得熟练掌握:
# 检查字符串是否为空
user_input = ""
if not user_input:
print("输入为空")
# 去除前后空白后检查
raw = " "
if not raw.strip():
print("输入仅含空白字符")
# 用 in 判断子串存在
log_line = "ERROR: connection timeout at 14:30"
if "ERROR" in log_line:
print("发现错误日志")
# 字符串的布尔判断
print(bool("")) # False(空字符串)
print(bool("anything")) # True(非空字符串)
# 将数字格式化为带千分位的字符串
revenue = 1234567
print(f"{revenue:,}") # 1,234,567
# 字符串的 center / ljust / rjust 方法
title = "报告"
print(title.center(20, "-")) # ---------报告---------
print(title.ljust(20, ".")) # 报告..................
实践任务
- 创建不同类型的变量,用
type()验证它们的类型 - 使用切片从
"automation"中提取出"auto" - 用 f-string 编写一段包含姓名、年龄和兴趣的自我介绍
- 编写程序,接收用户输入的两个数字,输出它们的和、差、积、商
- 执行
0.1 + 0.2,观察结果并理解浮点精度问题 - 用字符串方法将
"hello WORLD"转换为首字母大写格式"Hello World"
下一章,我们将从一个任务调度场景出发,学习条件判断和循环——让程序具备决策能力和重复执行能力。
购买课程解锁全部内容
零基础到独立开发:Python 自动化与 Web 实战
¥29.90