第二章:变量与数据类型
本章学习目标
- 掌握 Python 变量的声明与使用
- 理解 Python 的基本数据类型(整数、浮点数、布尔、字符串)
- 学会使用 Python 3.10+ 类型提示
- 掌握字符串的常用操作和方法
- 理解类型转换的规则
2.1 变量
2.1.1 什么是变量
变量是计算机内存中用于存储数据值的命名位置。可以把变量想象成一个带有标签的盒子,我们可以在盒子里放入数据(值),并通过标签(变量名)来访问和操作这些数据。
在 Python 中,变量不需要提前声明类型,Python 会根据赋值自动推断类型。这种特性称为动态类型。
2.1.2 变量声明与赋值
# 基本赋值
name = "Alice" # 字符串
age = 25 # 整数
height = 1.65 # 浮点数
is_student = True # 布尔值
2.1.3 多个变量同时赋值
Python 支持多种赋值方式:
# 多个变量同时赋值
x, y, z = 1, 2, 3
print(f"x={x}, y={y}, z={z}") # x=1, y=2, z=3
# 同一值赋给多个变量
a = b = c = 0
print(f"a={a}, b={b}, c={c}") # a=0, b=0, c=0
# 交换变量值
x, y = 1, 2
x, y = y, x # 直接交换,无需临时变量
print(f"x={x}, y={y}") # x=2, y=1
2.1.4 变量命名规则
必须遵循的规则:
- 变量名只能包含字母、数字和下划线(a-z, A-Z, 0-9, _)
- 变量名不能以数字开头
- 变量名不能使用 Python 保留字
保留字(Keywords):
# Python 保留字列表
['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await',
'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except',
'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is',
'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try',
'while', 'with', 'yield']
良好的命名实践:
# ✓ 良好的命名
user_name = "Alice"
max_value = 100
is_active = True
calculate_sum = lambda x, y: x + y
# ✗ 不推荐的命名
n = "Alice" # 名称过于简略
userName = "Alice" # 应使用 snake_case
UserName = "Alice" # 类名风格
MYNAME = "Alice" # 常量风格
_private = "secret" # 下划线开头通常表示私有
__magic = "value" # 双下划线有特殊含义
2.1.5 变量类型查看
# 使用 type() 查看变量类型
name = "Alice"
age = 25
height = 1.65
is_student = True
print(type(name)) # <class 'str'>
print(type(age)) # <class 'int'>
print(type(height)) # <class 'float'>
print(type(is_student)) # <class 'bool'>
2.2 类型提示 (Type Hints)
2.2.1 什么是类型提示
类型提示(Type Hints)是 Python 3.5+ 引入的特性,3.10+ 进一步增强了语法。类型提示不会影响程序运行,但可以:
- 提高代码可读性
- 帮助 IDE 提供更好的自动补全
- 配合类型检查器发现潜在错误
- 生成代码文档
# 没有类型提示
def greet(name):
return "Hello, " + name
# 有类型提示
def greet(name: str) -> str:
return f"Hello, {name}!"
2.2.2 基本类型提示
# 变量类型提示
name: str = "Alice"
age: int = 25
height: float = 1.65
is_active: bool = True
# 函数类型提示
def add(a: int, b: int) -> int:
return a + b
# 没有返回值的函数
def print_message(message: str) -> None:
print(message)
2.2.3 联合类型 (Python 3.10+ 新语法)
在 Python 3.10 之前,使用 Union 需要导入 typing 模块:
# Python 3.9 及之前
from typing import Union
user_id: Union[int, str] = 12345
# Python 3.10+ 推荐语法
user_id: int | str = 12345
2.2.4 Optional 类型
# Python 3.9 及之前
from typing import Optional
name: Optional[str] = None
# Python 3.10+ 推荐语法
name: str | None = None
2.2.5 容器类型提示
# 列表
numbers: list[int] = [1, 2, 3, 4, 5]
names: list[str] = ["Alice", "Bob"]
# 字典
person: dict[str, str | int] = {
"name": "Alice",
"age": 25,
"city": "Beijing"
}
# 元组(固定长度)
point: tuple[int, int] = (10, 20)
rgb: tuple[int, int, int] = (255, 128, 0)
# 元组(可变长度)
coordinates: tuple[int, ...] = (1, 2, 3, 4, 5)
# 集合
unique_numbers: set[int] = {1, 2, 3}
# 冻结集合
immutable_set: frozenset[str] = frozenset(["a", "b", "c"])
2.2.6 Any 类型
from typing import Any
# 任意类型
def process(data: Any) -> Any:
return data
2.2.7 类型别名
# 简单的类型别名
Point = tuple[float, float]
Vector = list[float]
Matrix = list[list[float]]
# 使用类型别名
def distance(p1: Point, p2: Point) -> float:
"""计算两点之间的距离"""
import math
return math.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)
# 使用
p1: Point = (0.0, 0.0)
p2: Point = (3.0, 4.0)
result: float = distance(p1, p2) # 5.0
2.2.8 Callable 类型(函数类型)
from collections.abc import Callable
# 函数作为参数
def apply(func: Callable[[int], int], value: int) -> int:
"""应用函数到值"""
return func(value)
def double(x: int) -> int:
return x * 2
result: int = apply(double, 5) # 10
# 返回函数
def create_multiplier(factor: int) -> Callable[[int], int]:
"""创建乘法函数"""
def multiplier(x: int) -> int:
return x * factor
return multiplier
double: Callable[[int], int] = create_multiplier(2)
triple: Callable[[int], int] = create_multiplier(3)
print(double(5)) # 10
print(triple(5)) # 15
2.3 基本数据类型
2.3.1 整数 (int)
整数类型表示没有小数部分的数值。
# 基本整数
positive: int = 42
negative: int = -17
zero: int = 0
# 不同进制的表示
binary: int = 0b1010 # 二进制: 10
octal: int = 0o12 # 八进制: 10 (1*8 + 2 = 10)
hexadecimal: int = 0xA # 十六进制: 10 (10*16^0 = 10)
# 大整数(Python 支持任意精度)
big_number: int = 10**100 # googol (1 后面 100 个 0)
# 整数运算
a, b = 10, 3
result: int = a + b # 加法: 13
result: int = a - b # 减法: 7
result: int = a * b # 乘法: 30
result: float = a / b # 浮点除法: 3.333...
result: int = a // b # 整数除法: 3
result: int = a % b # 取余: 1
result: int = a ** b # 幂运算: 1000
result: int = abs(-5) # 绝对值: 5
# 整数方法
print((42).bit_length()) # 6 (42 的二进制表示需要 6 位)
print((-42).bit_length()) # 6
2.3.2 浮点数 (float)
浮点数表示带小数部分的数值。
# 基本浮点数
positive: float = 3.14
negative: float = -2.5
zero: float = 0.0
# 科学计数法
large: float = 1.5e10 # 1.5 × 10^10 = 15000000000.0
small: float = 1.5e-10 # 1.5 × 10^-10 = 0.00000000015
# 浮点数精度问题
result: float = 0.1 + 0.2
print(result) # 0.30000000000000004
# 避免精度问题
from decimal import Decimal, getcontext
# 设置精度
getcontext().prec = 10
result: Decimal = Decimal("0.1") + Decimal("0.2")
print(result) # 0.3
# 浮点数方法
print(3.14.is_integer()) # False
print((3.0).is_integer()) # True
print(3.14.as_integer_ratio()) # (157, 50) = 157/50
print(3.14.hex()) # 0x1.91eb851eb851fp+1
2.3.3 复数 (complex)
Python 原生支持复数运算。
# 复数表示
c1: complex = 3 + 4j
c2: complex = 1 - 2j
# 复数运算
result: complex = c1 + c2 # 4 + 2j
result: complex = c1 - c2 # 2 + 6j
result: complex = c1 * c2 # 11 - 2j
result: complex = c1 / c2 # (-1+2j)
# 复数属性
print(c1.real) # 3.0 (实部)
print(c1.imag) # 4.0 (虚部)
print(c1.conjugate()) # (3-4j) (共轭复数)
# 复数的模
import cmath
print(abs(c1)) # 5.0 (模)
print(cmath.phase(c1)) # 0.9272952180016122 (幅角)
2.3.4 布尔类型 (bool)
布尔类型只有两个值:True 和 False。
# 布尔值
is_active: bool = True
is_deleted: bool = False
# 布尔转换
# 以下值在布尔上下文中被视为 False
bool(0) # False
bool(0.0) # False
bool("") # False
bool([]) # False (空列表)
bool(()) # False (空元组)
bool({}) # False (空字典)
bool(None) # False
# 以下值被视为 True
bool(1) # True
bool(-1) # True
bool("hello") # True
bool([1, 2]) # True
bool({"a": 1}) # True
bool("False") # True (非空字符串)
# 布尔运算
result: bool = True and False # False (与)
result: bool = True or False # True (或)
result: bool = not True # False (非)
# 短路求值
result = False and (1 / 0) # False,不执行除法
result = True or (1 / 0) # True,不执行除法
# 实际应用
name: str = ""
display_name: str = name or "匿名用户" # "匿名用户"
score: int = 85
passed: bool = score >= 60
2.4 字符串
2.4.1 字符串创建
# 单引号
s1: str = 'Hello'
# 双引号
s2: str = "Hello"
# 三引号(多行字符串)
s3: str = """这是一个
多行字符串"""
s4: str = '''也可以
使用单引号'''
# 转义字符
path: str = "C:\\Users\\Admin" # C:\Users\Admin
newline: str = "第一行\n第二行"
# 原始字符串
path_raw: str = r"C:\Users\Admin" # C:\Users\Admin
# 空字符串
empty: str = ""
2.4.2 字符串索引和切片
字符串是有序的字符序列,支持索引访问。
s: str = "Python"
# 索引访问(从 0 开始)
print(s[0]) # 'P' 第一个字符
print(s[1]) # 'y' 第二个字符
print(s[-1]) # 'n' 最后一个字符
print(s[-2]) # 'o' 倒数第二个字符
# 切片 [start:stop:step]
print(s[0:3]) # 'Pyt' 索引 0, 1, 2
print(s[2:]) # 'thon' 从索引 2 到末尾
print(s[:3]) # 'Pyt' 从开头到索引 2
print(s[::2]) # 'Pto' 步长为 2
print(s[::-1]) # 'nohtyP' 反转字符串
# 切片越界不会报错
print(s[0:100]) # 'Python'
print(s[100:]) # ''
# 负数索引
print(s[-3:-1]) # 'ho' 倒数第3到倒数第1(不含)
2.4.3 字符串方法
text: str = " Hello, Python! "
# 大小写转换
print(text.upper()) # " HELLO, PYTHON! "
print(text.lower()) # " hello, python! "
print(text.capitalize()) # " hello, python! " (首字母大写)
print(text.title()) # " Hello, Python! " (每个单词首字母大写)
print(text.swapcase()) # " hELLO, pYTHON! "
# 查找和替换
print(text.find("Python")) # 9 找不到返回 -1
print(text.index("Python")) # 9 找不到抛出 ValueError
print(text.count("o")) # 2
print(text.replace("Python", "World")) # " Hello, World! "
print(text.strip()) # "Hello, Python!" 去除两端空白
print(text.lstrip()) # "Hello, Python! " 去除左端
print(text.rstrip()) # " Hello, Python!" 去除右端
# 分割和连接
sentence: str = "苹果,香蕉,橙子"
parts: list[str] = sentence.split(",") # ['苹果', '香蕉', '橙子']
print(",".join(parts)) # "苹果,香蕉,橙子"
lines: str = "第一行\n第二行\n第三行"
line_list: list[str] = lines.splitlines() # ['第一行', '第二行', '第三行']
# 判断
print(text.startswith(" He")) # True
print(text.endswith("! ")) # True
print("123".isdigit()) # True (全是数字)
print("abc".isalpha()) # True (全是字母)
print("abc123".isalnum()) # True (字母数字混合)
print("hello".islower()) # True
print("HELLO".isupper()) # True
print("Hello".istitle()) # True
# 格式化
name: str = "Alice"
age: int = 25
# f-string (推荐)
result: str = f"我叫{name},今年{age}岁"
# format 方法
result = "我叫{},今年{}岁".format(name, age)
result = "我叫{0},今年{1}岁".format(name, age)
result = "我叫{name},今年{age}岁".format(name=name, age=age)
# 填充和对齐
print(f"{'hello':<10}") # 'hello ' 左对齐
print(f"{'hello':>10}") # ' hello' 右对齐
print(f"{'hello':^10}") # ' hello ' 居中
print(f"{42:05d}") # '00042' 数字填充
print(f"{3.14:.2f}") # '3.14' 浮点数格式
# 字符串编码
utf8_bytes: bytes = "你好".encode("utf-8") # b'\xe4\xbd\xa0\xe5\xa5\xbd'
decoded: str = utf8_bytes.decode("utf-8") # "你好"
2.4.4 字符串格式化进阶
# 数字格式
value: int = 42
print(f"{value:b}") # 二进制: '101010'
print(f"{value:o}") # 八进制: '52'
print(f"{value:d}") # 十进制: '42'
print(f"{value:x}") # 十六进制: '2a'
# 浮点数格式
pi: float = 3.1415926
print(f"{pi:.2f}") # '3.14'
print(f"{pi:.4f}") # '3.1416'
print(f"{pi:e}") # '3.141593e+00'
# 百分比
percent: float = 0.75
print(f"{percent:.1%}") # '75.0%'
# 千位分隔符
num: int = 1234567
print(f"{num:,}") # '1,234,567'
2.5 类型转换
2.5.1 隐式类型转换
Python 自动进行一些类型转换:
# 整数和浮点数运算,结果为浮点数
result: float = 10 + 3.5 # 13.5
# 布尔值和数值运算
result: int = True + 5 # 6 (True = 1)
result: int = False + 5 # 5 (False = 0)
2.5.2 显式类型转换
# 字符串转整数
int("123") # 123
int(" 42 ") # 42 (自动去除空白)
int("1010", 2) # 10 (二进制)
int("FF", 16) # 255 (十六进制)
# 字符串转浮点数
float("3.14") # 3.14
float("1e10") # 10000000000.0
float(" 2.5 ") # 2.5
# 数值转字符串
str(123) # '123'
str(3.14) # '3.14'
# 整数与浮点数转换
int(3.7) # 3 (截断)
float(3) # 3.0
# 进制转换
bin(10) # '0b1010'
oct(10) # '0o12'
hex(10) # '0xa'
2.5.3 eval() 函数
eval() 可以执行字符串中的 Python 表达式(谨慎使用):
result = eval("1 + 2 * 3") # 7
result = eval("[1, 2, 3]") # [1, 2, 3]
# 警告:eval 有安全风险,不要处理用户输入
2.6 常量约定
虽然 Python 没有真正的常量,但约定使用全大写表示不应修改的值:
# 常量约定
MAX_CONNECTIONS: int = 100
DEFAULT_TIMEOUT: float = 30.0
API_BASE_URL: str = "https://api.example.com"
# 常量集合
DAYS_OF_WEEK: tuple[str, ...] = ("Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday", "Sunday")
# Python 中常量实际上可以被修改,但约定不应修改
# 如果需要真正不可变的常量,可以使用 dataclasses 或枚举
最佳实践
- 使用类型提示:提高代码可读性和可维护性
- 优先使用 f-string:性能更好,语法更简洁
- 避免使用 eval():存在安全风险
- 使用
is None而非== None:符合 Python 惯例
# ✓ 推荐
if name is not None:
print(f"Hello, {name}")
# ✗ 不推荐
if name != None:
print(f"Hello, {name}")
- 字符串优先使用 strip():处理用户输入时去除空白
user_input: str = " hello "
clean_input: str = user_input.strip()
课后练习
练习 2.1:变量声明
声明以下变量并添加适当的类型提示:
- 你的名字(字符串)
- 你的年龄(整数)
- 你的身高(浮点数)
- 是否是学生(布尔值)
练习 2.2:变量操作
- 交换两个变量的值(不使用临时变量)
- 使用多个变量同时赋值计算:已知圆柱体的半径 r=5,高 h=10,计算体积
练习 2.3:类型提示练习
为以下函数添加类型提示:
def calculate_area(base, height):
return 0.5 * base * height
练习 2.4:字符串操作
给定字符串 "Python 3.10 is awesome",实现:
- 统计字符串长度
- 将字符串转为大写
- 提取 "Python" 子串
- 替换 "awesome" 为 "amazing"
- 计算 "o" 出现的次数
练习 2.5:温度转换
编写一个程序,实现摄氏温度转华氏温度:
- 公式:F = C × 9/5 + 32
- 要求用户输入摄氏温度,输出华氏温度
练习 2.6:格式化输出
使用 f-string 格式化输出以下信息: ```
学生信息卡
================================ 姓名: Alice 学号: 001 成绩: 95.5
### 练习 2.7:类型转换
编写一个程序,实现:
1. 将字符串 "123.45" 转换为浮点数
2. 将浮点数 98.6 转换为字符串
3. 将整数 255 转换为十六进制字符串
### 练习 2.8:高级字符串
编写一个函数,检查一个字符串是否是回文(正读和倒读相同):
- 例如:"aba" 是回文
- 例如:"hello" 不是回文
## 本章小结
本章我们学习了:
- 变量的声明、赋值和命名规则
- Python 3.10+ 类型提示语法
- 基本数据类型:整数、浮点数、复数、布尔
- 字符串的创建、索引、切片和方法
- 类型转换的规则
在下一章中,我们将学习流程控制语句,包括条件语句和 match-case 结构化模式匹配。
## 相关资源
- [Python 类型提示文档](https://docs.python.org/3/library/typing.html)
- [mypy 类型检查器](https://mypy.readthedocs.io/)
- [Python 字符串方法](https://docs.python.org/3/library/stdtypes.html#string-methods)
- [PEP 484 - 类型提示](https://peps.python.org/pep-0484/)