跳到主要内容

人工智能的定义是:让计算机去做人类需要智慧才能做的事。

Peter NorvigAI 研究者

📝 变量与数据类型

变量是程序中存储数据的容器,类似于贴在数据上的"标签"。Python 的变量机制相当灵活:同一个变量可以在不同时刻引用不同类型的对象。本节涵盖变量命名规则、赋值方式、内置基本数据类型,以及类型注解的基础用法。

Python 的变量为什么能这么灵活?答案在于它的动态类型机制——变量本身不携带类型信息,类型属于对象。接下来从命名规则开始。

📌 本节要点

  • 变量命名规则与 PEP 8 推荐风格
  • 动态类型:变量无类型,对象才有类型
  • type()isinstance() 查看与判断类型
  • 6 种基本数据类型:int、float、complex、str、bool、NoneType
  • 多重赋值与解包赋值(含星号 * 收集)
  • Python 3.10+ 类型注解基础:int | strlist[str]

变量命名规则

Python 变量命名有以下约束:

  • 只能由字母、数字、下划线组成
  • 不能以数字开头
  • 区分大小写(ageAge 是不同的变量)
  • 不能使用 Python 关键字(如 ifforclass 等)
Python
# 合法命名
name = "Alice"
user_age = 18
_private = "秘密"
student2 = "Bob"
userName = "Charlie" # 驼峰命名(Python 中更推荐下划线命名 snake_case)

# 非法命名(取消注释会报错)
# 2user = "Tom" # 不能以数字开头
# user-name = "Tom" # 不能包含连字符
# for = 10 # 不能使用关键字
推荐的命名风格

Python 官方风格指南 PEP 8 推荐使用 snake_case(下划线小写)命名变量与函数,如 user_agemax_count;类名使用 CamelCase(如 MyClass);常量使用全大写(如 MAX_VALUE)。

查看所有关键字

keyword 模块可以列出 Python 的全部保留关键字:

Python
import keyword

print(keyword.kwlist)
# ['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', ...]

print(len(keyword.kwlist)) # 当前关键字数量

动态类型

Python 是动态类型语言,意味着变量可以随时改变"身份"。

Python
x = 10 # x 现在是一个整数
print(type(x)) # <class 'int'>

x = "hello" # 现在 x 变成了字符串
print(type(x)) # <class 'str'>

x = [1, 2, 3] # 现在 x 变成了列表
print(type(x)) # <class 'list'>
关键概念:变量 vs 对象

Python 中,变量没有类型,对象才有类型。变量只是一个标签,可以随时绑定到不同类型的对象上。

Python 的类型系统

Python 的类型系统可以从两个维度来理解:类型检查时机(静态 vs 动态)和类型转换规则(强 vs 弱)。为什么需要理解这两个维度?因为它们决定了代码的行为方式和错误暴露时机。

静态类型 vs 动态类型

这个维度回答:类型信息在什么时候确定?

静态类型(Java、C、Rust):变量声明时必须指定类型,编译器在编译阶段就检查类型是否匹配,运行时不能改变。

Python
# Java 等静态类型语言(伪代码对比)
# int x = 10; // 声明 x 为 int
# x = "hello"; // ❌ 编译错误:不能把 str 赋给 int 变量

动态类型(Python、Ruby、JavaScript):变量不需要声明类型,类型在运行时根据赋值自动确定,同一变量可以随时引用不同类型的对象。

Python
x = 10 # x 引用 int
x = "hello" # ✅ 合法,x 现在引用 str
x = [1, 2, 3] # ✅ 合法,x 现在引用 list
为什么 Python 选择动态类型?

动态类型让代码更简洁——不需要写类型声明,快速迭代时非常方便。代价是类型错误要到运行时才会暴露。Python 3.5+ 引入的类型注解(Type Hints)让我们可以选择性地添加类型信息,兼顾灵活性和安全性。

强类型 vs 弱类型

这个维度回答另一个问题:不同类型混用时会发生什么?

强类型(Python、Java、Rust):不同类型之间不会进行隐式转换,混用直接报错。

Python
"1" + 1 # TypeError: can only concatenate str to str (not "int")
"1" * 3 # "111" — 合法,因为 str * int 是 Python 明确定义的操作

弱类型(JavaScript、Perl、PHP):引擎会自动进行隐式类型转换,结果往往出人意料。

// JavaScript(弱类型)
"1" + 1 // "11" — 数字被隐式转为字符串
"1" - 1 // 0 — 字符串被隐式转为数字
true + 1 // 2 — 布尔值被隐式转为数字
隐式转换的陷阱

弱类型的隐式转换是大量 bug 的根源。"1" + 1 在 JavaScript 中得到 "11" 而不是 2,这种行为很容易造成困惑。Python 的强类型策略让这类错误在运行时立即暴露,而不是悄悄产生错误结果。

四象限总览

把两个维度组合起来,编程语言可以分成四类:

强类型弱类型
静态类型Java、Rust、Go、C#C(隐式指针转换)、Go(部分隐式转换)
动态类型Python、Ruby、HaskellJavaScript、Perl、PHP

Python 的定位:动态 + 强类型。 这意味着:

  • 变量不需要声明类型(动态)
  • 但不同类型不能隐式混用(强)

Python 的有限例外

Python 虽然是强类型,但有一些基于继承关系的隐式行为,这不是"弱类型转换",而是面向对象的设计:

Python
# bool 是 int 的子类
True + 1 # 2(布尔值参与整数运算)
isinstance(True, int) # True

0 == False # True
1 == True # True
"" == False # True(空字符串等于 False)

# 这些是继承关系带来的行为,不是隐式类型转换
# bool 本质上就是 int 的特殊子类,True 就是 1,False 就是 0

渐进式类型注解

Python 独特的组合是:动态 + 强类型 + 可选类型注解。这三个特性各解决不同的问题:

Python
# 动态:变量可以换类型
x = 10
x = "hello" # 合法

# 强类型:不同类型不能混用
# "1" + 1 # TypeError

# 可选注解:添加类型提示(不影响运行)
def greet(name: str) -> str:
return f"Hello, {name}"

# 类型注解不改变运行行为,只是给 IDE 和 mypy 看的
greet(123) # 运行时不报错,但 mypy 会警告

对比其他语言的组合:

  • Java:静态 + 强类型 — 必须声明类型,不能混用,灵活度低但安全性高
  • JavaScript:动态 + 弱类型 — 不声明类型,还能隐式转换,灵活度最高但 bug 最多
  • Python:动态 + 强类型 + 可选注解 — 兼顾灵活性和安全性,是独特的"中间路线"

使用 type() 查看类型

查看对象类型最直接的方式是 type()

Python
print(type(42)) # <class 'int'>
print(type(3.14)) # <class 'float'>
print(type("Python")) # <class 'str'>
print(type(True)) # <class 'bool'>
print(type(None)) # <class 'NoneType'>

如果要做"类型判断",推荐使用 isinstance() 而不是直接比较 type()

Python
x = 5

# ❌ 不推荐:不支持子类判断
print(type(x) == int) # 输出: True

# ✅ 推荐:支持继承关系判断
print(isinstance(x, int)) # 输出: True

# isinstance 支持传入元组判断多种类型
print(isinstance(x, (int, float, str))) # 输出: True
核心概念:isinstance vs type
场景推荐 ✅不推荐 ❌
类型判断isinstance(x, int)type(x) == int
多类型判断isinstance(x, (int, str))type(x) in (int, str)
空值检查x is Nonex == None

isinstance() 会考虑继承关系,例如 True 既是 bool 也是 int 的实例(boolint 的子类);而 type(True) == int 返回 False。一般做类型判断时优先用 isinstance()

基本数据类型总览

Python 内置了6种基本数据类型,各司其职:

类型名类型示例
int整数42, 0, -7, 1_000_000
float浮点数3.14, -0.5, 2.0
complex复数1+2j, 3j
str字符串"hello", 'a'
bool布尔值True, False
NoneType空值None
Python
age = 25 # int
height = 1.75 # float
name = "Alice" # str
is_student = True # bool
result = None # NoneType

print(age, height, name, is_student, result)
# 输出: 25 1.75 Alice True None

print(type(age), type(height), type(name), type(is_student), type(result))
# 输出: <class 'int'> <class 'float'> <class 'str'> <class 'bool'> <class 'NoneType'>
数字下划线分隔

Python 3.6+ 支持在数字字面量中使用下划线作为分隔符,提高大数字的可读性:1_000_000 等价于 10000000xFF_FF 等价于 0xFFFF

多重赋值

Python 支持在一行内为多个变量同时赋值,这是非常实用的特性,尤其在交换变量值时格外方便:

Python
# 同时给多个变量赋值
a, b, c = 1, 2, 3
print(a, b, c) # 输出: 1 2 3

# 交换两个变量的值(无需中间变量)
a, b = b, a
print(a, b) # 输出: 2 1

# 给多个变量赋同一个值
x = y = z = 0
print(x, y, z) # 输出: 0 0 0
多重赋值数量必须一致

多重赋值要求左右两侧的元素数量一致,否则会抛出 ValueError

Python
a, b = 1, 2, 3 # ValueError: too many values to unpack

解包赋值

解包(unpacking)是 Python 中非常优雅的特性,可以从任何可迭代对象中提取元素赋给多个变量。这种语法在处理函数返回值和数据结构时特别常用。

列表/元组解包

Python
point = (3, 4)
x, y = point
print(x, y) # 3 4

colors = ["red", "green", "blue"]
r, g, b = colors
print(r, g, b) # red green blue

星号解包(*)

使用 * 可以收集剩余的元素为一个列表:

Python
first, *rest = [1, 2, 3, 4, 5]
print(first) # 1
print(rest) # [2, 3, 4, 5]

*head, last = [1, 2, 3, 4, 5]
print(head) # [1, 2, 3, 4]
print(last) # 5

first, *middle, last = [1, 2, 3, 4, 5]
print(first, middle, last) # 1 [2, 3, 4] 5

函数返回值解包

Python
def get_user_info():
return "Alice", 25, "Beijing"

name, age, city = get_user_info()
print(name, age, city) # Alice 25 Beijing

类型注解基础

Python 依然是动态类型语言,但支持类型注解(Type Hints)——给变量贴上"我是数字"、"我是字符串"之类的标签。这些标签不会影响程序运行,但能让 IDE 和 mypy 等工具更好地理解代码意图。

变量类型注解

Python
# 基本写法:变量名: 类型 = 值
name: str = "Alice"
age: int = 25
height: float = 1.75
is_active: bool = True

# 类型注解只是"提示",运行时仍可赋其他类型(但会被检查工具警告)
name = 123 # 运行不会报错,但 mypy 会警告
print(name)
类型注解不会强制运行时检查

类型注解不会在运行时强制校验类型,它只是给开发者和工具看的"说明"。要让类型真正被校验,需要使用 mypy 等静态检查工具。

Python 3.10+ 的联合类型语法

Python
# Python 3.10+:使用 | 表示"或"类型
def process(value: int | str) -> str:
return f"处理: {value}"

print(process(42)) # 处理: 42
print(process("hello")) # 处理: hello

# 列表类型注解
from typing import Optional

def find_user(user_id: int) -> str | None:
if user_id == 1:
return "Alice"
return None

result: str | None = find_user(2)
print(result) # None

容器类型注解

Python
from typing import Sequence

# 使用内置 list/dict/tuple/set 类型注解(Python 3.9+)
names: list[str] = ["Alice", "Bob"]
scores: dict[str, int] = {"Alice": 90, "Bob": 85}
point: tuple[int, int] = (3, 4)
unique_ids: set[int] = {1, 2, 3}

print(names, scores, point, unique_ids)

实战:个人信息卡片

综合示例,将本节涉及的变量、多类型、解包与类型注解融合在一起:

Python
def build_profile(name: str, age: int, height: float, tags: list[str]) -> dict:
"""构建用户信息字典"""
return {
"name": name,
"age": age,
"height": height,
"tags": tags,
"adult": age >= 18,
}


# 解包函数返回值
profile: dict = build_profile(
name="Alice",
age=25,
height=1.68,
tags=["python", "music"],
)

# 多重赋值 + 解包
name, age = profile["name"], profile["age"]
print(f"姓名: {name}, 年龄: {age}")

# 星号解包
*_, last_tag = profile["tags"]
print(f"最后一个标签: {last_tag}")

# 类型检查
print(f"profile 类型: {type(profile).__name__}")
print(f"age 是 int 吗: {isinstance(age, int)}")

运行结果:

输出
姓名: Alice, 年龄: 25
最后一个标签: music
profile 类型: dict
age 是 int 吗: True

🎯 动手练习

以下练习有助于巩固本节内容:

  1. 命名规则验证:尝试使用非法命名(如 2useruser-namefor),观察 Python 的错误提示
  2. 类型探索:使用 type() 查看以下值的类型:00.0""[]{}set()
  3. 解包练习:创建一个包含 5 个元素的列表,使用星号解包分别获取第一个、中间三个、最后一个元素
  4. 类型注解实践:编写一个函数 calculate(a: int | float, b: int | float) -> int | float,实现加减乘除运算
变量类型探索

📚 延伸阅读

📋速查表
name = value变量赋值
age = 25
a, b = b, a交换变量
x, y = y, x
first, *rest = lst星号解包
1, [2,3,4,5]
x: int = 10类型注解
name: str = "Alice"
`int \str`
联合类型
list[str]泛型容器
names: list[str] = []
isinstance(x, T)类型判断
isinstance(x, int)
type(x)查看类型
type(42) # <class 'int'>

✅ 本节总结

  • Python 变量命名只能用字母、数字、下划线,且不能以数字开头,不能与关键字冲突
  • Python 是动态类型语言:变量没有类型,对象才有类型;可用 type() 查看,用 isinstance() 判断
  • 基本数据类型包括 intfloatcomplexstrboolNoneType
  • 支持多重赋值解包赋值(含星号 * 收集),让代码更简洁
  • Python 3.10+ 的类型注解(如 int | strlist[str])能显著提升代码可读性,配合 mypy 等工具可实现静态类型检查