跳到主要内容
预计阅读 31 分钟

02|用变量和类型系统管理项目数据

场景引入:客户信息登记表

假设你正在为一个社区活动搭建报名系统。每位参与者需要录入姓名、年龄、联系方式、是否为会员等信息。这些信息各不相同——有的是文字,有的是数字,有的是”是或否”。如何在程序中表达并管理这些多样化的数据?

这就引出了两个基础问题:

  1. 怎样在程序中为数据命名并引用它?——变量
  2. 程序如何区分”文字”和”数字”这类不同性质的数据?——数据类型

变量:给数据贴上标签

在 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 保留关键字(如 ifforclass
  • 区分大小写:Totaltotal 是两个不同的变量

推荐遵守:

  • 使用有描述性的名称: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)

布尔值只有两个:TrueFalse(首字母必须大写):

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

  • 00.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 常用于表示”变量尚未被赋予有效值”或”函数没有显式返回值”。

类型速查表

类型关键字示例典型场景
整数int42, -7, 0计数、索引
浮点数float3.14, 1e10测量值、坐标
字符串str"data", 'log'文本处理
布尔值boolTrue, False逻辑判断
空值NoneTypeNone缺省标记

类型转换

不同类型之间有时需要互相转换。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("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不可变文本,支持索引、切片、丰富的方法
布尔值 boolTrue / 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, "."))     # 报告..................

实践任务

  1. 创建不同类型的变量,用 type() 验证它们的类型
  2. 使用切片从 "automation" 中提取出 "auto"
  3. 用 f-string 编写一段包含姓名、年龄和兴趣的自我介绍
  4. 编写程序,接收用户输入的两个数字,输出它们的和、差、积、商
  5. 执行 0.1 + 0.2,观察结果并理解浮点精度问题
  6. 用字符串方法将 "hello WORLD" 转换为首字母大写格式 "Hello World"

下一章,我们将从一个任务调度场景出发,学习条件判断和循环——让程序具备决策能力和重复执行能力。

购买课程解锁全部内容

零基础到独立开发:Python 自动化与 Web 实战

¥29.90