Python 语法篇 · 第2章

变量与基本数据类型

程序处理的核心是"数据"。本章学习如何用变量存储数据,以及 Python 内置的数字、布尔、字符串等基本类型。

🎯 学习目标

  • 掌握单行/多行注释的写法与用途
  • 理解 Python 中"变量是标签"的赋值模型,掌握命名规范与关键字
  • 掌握整数、浮点数、布尔、复数、None 的特性与常用运算
  • 会用 type()、isinstance() 判断类型,熟练进行类型转换
  • 掌握 print() 与 input() 完成最基本的输入输出
  • 初步理解可变对象与不可变对象、id() 与 is 的含义

1注释:写给人看的说明

注释在运行时会被解释器完全忽略,作用是解释代码意图、临时屏蔽代码。好代码的注释应该解释"为什么",而不是重复"做了什么"。

# 这是单行注释:从 # 开始到行尾都不会执行

print("hello")    # 行尾注释:代码与注释之间空两格更美观

"""
这是多行字符串,
没有被赋值时也常被当作"块注释"使用,
用三个单引号或三个双引号包裹均可。
"""

def add(a, b):
    """两数之和(这是文档字符串 docstring,函数的正式说明书)。"""
    return a + b

严格来说 Python 没有"多行注释"语法,三引号包裹的是字符串字面量。只有放在文件开头、函数/类开头的那种,会被当作文档字符串(docstring)保留下来,可用 help(add) 查看。

2变量:贴在数据上的标签

赋值语句

age = 18            # 把整数 18 赋值给变量 age
name = "小明"
price = 9.9
is_student = True

print(age, name, price, is_student)   # 18 小明 9.9 True

很多语言把变量理解成"装数据的盒子",而 Python 更准确的模型是:数据(对象)先存在内存中,变量是贴在对象上的标签(引用)。执行 a = 10; b = a 后,是两个标签同时贴在同一个整数对象 10 上,而不是把 10 复制了一份。

同时赋值 / 链式赋值

a = b = c = 0          # 链式赋值:三个标签指向同一个 0
x, y = 10, 20          # 多元赋值(元组解包)
x, y = y, x            # 一行交换两个变量,无需中间变量!
print(x, y)            # 20 10

# 实战:用 _ 接收不需要的值
name, _ = ("张三", 99)

# 星号收集多余的值
first, *rest = [1, 2, 3, 4]
print(first, rest)     # 1 [2, 3, 4]

变量的重新赋值与删除

n = 100
n = "一百"            # Python 允许随时贴到别的类型对象上(动态类型)
del n                 # 删除变量名(之后再访问 n 会报 NameError)

命名规则(语法强制)

  • 只能由字母、数字、下划线组成,且不能以数字开头:name1 合法,1name 非法。
  • 区分大小写:Age 和 age 是两个变量。
  • 不能使用关键字(被语言保留的单词)。
  • 支持中文等 Unicode 字符(如 名字 = "张三"),但强烈不建议,工程上一律用英文。
# 查看全部关键字
import keyword
print(keyword.kwlist)
# ['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']

命名规范(PEP 8 风格建议)

类型风格示例
变量 / 函数蛇形命名 snake_caseuser_name、get_total()
类名大驼峰 CapWordsStudentInfo
常量全大写+下划线MAX_SIZE = 100
私有变量单下划线开头_internal_data
应避免内置名被覆盖list = [1,2](把类型 list 覆盖了,坑!)

变量名要"见名知意":a1、tmp 不如 score、total_count。但循环计数器用 i、j 是约定俗成的。

3基本数据类型总览

Python 内置的核心数据类型可以分成几大类(本章先看标量类型,容器类型在第 6 章详解):

大类类型关键字示例可变性
数字整数int18、-3、0不可变
浮点数float3.14、-0.5、1e3不可变
复数complex3+4j不可变
布尔布尔值boolTrue、False不可变
文本字符串str"hello"不可变
空值空对象NoneTypeNone—
容器列表list[1, 2, 3]可变
元组tuple(1, 2, 3)不可变
字典dict{"a": 1}可变
集合set{1, 2, 3}可变

4数字类型

4.1 整数 int:任意精度,永不溢出

Python 的整数没有固定大小限制(不像 C 语言有 int32 上限),可以写天文数字:

a = 10
big = 10 ** 100        # 10 的 100 次方(Googol),轻松表示
print(big)

# 三种进制写法(值都等于 255)
print(0b11111111)      # 0b 开头:二进制
print(0o377)           # 0o 开头:八进制
print(0xFF)            # 0x 开头:十六进制

# 数字可读性分隔符(Python 3.6+,下划线会被忽略)
population = 1_400_000_000
print(population)      # 1400000000

4.2 浮点数 float 与精度坑

pi = 3.14159
sci = 1.5e3           # 科学计数法:1.5 × 10³ = 1500.0
print(0.1 + 0.2)      # 0.30000000000000004  ← 经典坑!

0.1 + 0.2 != 0.3 不是 Python 的 bug,而是浮点数采用 IEEE 754 二进制存储导致的世界性现象。永远不要用 == 直接比较两个浮点数。精确十进制计算请用标准库 decimal:

from decimal import Decimal
print(Decimal("0.1") + Decimal("0.2"))   # 0.3 —— 金额等场景使用

# 普通比较:判断差值是否足够小
print(abs((0.1 + 0.2) - 0.3) < 1e-9)     # True

整数与浮点数运算:/ 的结果永远是 float;// 整除、% 取余、** 乘方:

print(7 / 2)     # 3.5   真除法
print(7 // 2)    # 3     整除(向下取整)
print(-7 // 2)   # -4    注意负数是"向下取整",结果是 -4 而不是 -3
print(7 % 2)     # 1     取余
print(2 ** 10)   # 1024  乘方
print(divmod(7, 2))   # (3, 1)  同时得到商和余数

4.3 常用数学函数

round(3.567, 2)    # 3.57   四舍六入(银行家舍入,.5 取偶)
abs(-12)           # 12
max(1, 9, 3)       # 9
min(1, 9, 3)       # 1
sum([1, 2, 3])     # 6
pow(2, 8)          # 256

import math
math.floor(3.9)    # 3     向下取整
math.ceil(3.1)     # 4     向上取整
math.sqrt(16)      # 4.0
math.pi            # 3.141592653589793
math.log(math.e)   # 1.0

import random
random.randint(1, 6)     # 掷骰子:1~6 的随机整数(含两端)
random.random()          # 0.0~1.0 之间的随机小数
random.choice(["石头", "剪刀", "布"])

round(2.5) 的结果是 2 而不是 3,round(3.5) 是 4——这是"四舍六入五成双"规则(与数学课本的四舍五入不同),金融场景同样建议用 decimal。

4.4 布尔类型 bool

布尔值只有两个:True 和 False(注意首字母大写)。有趣的是,bool 是 int 的子类,True 本质上就是 1,False 就是 0:

print(True + True)      # 2
print(int(False))       # 0
print(isinstance(True, int))   # True —— 布尔属于整数的一种

Python 中常见的"假值"(falsy),在 if 中都会被当作 False:

# 以下值布尔测试均为 False,其余基本为 True
bool(False)       # False
bool(0)           # False      数字零
bool(0.0)         # False
bool("")          # False      空字符串
bool([])          # False      空容器(列表/元组/字典/集合)
bool(None)        # False      空值
bool(" ")         # True       注意!含空格的字符串不是空的

4.5 复数(了解)

z = 3 + 4j
print(z.real, z.imag)      # 3.0 4.0
print(abs(z))              # 5.0   模
# 主要用于科学/工程计算,业务开发几乎用不到

5字符串初体验

字符串用来表示文本,用单引号、双引号或三引号包裹,三者没有本质区别:

s1 = '单引号'
s2 = "双引号"
s3 = """三引号可以
跨多行书写"""

# 引号嵌套:外双内单或反过来,无需转义
msg = "It's a book"
say = '他说:"你好"'

# 拼接与重复
print("Py" + "thon")      # Python
print("=" * 10)           # ==========
print("我今年%d岁" % 18)   # 旧式格式化(第5章详解)

字符串的索引、切片、几十个处理方法、编码问题非常丰富,第 5 章会系统讲解。

6类型判断与类型转换

判断类型

print(type(18))            # <class 'int'>
print(type(3.14))          # <class 'float'>
print(type("hi"))          # <class 'str'>

print(type(18) == int)                 # True
print(isinstance(18, int))             # True,更推荐这种写法
print(isinstance(True, int))           # True(bool 是 int 子类)
print(isinstance(18, (int, float)))    # True,可传元组判断多种类型

类型转换

int("123")        # 123     字符串 → 整数
int(3.99)         # 3       浮点数 → 整数(直接截断小数,不是四舍五入)
float("3.14")     # 3.14
str(123)          # '123'
bool(0)           # False
list("abc")       # ['a', 'b', 'c']

# 进制转换
bin(255)          # '0b11111111'
oct(255)          # '0o377'
hex(255)          # '0xff'
chr(65)           # 'A'   码点 → 字符
ord("A")          # 65    字符 → 码点

int("18岁") 或 int("3.14") 会抛出 ValueError——字符串必须"长得像"目标类型才能转。这类错误在处理用户输入时极为常见,第 10 章会学习用 try/except 优雅处理。

7输入与输出:print 与 input

print() 详解

print(1, 2, 3)                    # 1 2 3     默认用空格分隔
print("a", "b", sep="-")          # a-b       sep:自定义分隔符
print("不换行", end="")           # end:自定义结尾(默认是 \n 换行)
print("接在同一行")
print()                           # 只输出一个换行

# 最推荐:f-string 格式化(第5章细讲)
name, score = "小红", 95.5
print(f"{name} 的成绩是 {score:.1f} 分")   # 小红 的成绩是 95.5 分

input() 获取用户输入

name = input("请输入你的姓名:")    # 程序暂停,等待键盘输入
print("你好," + name)

# input() 得到的永远是字符串!做数学运算前必须转换类型
age = int(input("请输入年龄:"))
print(age >= 18)                    # 输入 20 → True
print("十年后你", age + 10, "岁")

新手高频错误:num = input("数字:"); print(num * 2),输入 3 得到的是 '33'(字符串重复)而不是 6。记住 input 的返回类型永远是 str。

小案例:圆面积计算器

import math

r = float(input("请输入圆的半径:"))
area = math.pi * r ** 2
print(f"半径为 {r} 的圆面积是 {area:.2f}")
请输入圆的半径:5
半径为 5.0 的圆面积是 78.54

8None:表示"什么都没有"

None 是 Python 里的"空值",表示"不存在 / 还没有值",类似其他语言的 null。它有自己的类型 NoneType,且全局唯一。

result = None
print(result is None)     # True   判断 None 永远用 is,不要用 ==

def say_hi():
    print("hi")           # 函数没有 return 时,默认返回 None

print(say_hi())           # 先打印 hi,再打印 None

9深入一步:id、is 与可变性

id(obj) 返回对象在 CPython 解释器中的唯一编号(可近似理解为内存地址);is 比较两个标签是否指向同一个对象,== 比较的是值是否相等。

a = [1, 2]
b = [1, 2]
print(a == b)     # True   值相等
print(a is b)     # False  但是两个不同的列表对象

n1 = 100
n2 = 100
print(n1 is n2)   # True(CPython 小整数池缓存 -5~256,实现细节,勿依赖)

s1 = "abc"
s2 = "abc"
print(id(s1), id(s2))   # 简单字符串也有驻留机制

经验法则:比较值用 ==;判断是否为 None 用 is None。不要依赖小整数池、字符串驻留等实现细节写业务代码。

不可变类型(int/str/tuple 等)无法原地修改,所有"修改"其实都是创建并指向新对象;可变类型(list/dict/set)可以原地增删内容。这一区别会深刻影响赋值、传参和拷贝行为,第 6 章讲列表拷贝时会重点实验。

s = "abc"
print(id(s))     # 假设 14023456
s = s + "d"      # 不是把原字符串改掉,而是创建了新对象 "abcd"
print(id(s))     # 编号变了!

10本章小结与练习

📌 关键结论

  • 变量是对象的"标签";命名遵守 snake_case,不能用关键字。
  • 整数任意精度;浮点有精度问题,比较要留容差,精确计算用 decimal。
  • 记住六个假值:False、0、0.0、""、空容器、None。
  • input() 返回字符串,运算前先 int()/float()。
  • == 比值,is 比身份(是否同一对象),判空用 is None。
练习1:a = 5; b = a; a = 6 之后,b 是多少?为什么?
b 仍是 5。a 和 b 一开始都指向整数对象 5;重新赋值 a = 6 是让 a 改而指向新对象 6,b 不受影响仍指向 5。整数不可变,"修改"只会产生新对象。
练习2:让用户输入两个整数,输出它们的和、商(保留2位小数)以及平均值。
参考:a = int(input()); b = int(input()); print(a+b, f"{a/b:.2f}", (a+b)/2)。注意 input 必须 int 转换,否则 + 会变成字符串拼接。
练习3:判断下面表达式的值:bool("0")、bool([])、0.1+0.2 == 0.3、"3" * 3。
bool("0") 为 True(非空字符串即真);bool([]) 为 False(空列表);0.1+0.2 == 0.3 为 False(浮点存储误差,结果是 0.30000000000000004);"3" * 3 为字符串 "333"。