变量是编程的第一块砖。写程序其实就是”用变量装数据,让数据流动”的过程。上一篇 第一个 Python 程序 里我们已经悄悄用过变量了(name = "咖飞")。这一篇我们要正式讲清楚:Python 的变量到底是什么?有哪些基本数据类型?为什么 Python 是”动态类型”?以及一堆新手容易翻车的细节。学完这一篇,你写的代码就能装东西了。
一、变量到底是什么
在 C 语言里,变量是”一块贴了标签的内存”;在 Python 里,思维要反过来——变量是贴在对象上的标签。
1 | name = "咖飞" |
这一行代码干了三件事:
- 内存里创建了一个字符串对象
"咖飞"; - 定义了一个叫
name的名字; - 让
name指向那个对象。
所以 Python 的赋值不是”把值放进变量”,而是”把标签贴到对象上”。这个模型很重要,理解它可以省掉后面 80% 的困惑。
来看一段能证明这个观点的代码:
1 | a = [1, 2, 3] |
如果按”变量是盒子”的模型,你会觉得 b = a 是复制一份,改 b 不影响 a。但按”变量是标签”的模型,就一目了然:两个标签贴在同一件行李上,动一个另一个当然跟着变。
二、变量命名规则与惯例
Python 变量命名规则:
- 由字母、数字、下划线组成;
- 不能以数字开头;
- 不能与关键字冲突(如
if、for、class、True等); - 区分大小写:
age和Age是两个不同的变量; - 支持 Unicode,
名字 = "咖飞"也合法,但不推荐。
命名风格惯例(PEP 8):
- 普通变量、函数:
snake_case(小写下划线),如user_name; - 常量:
UPPER_CASE,如MAX_RETRY; - 类名:
PascalCase,如UserAccount; - “私有”变量:前缀单下划线,如
_internal; - 避免用单字符(除了
i、j之类循环变量); - 变量名要有意义——
d = 86400不如seconds_per_day = 86400。
1 | # 好 |
三、基本数据类型总览
Python 内置基本类型有 6 大类:
| 类型 | 关键字 | 举例 | 说明 |
|---|---|---|---|
| 整数 | int | 42, -7, 0, 10_000 |
任意精度整数 |
| 浮点数 | float | 3.14, 1e5, -0.5 |
双精度浮点 |
| 字符串 | str | "hi", '咖飞', """...""" |
不可变的字符序列 |
| 布尔 | bool | True, False |
int 的子类 |
| 空值 | None | None |
表示”没有值” |
| 复数 | complex | 1+2j |
一般用不到,本文只提一下 |
先只讲前 5 个,复数遇到再说。
四、int:整数
Python 3 的整数是”任意精度”,不用担心溢出:
1 | big = 2 ** 128 |
支持不同进制字面量:
1 | dec = 255 # 十进制 |
Python 3.6+ 允许下划线做视觉分隔:
1 | population = 1_400_000_000 # 十四亿 |
五、float:浮点数
浮点数用双精度 IEEE 754,注意精度问题:
1 | print(0.1 + 0.2) # 0.30000000000000004,不是 0.3! |
这不是 Python 的 bug,而是所有基于 IEEE 754 的语言的通病。结论:不要用 == 比较浮点数。要用容差:
1 | import math |
或者对财务/金额场景,用 decimal 模块:
1 | from decimal import Decimal |
科学计数法也可以:
1 | c = 3e8 # 3 * 10^8,光速 |
六、str:字符串
字符串是 Python 里最常用的类型之一:
1 | s1 = "双引号" |
字符串支持”加法”(拼接)和”乘法”(重复):
1 | print("ab" + "cd") # abcd |
字符串是不可变的——你不能修改一个已有字符串的某一位:
1 | s = "hello" |
关于字符串还有更多内容,我们会在 字符串基础与常用方法 单独讲。
七、bool:布尔
True 和 False,注意首字母大写。它们其实是 int 的子类:
1 | print(True + True) # 2,True 相当于 1 |
Python 里的真值判断很宽松,以下都被视为”假”:
FalseNone0、0.0、0j- 空字符串
""、空列表[]、空字典{}、空集合set()、空元组()
其他一切都是”真”。所以:
1 | if items: # items 非空就为真,简洁又 Pythonic |
八、None:什么都不是
None 表示”没有值”,函数没有 return 时默认返回 None:
1 | def do_nothing(): |
判断 None 用 is,不要用 ==:is 判断”是不是同一个对象”,None 全局只有一个;== 是”值相等”,可能被自定义类重写而产生意外行为。
九、类型转换
Python 支持显式类型转换:
1 | # 数字与字符串 |
陷阱:int("3.14") 会报错,因为 "3.14" 不是合法整数字符串。要先转成 float 再转 int:int(float("3.14")) 得到 3。
十、type 与 isinstance
想知道一个变量是什么类型:
1 | x = 42 |
isinstance 比 type == ... 更好,因为它支持继承关系(比如 isinstance(True, int) 是 True)。
十一、动态类型 vs 静态类型
Python 是动态类型语言:
1 | x = 1 # 现在 x 是 int |
这三行代码都合法。同一个变量名可以贴到不同类型的对象上,非常灵活,但也带来风险:代码一多,你不知道某个变量此刻到底是什么类型。因此 Python 3.5+ 引入了 类型注解:
1 | name: str = "咖飞" |
注解不改变运行时行为(Python 不会真的检查类型),只是给 IDE 和静态检查工具 mypy 看的。养成写类型注解的习惯,能省下大量调试时间。
十二、常见陷阱
陷阱 1:可变默认参数(本篇预告)
1 | def add_item(item, items=[]): # 危险! |
items=[] 只在函数定义时执行一次,多次调用会共享同一个列表。这个坑我们在 参数详解 里会详细讲。
陷阱 2:is 与 == 分不清
1 | a = 256 |
结论:判断值相等永远用 ==,判断”是不是同一个对象”才用 is(一般只用于 is None)。
陷阱 3:数字前导 0
在 Python 3 里 x = 007 会报语法错误,因为过去八进制字面量是 0 开头,容易和十进制混淆,现在必须写 0o7。
陷阱 4:整数除法
1 | print(5 / 2) # 2.5(float 结果) |
Python 2 的 / 是整除,Python 3 改成了浮点除法。所有网上 Python 2 时代的代码到 3 里都要小心这一条。
陷阱 5:字符串数字直接相加
1 | n = input("年龄:") |
input() 永远返回字符串。
十三、小结与延伸阅读
- 变量是”贴在对象上的标签”,不是”存放值的盒子”;
- 命名遵循 PEP 8:snake_case、UPPER_CASE、PascalCase;
- 6 大基本类型:int、float、str、bool、None、complex;
- Python 是动态类型,但配合 type hints 可以获得静态检查;
- 浮点数不精确,
0.1 + 0.2 != 0.3; is判断对象身份,==判断值相等,除非判None否则用==;input()返回字符串,需要手动转类型。
延伸阅读:
- PEP 8 中文版:https://peps.python.org/pep-0008/
- Python 数据模型:https://docs.python.org/zh-cn/3/reference/datamodel.html
下一篇 运算符与表达式 我们要用这些变量做点计算了。