文章目录
-
- 一、从一个需求开始:写一个计算器
- 二、变量与赋值:给数据起个名字
-
- [2.1 什么是变量](#2.1 什么是变量)
- [2.2 变量命名规范](#2.2 变量命名规范)
- [2.3 变量在计算器中的应用](#2.3 变量在计算器中的应用)
- 三、六大基本数据类型
-
- [3.1 为什么需要区分类型](#3.1 为什么需要区分类型)
- [3.2 用 `type()` 验证计算器中的数据类型](#3.2 用
type()验证计算器中的数据类型)
- 四、数字运算与浮点数精度问题
-
- [4.2 浮点数精度问题:`0.1 + 0.2 != 0.3`](#4.2 浮点数精度问题:
0.1 + 0.2 != 0.3) -
- [4.2.1 为什么会这样?](#4.2.1 为什么会这样?)
- [4.2.2 日常开发中如何处理](#4.2.2 日常开发中如何处理)
- [4.2 浮点数精度问题:`0.1 + 0.2 != 0.3`](#4.2 浮点数精度问题:
- 五、字符串:从用户输入到格式化输出
-
- [5.1 字符串的创建与引号规则](#5.1 字符串的创建与引号规则)
- [5.2 字符串的索引与切片](#5.2 字符串的索引与切片)
- [5.3 f-string 格式化:Python 3.6+ 的最佳实践](#5.3 f-string 格式化:Python 3.6+ 的最佳实践)
- [5.4 字符串的不可变性](#5.4 字符串的不可变性)
- 六、布尔值:程序做决策的基础
-
- [6.1 比较运算符](#6.1 比较运算符)
- [6.2 Python 特有的链式比较](#6.2 Python 特有的链式比较)
- 七、类型转换:让数据从一种形态变成另一种
-
- [7.1 常用类型转换函数](#7.1 常用类型转换函数)
- [7.2 转换失败的处理](#7.2 转换失败的处理)
- 八、注释:写给未来的自己
-
- [8.1 单行注释与多行注释](#8.1 单行注释与多行注释)
- 九、实战:构建一个简易计算器
- [十、print 函数:你可能不知道的参数](#十、print 函数:你可能不知道的参数)
- 写在最后
一、从一个需求开始:写一个计算器
在正式讨论语法之前,先设想一个真实场景:需要写一个简易的加减乘除计算器,用户输入两个数字,选择运算方式,程序输出结果。
这个看似简单的需求,实际上涵盖了 Python 基本语法中最核心的概念:
计算器需求
接收用户输入
→ input() → str 类型
获取运算符
→ str 判断
数值计算
→ int/float 类型
输出结果
→ print() 输出
类型转换
str → int/float
结果格式化
保留小数位
根据运算符
调用对应计算
下面的内容将按照这个顺序展开:每个概念的引入都对应计算器开发中的具体步骤,让语法不再是抽象的规则,而是解决问题的工具。
二、变量与赋值:给数据起个名字
2.1 什么是变量
变量就是一个存放数据的"盒子"。Python 里创建一个变量只需要一行代码:
python
name = "Alice"
age = 28
height = 1.65
is_student = False
等号 = 在 Python 中不是"等于"的意思,而是赋值运算符 ------将右侧的值存入左侧的变量中。"name = "Alice"" 的含义是:创建一个名为 name 的盒子,把字符串 "Alice" 放进去。
可以用 type() 函数查看任意数据的类型:
python
>>> type("Alice")
<class 'str'>
>>> type(28)
<class 'int'>
>>> type(1.65)
<class 'float'>
>>> type(False)
<class 'bool'>
2.2 变量命名规范
Python 的变量名有以下硬性规则:
- 只能包含字母、数字、下划线
_ - 不能以数字开头(如
2name非法) - 不能使用 Python 保留字(如
if、for、class等) - 大小写敏感(
Name和name是两个不同的变量)
除了硬性规则,还有一个行业惯例 :Python 社区统一使用蛇形命名法(snake_case)------所有字母小写,单词之间用下划线分隔。
python
# 符合规范的命名
user_name = "Bob"
total_price = 129.8
is_vip_member = True
# 不推荐的命名(虽然合法,但不符合社区惯例)
userName = "Bob" # 驼峰命名,Python 社区不常用
TotalPrice = 129.8 # 帕斯卡命名,用于类名而非变量
为什么有"社区惯例"这种东西? 代码不是写给自己看的------接手代码的人、Review 代码的同事、调用 API 的开发者,都需要快速理解变量名代表什么。一致的命名风格比"好不好看"更重要。
2.3 变量在计算器中的应用
回到计算器场景。需要存储用户输入的两个数字:
python
# 获取用户输入
a = input("请输入第一个数字: ") # input() 返回的是字符串
b = input("请输入第二个数字: ")
print(type(a)) # <class 'str'> ------ 拿到的是字符串,不是数字
print(type(b)) # <class 'str'>
这里出现了一个关键问题:input() 返回的始终是字符串类型,即使输入的是 100,在程序内部也是 "100" 而不是数字 100。理解这一点,是掌握 Python 类型系统的第一步。
三、六大基本数据类型
Python 的数据类型可以分为两大类:原子类型 (不可再分)和容器类型(可容纳多个数据)。对于计算器场景,重点掌握以下六种:
| 类型 | 名称 | 示例 | 是否原子 |
|---|---|---|---|
int |
整数 | 42, -7, 0 |
✓ |
float |
浮点数 | 3.14, -0.5, 2.0 |
✓ |
str |
字符串 | "hello", 'world' |
✓ |
bool |
布尔值 | True, False |
✓ |
list |
列表 | [1, 2, 3] |
✗ |
dict |
字典 | {"name": "Alice", "age": 28} |
✗ |
3.1 为什么需要区分类型
不同类型支持的操作不同。数字类型可以做加减乘除,字符串类型可以做拼接和切片:
python
# 数字相加
>>> 10 + 5
15
# 字符串拼接
>>> "10" + "5"
'105' # 结果是字符串 "105",不是数字 15!
这意味着:如果想让字符串 "10" 和 "5" 相加得到 15,必须先将它们转换为数字类型。
3.2 用 type() 验证计算器中的数据类型
输入 10 和 3,选择除法运算。不同类型会直接影响计算结果:
python
# 场景1: 没有转换------字符串除法会报错
>>> "10" / "3"
TypeError: unsupported operand type(s) for /: 'str' and 'str'
# 场景2: 转换为浮点数------得到精确小数
>>> float("10") / float("3")
3.3333333333333335
第二行中,float("10") 将字符串 "10" 转换为浮点数 10.0,再进行除法运算。
四、数字运算与浮点数精度问题
除了加减乘除,Python 还提供了几个在特定场景下非常有用的运算符。
python
a, b = 10, 3
print(a + b) # 加法: 13
print(a - b) # 减法: 7
print(a * b) # 乘法: 30
print(a / b) # 除法: 3.3333333333333335
print(a // b) # 整除: 3(向下取整)
print(a % b) # 取模: 1(10 除以 3 余 1)
print(a ** b) # 幂运算: 10 的 3 次方 = 1000
其中有两个值得特别注意的运算符:
//整除 :计算结果只保留整数部分,10 // 3等于3而非3.33%取模(取余) :计算除法后的余数,常用于判断奇偶性(n % 2 == 0是偶数)、周期性操作等
4.2 浮点数精度问题:0.1 + 0.2 != 0.3
大多数编程语言都有这么一出------Python 里也不例外:
python
>>> 0.1 + 0.2 == 0.3
False
>>> 0.1 + 0.2
0.30000000000000004
这不是 Python 的 Bug,也不是代码写错了,而是二进制浮点数运算的固有特性------C、Java、JavaScript 遇到同样的情况,反应一模一样。
4.2.1 为什么会这样?
计算机内部使用二进制(Base 2)存储小数,而十进制的 0.1(即 1/10)在二进制中是一个无限循环小数:
0.0001100110011001100110011001100110011001100110011... (0011 循环)
IEEE 754 双精度浮点数只有 53 位有效精度,无法精确表示 0.1。计算机实际存储的是最接近它的分数:
python
>>> (0.1).as_integer_ratio() # 查看 0.1 的二进制分数表示
(3602879701896397, 9007199254740992)
# 也就是: 3602879701896397 / 2**55
这个分数换算成十进制后,比真正的 0.1 多出了微小的正向误差。0.2 同样也存在类似误差。两者相加时误差累积,最终结果与 0.3(也是一个不精确的近似值)并不完全相等。
用图示理解误差来源:
计算机存储的(IEEE 754 浮点数)
我们看到的(十进制)
存储
存储
存储
+
+
不相等
0.1
0.2
0.3
0.1000000000000000055...
0.200000000000000011...
0.299999999999999988...
0.30000000000000004
4.2.2 日常开发中如何处理
不要用 == 比较浮点数 。Python 官方推荐使用 math.isclose():
python
>>> import math
>>> math.isclose(0.1 + 0.2, 0.3)
True
当需要精确十进制运算时 (财务、账目等场景),使用 decimal 模块:
python
>>> from decimal import Decimal
>>> Decimal("0.1") + Decimal("0.2") == Decimal("0.3")
True
注意 :必须用字符串
"0.1"初始化Decimal,如果写成Decimal(0.1),二进制误差会随着0.1一起传入,==比较仍然会返回False。
当需要累加大量浮点数时 ,使用 math.fsum() 控制误差累积:
python
>>> import math
>>> sum([0.1] * 10) == 1.0
False
>>> math.fsum([0.1] * 10) == 1.0
True
在计算器场景中,通常只需在输出时格式化保留两位小数:
python
result = a / b
print(f"结果是: {result:.2f}") # .2f 表示保留两位小数
# 结果是: 3.33
五、字符串:从用户输入到格式化输出
5.1 字符串的创建与引号规则
Python 中三种引号都可以创建字符串:
python
s1 = "双引号"
s2 = '单引号' # 在字符串内包含引号时换用,避免转义
s3 = """三引号
可以跨行""" # 三引号支持多行文本
两种引号("" 和 '')在功能上完全等价,选择哪种纯粹取决于字符串内容是否包含同类引号。
5.2 字符串的索引与切片
字符串中的每个字符都有一个位置编号,从 0 开始:
python
>>> text = "Python"
>>> text[0]
'P'
>>> text[-1] # 负数索引从右往左数,-1 是最后一个字符
'n'
>>> text[0:3] # 切片语法:左闭右开,提取索引 0、1、2
'Pyt'
>>> text[::2] # 第三个参数表示步长,每隔一个字符取一个
'Pto'
5.3 f-string 格式化:Python 3.6+ 的最佳实践
f-string(格式化字符串字面量)是目前最推荐的字符串格式化方式。在字符串前加 f 前缀,就可以在 {} 中直接插入变量或表达式:
python
name = "Alice"
age = 28
# 基本用法
print(f"我叫 {name},今年 {age} 岁。")
# 输出: 我叫 Alice,今年 28 岁。
# 嵌入表达式
print(f"明年就 {age + 1} 岁了。")
# 输出: 明年就 29 岁了。
# 保留小数位
pi = 3.1415926
print(f"π 保留两位小数是 {pi:.2f}")
# 输出: π 保留两位小数是 3.14
# 数字千分位格式化
population = 1412000000
print(f"人口: {population:,}")
# 输出: 人口: 1,412,000,000
回到计算器场景,用 f-string 输出结果:
python
result = a / b
print(f"{a} ÷ {b} = {result:.4f}")
# 输入 a=10, b=3 时,输出: 10 ÷ 3 = 3.3333
5.4 字符串的不可变性
Python 中的字符串是不可变对象------创建之后不能直接修改。如果尝试对字符串的某个位置赋值,会报错:
python
>>> s = "hello"
>>> s[0] = "H"
TypeError: 'str' object does not support item assignment
这不是限制,而是设计选择。不可变对象让程序更容易推理------一个字符串一旦创建,它的值永远不会因为某个意外操作而改变。如果需要"修改"字符串,实际上是创建了一个新的字符串:
python
>>> s = "hello"
>>> s_new = "H" + s[1:] # 创建新字符串,旧字符串不变
>>> s_new
'Hello'
>>> s # 原字符串保持不变
'hello'
六、布尔值:程序做决策的基础
布尔类型只有两个值:True(真)和 False(假)。在计算器场景中,可以用布尔值判断运算是否合法:
python
# 判断除数是否为 0
divisor = 3
is_valid = divisor != 0
print(is_valid) # True
if divisor == 0:
print("除数不能为 0")
else:
print(f"结果是 {10 / divisor}")
6.1 比较运算符
| 运算符 | 含义 | 示例 | 结果 |
|---|---|---|---|
== |
等于 | 5 == 5 |
True |
!= |
不等于 | 5 != 3 |
True |
> |
大于 | 5 > 3 |
True |
< |
小于 | 5 < 3 |
False |
>= |
大于等于 | 5 >= 5 |
True |
<= |
小于等于 | 5 <= 3 |
False |
6.2 Python 特有的链式比较
Python 允许一种在其他语言中很少见的比较写法------链式比较:
python
>>> 0 < x < 10 # 等价于 (0 < x) and (x < 10)
>>> 0 < age <= 18 # 年龄在 0 到 18 岁之间(包含 18)
>>> -1 < x < 1 # x 在 -1 到 1 之间
这种写法不仅更简洁,而且在数学上更直观:0 < x < 10 直接表达"x 介于 0 和 10 之间"这个概念,而不是拆成两个独立条件。
七、类型转换:让数据从一种形态变成另一种
类型转换是计算器开发中最核心的步骤之一。用户的输入永远是字符串,数学运算需要数字,输出结果又需要变回字符串------这个过程贯穿整个程序:
输出阶段
计算阶段
转换阶段
输入阶段
input()
str 类型
如 '10', '3'
int() / float()
数值类型
10, 3
算术运算
a / b
float 类型
3.3333...
f-string 格式化
保留小数位
str 类型
'3.3333'
7.1 常用类型转换函数
python
# 字符串 → 整数
int("42") # → 42
int(" 7 ") # → 7(自动忽略前后空格)
# 字符串 → 浮点数
float("3.14") # → 3.14
float("42") # → 42.0(整数转浮点数)
# 数字 → 字符串
str(42) # → "42"
str(3.14) # → "3.14"
str(True) # → "True"(布尔转字符串)
# 浮点数 → 整数(截断小数部分,不四舍五入)
int(3.99) # → 3(不是 4!)
# 字符串 → 布尔值(非空字符串为 True)
bool("hello") # → True
bool("") # → False
bool("0") # → True(非空字符串)
bool(0) # → False(数字 0 本身是 False)
7.2 转换失败的处理
当类型转换无法完成时,Python 会抛出 ValueError:
python
>>> int("hello")
ValueError: invalid literal for int() with base 10: 'hello'
>>> float("3.14.15")
ValueError: could not convert string to float: '3.14.15'
在实际开发中,应该在转换之前先验证字符串的内容是否符合预期:
python
user_input = "10"
if user_input.isdigit(): # 判断字符串是否全由数字组成
number = int(user_input)
print(f"转换成功: {number}")
else:
print(f"'{user_input}' 不是有效数字")
八、注释:写给未来的自己
代码写完后,最常见的困惑不是"这段代码是做什么的",而是"为什么这样做"。注释记录的是"为什么",而不是"做了什么"------代码本身已经说明了"做了什么",好的注释应该解释那些从代码本身看不出来的决策理由。
python
# 计算圆的面积
area = 3.14 * radius ** 2
# 为什么要用 3.14 而不是 math.pi?
# ------因为用户要求精确到小数点后两位,3.14 已经足够
# ------math.pi 的精度在这里反而是过度工程
8.1 单行注释与多行注释
python
# 这是一个单行注释
"""
这是一个多行注释(三引号字符串)
常用于模块开头的说明文档(docstring)
"""
def greet(name):
"""
向指定用户打招呼。
参数:
name: 用户名字符串
返回:
打招呼的字符串
"""
return f"你好,{name}!"
三引号字符串在函数内部作为第一个语句出现时,就成了该函数的文档字符串(docstring) 。Python 的内置 help() 函数会读取并显示它:
python
>>> help(greet)
Help on function greet in module __main__:
greet(name)
向指定用户打招呼。
参数:
name: 用户名字符串
返回:
打招呼的字符串
九、实战:构建一个简易计算器
整合以上所有概念,构建完整的计算器程序:
python
"""
简易计算器 v1.0
支持加减乘除,支持除数为零的检查
"""
def calculator():
"""运行一次计算器交互"""
print("=" * 30)
print("欢迎使用简易计算器")
print("=" * 30)
# 第一步:获取用户输入(input 返回 str)
num1_str = input("请输入第一个数字: ").strip()
operator = input("请输入运算符 (+ - * /): ").strip()
num2_str = input("请输入第二个数字: ").strip()
# 第二步:验证输入是否为有效数字(isdigit 检查)
if not num1_str.replace(".", "", 1).replace("-", "", 1).isdigit():
print(f"错误: '{num1_str}' 不是有效数字")
return
if not num2_str.replace(".", "", 1).replace("-", "", 1).isdigit():
print(f"错误: '{num2_str}' 不是有效数字")
return
# 第三步:类型转换(str → float,用于精确除法运算)
num1 = float(num1_str)
num2 = float(num2_str)
# 第四步:根据运算符分支处理
# 特别处理除法:除数为零时给出友好提示而非崩溃
if operator == "+":
result = num1 + num2
symbol = "+"
elif operator == "-":
result = num1 - num2
symbol = "-"
elif operator == "*":
result = num1 * num2
symbol = "×"
elif operator == "/":
if num2 == 0:
print("错误: 除数不能为零")
return
result = num1 / num2
symbol = "÷"
else:
print(f"错误: 不支持的运算符 '{operator}'")
return
# 第五步:格式化输出(f-string + 保留小数位)
if result == int(result):
# 如果结果是整数,不显示小数部分
print(f"{num1} {symbol} {num2} = {int(result)}")
else:
# 如果结果是小数,保留两位小数
print(f"{num1} {symbol} {num2} = {result:.2f}")
if __name__ == "__main__":
calculator()
运行效果:
==============================
欢迎使用简易计算器
==============================
请输入第一个数字: 10
请输入运算符 (+ - * /): /
请输入第二个数字: 3
10 ÷ 3 = 3.33
十、print 函数:你可能不知道的参数
print() 是 Python 中最常用的函数之一,但很多人只用过它最基本的用法。事实上 print 还有几个实用参数:
python
# sep: 多个参数之间的分隔符,默认是空格
print("Hello", "World", "Python", sep=" | ")
# 输出: Hello | World | Python
# end: 打印结束后的字符,默认是换行符 \n
print("正在加载", end="")
print("...", end="")
print("完成")
# 输出: 正在加载...完成(所有内容在同一行)
# file: 指定输出目标,默认是 sys.stdout(屏幕)
# 可重定向到文件
with open("result.txt", "w", encoding="utf-8") as f:
print(f"计算结果: {result}", file=f)
# 内容被写入文件而非显示在屏幕上
# flush: 是否立即刷新输出(常用于进度条显示)
import time
for i in range(5):
print(f"进度 {i+1}/5", end="\r", flush=True)
time.sleep(0.5)
# \r 把光标回到行首,覆盖打印同一行内容
写在最后
本篇从一个计算器的实际需求出发,依次覆盖了变量、类型系统、数字运算、字符串处理、布尔值、类型转换和 print 函数等核心概念。这些内容并非孤立------在计算器的开发过程中,每一步都用到了前面学过的知识:用户输入产生字符串,字符串需要转换才能参与计算,计算结果又需要格式化才能友好输出。
这种"环环相扣"的感觉,正是编程有意思的地方。
如果本文有帮助,欢迎点赞、关注。Python 基础系列会持续更新。