【Python】基础语法(1):常量、变量、类型、输入输出与运算符

🔥 星光编译者 · 个人主页

📚 学习专栏: 《C/C++ 成长笔记》 · 《Linux 实践手册》 · 《数据结构与算法》

🌄 向云端飞扬,编译属于自己的代码星河。


☕ 写在开篇

  你好,这里是 星光编译者。

  这里记录我在 C/C++、Linux、数据结构与算法 学习中遇到的真实问题、亲手验证过的代码,以及那些容易被忽略的实现细节。

  比起简单罗列结论,我更愿意从问题出发,把一个知识点的来由讲清楚,把"为什么会这样"和"应该怎样解决"说明白,让每一次踩坑都沉淀成可以复用的经验。

  如果这篇记录能帮你少绕一点路,或让某个模糊的地方忽然变得清晰,那么这次分享便有了意义。愿我们在一次次阅读、编译与调试中稳步向前,慢慢搭起属于自己的技术世界。


🔥 本文定位:面向 Python 初学者,从"把 Python 当计算器"开始,建立表达式、变量、数据类型、控制台交互与运算符的完整认知。

💡 学习目标 :能读懂并写出基本表达式;理解变量绑定和动态类型;会使用 input()、print() 与 f-string;掌握算术、关系、逻辑和赋值运算符;能避开浮点数精度、字符串拼接与短路求值中的常见坑。

📌 阅读说明 :本文根据课程 PDF《2.基础语法(1)》整理,并按现代 Python 3 实践补充 snake_case、math.isclose()、异常处理与 docstring 的准确语义。


文章目录


一、从计算器开始:常量、运算符与表达式

Python 可以直接完成算术计算:

python 复制代码
print(1 + 2 - 3)
print(1 + 2 * 3)
print((1 + 2) * 3)
print(1 + 2 / 3)

这四行代码虽然简单,却已经包含三个基本概念:

  • 1、2、3 是直接写在代码里的字面值;
  • +、-、*、/ 是运算符;
  • 字面值与运算符按规则组合成表达式,求值后产生一个结果。

1.1 优先级与括号

Python 的基本算术优先级与数学习惯一致:先乘除,后加减,括号最先。因此:

python 复制代码
1 + 2 * 3      # 7
(1 + 2) * 3    # 9

当表达式稍微复杂时,即使默认优先级恰好符合意图,也可以用括号强化可读性。不要把代码写成一场"运算符优先级背诵比赛"。

1.2 / 不会截断小数

在 Python 3 中,/ 执行真除法:

python 复制代码
print(2 / 3)   # 0.6666666666666666
print(4 / 2)   # 2.0

即使两边都是整数,/ 的结果也是 float。如果需要地板除,应使用 //,但它对负数的行为与"直接去掉小数"不同,后文会专门说明。

1.3 用表达式计算平均数

python 复制代码
average = (67.5 + 89.0 + 12.9 + 32.2) / 4
print(average)

这里的右侧是表达式,左侧的 average 则把结果保留了下来。一旦计算需要多个中间步骤,变量就开始显示价值。


二、变量的本质:不只是"存数据的盒子"

初学时常把变量比喻成"存放数据的盒子"。这个比喻有助于入门,但对 Python 而言,更准确的理解是:

变量是一个名字,赋值会让这个名字与某个对象建立绑定。

python 复制代码
score = 89.5
score = "A"

第一行让 score 绑定到一个 float 对象;第二行又让它改为绑定一个 str 对象。不是"原来的浮点数盒子被改造成了字符串盒子",而是名字的指向发生了变化。

2.1 变量的定义、读取与修改

python 复制代码
count = 10          # 首次绑定
print(count)        # 读取
count = 20          # 重新绑定
print(count)

Python 不需要在变量名前写 int、float 之类的类型声明。变量必须先赋值再使用:

python 复制代码
# print(total)  # NameError: name 'total' is not defined

2.2 变量名的硬性规则

合法变量名需要满足:

  1. 由字母、数字和下划线组成;
  2. 不能以数字开头;
  3. 不能与 Python 关键字重复;
  4. 区分大小写,score 与 Score 是两个名字。
python 复制代码
user_name = "Ada"   # 合法
score2 = 95          # 合法
_cache = {}          # 合法

# 2score = 95        # 非法:数字开头
# class = "A"       # 非法:class 是关键字

可以用标准库查看关键字:

python 复制代码
import keyword

print(keyword.kwlist)

2.3 软性规范:优先使用 snake_case

变量名要表达用途,不要满篇都是 a、b、x、y。现代 Python 代码通常遵循 PEP 8,变量和函数名推荐使用小写加下划线:

python 复制代码
total_count = 100
person_info = "student"
average_score = 86.5

totalCount 这种驼峰写法并非语法错误,但它不是 Python 变量名的主流风格。


三、基本类型与动态类型

类型并不是为了给知识点分类而硬造出来的名词。它至少回答两个问题:

  1. 这个对象如何在计算机中表示?
  2. 可以对它执行哪些操作?

3.1 int:整数

python 复制代码
count = 42
print(type(count))  # <class 'int'>

Python 的 int 不固定为 32 位或 64 位整数,数值可在内存和实现允许的范围内继续增大:

python 复制代码
huge_number = 10 ** 100
print(huge_number)

"任意精度"不等于物理世界中的"无限";实际能表示多大仍受内存和运行环境限制。

3.2 float:浮点数

python 复制代码
temperature = 36.5
print(type(temperature))  # <class 'float'>

Python 内置的 float 通常使用 IEEE 754 双精度表示。它能表示很大的范围,但并不能精确表示所有十进制小数。

3.3 str:字符串

python 复制代码
language = "Python"
message = 'hello'

print(len(language))       # 6
print(message + " world") # hello world

单引号与双引号创建的都是 str,Python 没有独立的"单字符类型";"A" 仍然是长度为 1 的字符串。

python 复制代码
print(type("A"))  # <class 'str'>

字符串可以与字符串拼接,却不能直接与整数相加:

python 复制代码
age = 18
print("age = " + str(age))  # 可以,但更推荐 f-string
print(f"age = {age}")

# print("age = " + age)     # TypeError

3.4 bool:布尔值

python 复制代码
is_ready = True
is_finished = False

True 和 False 的首字母必须大写。从类型关系上说,bool 是 int 的子类,所以:

python 复制代码
print(True + 1)   # 2
print(False + 1)  # 1

这个行为在计数场景中偶尔有用,但不要为了"省一行代码"而让业务含义变得难懂。

3.5 动态类型是一把双刃剑

python 复制代码
value = 10
print(type(value))  # int

value = "ten"
print(type(value))  # str

好处是代码简洁、函数容易复用;代价是错误可能到运行时才出现。大型项目中可以通过清晰命名、单元测试、类型标注和静态检查降低沟通成本:

python 复制代码
def calculate_average(total: float, count: int) -> float:
    return total / count

类型标注主要服务于阅读与工具检查,Python 默认不会因为标注而自动在运行时强制类型。


四、注释与文档字符串

代码首先要能被人读懂,然后才是让计算机执行。注释的价值不在于"多",而在于它能否解释代码本身无法直接表达的意图、边界与取舍。

4.1 单行注释

# 之后到行尾的内容是注释:

python 复制代码
# 样本方差的分母使用 n - 1
variance = squared_error_sum / (sample_count - 1)

上面的注释说明了"为什么是 n - 1",比"计算方差"更有信息量。

4.2 docstring 不只是多行注释

三引号可以创建多行字符串。当它作为模块、函数、类或方法的第一条语句时,会成为文档字符串:

python 复制代码
def average(a: float, b: float) -> float:
    """返回两个数的算术平均值。"""
    return (a + b) / 2


print(average.__doc__)

它是一个真实的字符串对象,可被 help()、IDE 和文档生成工具使用。因此,不应把"任意位置写一个三引号字符串"当成 Python 的通用多行注释语法。

4.3 注释的四个检查点

  • 准确:代码改了,注释也要改;
  • 适量:既不写废话,也不留下无法理解的黑盒;
  • 解释意图:多回答"为什么",少重复"做了什么";
  • 专业:把注释视为团队文档,避免情绪化和攻击性内容。

五、控制台输入输出

用户向程序提供信息是输入 ,程序向用户展示结果是输出。图形界面、Web 页面和 API 都是交互方式,但学习阶段最直接的入口是控制台。

5.1 print() 输出

python 复制代码
name = "Ada"
age = 18

print("hello")
print(name)
print("name =", name, "age =", age)

print() 可以接收多个参数,默认用空格分隔,并在最后换行。可以通过 sep 和 end 修改:

python 复制代码
print("2026", "09", "24", sep="-")  # 2026-09-24
print("loading", end="...")
print("done")                          # loading...done

5.2 f-string:把值放进字符串

python 复制代码
name = "Ada"
score = 96.5

print(f"{name} 的成绩是 {score}")
print(f"成绩保留一位小数:{score:.1f}")

{} 中可以放变量,也可以放简单表达式:

python 复制代码
price = 19.9
count = 3
print(f"合计:{price * count:.2f} 元")

5.3 input() 的返回值永远是字符串

python 复制代码
age = input("请输入年龄:")
print(type(age))  # str

因此,下面的代码做的是拼接,不是数学加法:

python 复制代码
a = input("请输入 a:")  # 输入 10
b = input("请输入 b:")  # 输入 20
print(a + b)                  # 1020

需要先转换类型:

python 复制代码
a = int(input("请输入 a:"))
b = int(input("请输入 b:"))
print(a + b)  # 30

5.4 类型转换不一定成功

python 复制代码
# int("hello")  # ValueError

当输入不可信时,应使用异常处理:

python 复制代码
try:
    age = int(input("请输入年龄:"))
except ValueError:
    print("输入无效,请输入整数。")
else:
    print(f"明年你将 {age + 1} 岁。")

还有一个非常容易被忽略的点:

python 复制代码
print(bool("False"))  # True
print(bool(""))       # False

bool() 对字符串判断的是"是否为空",不会识别单词"False"的语义。


六、算术运算符

Python 常用算术运算符包括 +、-、*、/、%、**、//。

运算符 含义 示例 结果
+ 加法,也可用于字符串拼接 7 + 2 9
- 减法 7 - 2 5
* 乘法,也可用于序列重复 "ha" * 3 "hahaha"
/ 真除法 7 / 2 3.5
// 地板除 7 // 2 3
% 取余 7 % 2 1
** 幂运算 4 ** 2 16

6.1 除数不能为 0

python 复制代码
# print(10 / 0)  # ZeroDivisionError

除零错误不是程序"有点不准",而是当前计算无法继续,Python 会抛出异常。

6.2 // 是向下取整

python 复制代码
print(7 // 2)    # 3
print(-7 // 2)   # -4
print(int(-7 / 2))  # -3

-7 / 2 是 -3.5。// 向负无穷方向取整,所以得到 -4;int() 对浮点数转整数时则向 0 截断,所以得到 -3。两者不能混为一谈。

6.3 % 与取整方向配合

Python 满足这个关系:

text 复制代码
a == (a // b) * b + (a % b)

因此:

python 复制代码
print(-7 // 2)  # -4
print(-7 % 2)   # 1
# -7 == (-4) * 2 + 1

当负数参与取模时,不要只靠直觉猜结果,应回到上面的等式检查。

6.4 ** 不只能算整数次方

python 复制代码
print(4 ** 2)    # 16
print(4 ** 0.5)  # 2.0

对负数底数进行非整数次幂运算时,结果还可能进入复数范围:

python 复制代码
print((-1) ** 0.5)  # 近似为 1j

七、关系运算符与浮点数比较

关系运算符用来比较两个值,返回布尔结果:

python 复制代码
a = 10
b = 20

print(a < b)   # True
print(a <= b)  # True
print(a > b)   # False
print(a >= b)  # False
print(a == b)  # False
print(a != b)  # True

= 是赋值,== 才是相等比较。

7.1 字符串按字典序比较

python 复制代码
print("apple" < "banana")  # True
print("Zoo" < "apple")     # True

字符串比较是逐个字符按 Unicode 码点进行,它不等同于自然语言中面向用户的排序规则。大小写、重音符号和语言区域都可能影响期望结果。

7.2 链式比较

Python 可以直接写出贴近数学习惯的范围判断:

python 复制代码
age = 25
print(18 <= age < 60)

它等价于对中间值只求值一次的链式比较,语义接近:

python 复制代码
18 <= age and age < 60

7.3 浮点数不宜直接用 ==

python 复制代码
print(0.1 + 0.2)         # 0.30000000000000004
print(0.1 + 0.2 == 0.3)  # False

这不是 Python 的算术出错,而是许多十进制小数无法被有限位二进制浮点数精确表示。

不要只写一个神秘的固定差值,标准库的 math.isclose() 同时支持相对容差与绝对容差:

python 复制代码
import math

a = 0.1 + 0.2
b = 0.3

print(math.isclose(a, b))
print(math.isclose(a, b, rel_tol=1e-9, abs_tol=0.0))

如果比较的量可能接近 0,绝对容差往往也很重要:

python 复制代码
print(math.isclose(1e-12, 0.0, abs_tol=1e-9))  # True

容差应来自业务允许的误差范围,而不是为了"让测试通过"随意调大。金额等需要精确十进制语义的场景,通常应考虑 decimal.Decimal。


八、逻辑运算符与短路求值

Python 的逻辑运算符为 and、or、not:

  • A and B:只有两者都为真时整体才为真;
  • A or B:只要至少一个为真,整体就为真;
  • not A:对真值取反。
python 复制代码
age = 25
has_ticket = True

print(age >= 18 and has_ticket)
print(age < 18 or not has_ticket)

8.1 短路求值

对 and 而言,左边为假时,整体已经不可能为真,因此右边不再执行。对 or 而言,左边为真时,整体已经确定为真,右边也不再执行。

python 复制代码
print(False and 10 / 0)  # False,右侧未执行
print(True or 10 / 0)    # True,右侧未执行

短路常用于安全前置检查:

python 复制代码
denominator = 0

if denominator != 0 and 10 / denominator > 2:
    print("条件成立")

第一个条件为假后,除法不会执行,从而避免除零。

8.2 and 和 or 返回的不一定是 bool

这是从"会用"到"真正理解"的一个重要细节。and 与 or 返回的是决定结果的那个操作数:

python 复制代码
print("" or "guest")       # guest
print("Ada" and "online") # online
print(0 and 100)           # 0

Python 会对对象进行真值测试。常见假值包括 False、None、数字 0、空字符串与空容器。这种写法可用于默认值,但要小心把合法的 0 或空字符串也当成"缺失"。


九、赋值、拆包、复合赋值与交换

= 表示赋值,它按先右后左的思路工作:先计算右侧表达式,再把结果绑定给左侧名字。

9.1 链式赋值

python 复制代码
a = b = 10

a 与 b 会绑定到同一个整数对象。对整数这类不可变对象,通常很直观;对列表等可变对象则要特别小心:

python 复制代码
a = b = []
a.append(1)
print(b)  # [1]

这不是 b "偷看了" a,而是两个名字从一开始就绑定到同一个列表。

9.2 多元赋值与拆包

python 复制代码
name, age = "Ada", 18
print(name)
print(age)

左右数量应匹配,否则会触发 ValueError:

python 复制代码
# a, b = 1, 2, 3  # too many values to unpack

9.3 交换变量

python 复制代码
a = 10
b = 20
a, b = b, a

print(a, b)  # 20 10

可以概念上理解为:先取得右侧 b 和 a 的值,再按位置分别绑定给左侧 a 和 b,所以不需要手写临时变量。

9.4 复合赋值

python 复制代码
count = 10
count += 1
count *= 2
print(count)  # 22

Python 支持 +=、-=、*=、/=、//=、%=、**= 等复合赋值,但不支持 C/C++/Java 中的 ++ 和 --:

python 复制代码
count += 1   # 正确
# count++    # SyntaxError

值得注意的是,对可变对象而言,+= 可能就地修改原对象;它不能在所有类型上简单当成 x = x + y 的完全等价文本替换。


十、综合实战:一个更稳健的成绩计算器

现在把变量、类型转换、输入输出、算术运算、关系运算和逻辑运算组合起来。目标是:读取 4 门课成绩,验证范围,计算平均分,并输出是否合格。

python 复制代码
try:
    chinese = float(input("请输入语文成绩:"))
    math_score = float(input("请输入数学成绩:"))
    english = float(input("请输入英语成绩:"))
    python_score = float(input("请输入 Python 成绩:"))
except ValueError:
    print("输入无效:成绩必须是数字。")
else:
    all_valid = (
        0 <= chinese <= 100
        and 0 <= math_score <= 100
        and 0 <= english <= 100
        and 0 <= python_score <= 100
    )

    if not all_valid:
        print("输入无效:每门成绩必须在 0 到 100 之间。")
    else:
        total = chinese + math_score + english + python_score
        average = total / 4
        passed = average >= 60

        print(f"总分:{total:.1f}")
        print(f"平均分:{average:.2f}")
        print(f"结果:{'合格' if passed else '不合格'}")

这段代码体现了一条清晰的数据处理链路:

  1. input() 获得字符串;
  2. float() 尝试转换,失败时进入 except;
  3. 用链式比较和 and 验证范围;
  4. 用算术表达式计算总分和平均分;
  5. 用 f-string 格式化输出。

初学阶段重复写 4 次输入是为了突出当前语法知识。学习列表、循环和函数后,应把这段代码重构为更易扩展的形式。


十一、常见误区与自测练习

11.1 高频误区

误区一:把 = 当成相等比较

= 是赋值,== 是比较。a = 10 是让名字 a 绑定到数值 10,不是在做数学命题。

误区二:认为 input() 会自动识别数字

input() 返回 str。输入 10 不等于得到整数 10,算术计算前要用 int() 或 float() 转换。

误区三:认为 bool("False") 是 False

非空字符串的真值是 True。如果要解析用户输入的布尔文本,应显式定义可接受的词汇:

python 复制代码
raw = input("是否继续?(y/n) :").strip().lower()
should_continue = raw in {"y", "yes"}
误区四:对浮点计算结果直接用 ==

浮点误差是表示方式的结果。近似比较优先使用 math.isclose(),精确十进制业务要考虑 Decimal。

误区五:把 // 理解成单纯删掉小数部分

// 向负无穷取整,因此 -7 // 2 是 -4,不是 -3。

误区六:把三引号等同于通用多行注释

三引号创建字符串。放在模块、函数或类的开头时它是 docstring,会被工具与运行时元数据使用,并非普通注释。

误区七:认为 and 与 or 永远返回 True 或 False

它们根据真值测试决定是否继续,并返回其中一个操作数。需要布尔值时可显式使用 bool()。

11.2 自测题

  1. 1 + 2 * 3 和 (1 + 2) * 3 分别得到什么?
  2. 为什么 input() 读取的 "10" 与 "20" 相加得到 "1020"?
  3. int、float、str、bool 各适合表示什么数据?
  4. -7 // 2 与 int(-7 / 2) 分别是多少?
  5. 为什么 0.1 + 0.2 == 0.3 是 False?推荐如何比较?
  6. False and 10 / 0 为什么不会抛出除零异常?
  7. a = b = [] 后执行 a.append(1),b 是什么?为什么?
  8. bool("False") 的结果是什么?
  9. a, b = b, a 为什么可以交换两个变量?
  10. Python 为什么不支持 ++?应怎样写自增 1?

11.3 参考答案

  1. 分别是 7 和 9,括号改变了求值顺序。
  2. 因为 input() 返回 str,+ 对两个字符串表示拼接。
  3. 依次是整数、浮点数、文本字符序列、真假状态。
  4. 分别是 -4 和 -3;前者向下取整,后者向 0 截断。
  5. 许多十进制小数无法用有限位二进制浮点数精确表示;推荐使用 math.isclose() 并设置业务合理的容差。
  6. and 发生短路,左侧为假后右侧不再执行。
  7. b 也是 [1],因为 a 与 b 绑定到同一个可变列表。
  8. True,因为它是非空字符串。
  9. 概念上先对右侧求值,再按位置将结果绑定给左侧名字。
  10. Python 没有前置/后置自增运算符,直接写 value += 1。

总结

这一讲的知识点看起来很多,但可以收束成一条稳定的主线:

  1. 字面值提供数据,运算符把数据组成表达式;
  2. 变量是名字与对象的绑定,而不是固定类型的物理盒子;
  3. 类型决定表示与操作 ,int、float、str、bool 的规则不能随意混用;
  4. input() 返回字符串,转换类型时要考虑失败;
  5. 运算符不只是符号,还包含优先级、类型规则、取整方向和短路语义;
  6. 浮点数是近似表示,工程比较需要合理容差。

真正值得掌握的,不是每个符号孤立的读法,而是面对一行代码时能够按顺序问出:数据是什么类型?表达式按什么顺序求值?中间会不会转换、舍入或短路?最终又把结果绑定到哪个名字?

把这条思考链建立起来,后面学习条件、循环、函数和容器时,语法就不会再是零散的记忆点。


🔥 如果这篇文章对你有帮助,欢迎点赞、收藏与关注。

📚 下一篇继续学习 Python 的条件判断与循环结构。

相关推荐
jimy11 小时前
polymorph.cpp里面的“析构函数、智能指针”问题
开发语言·c++
m0_380743871 小时前
PHP 8.3 缓存清除不生效怎么排查
开发语言·php
happylifetree2 小时前
Python14:核心语法-数据存储与运算-字符串定义
python
hhb_6182 小时前
AIRAGDebug:一键定位RAG链路异常
人工智能·python·算法
朝朝辞暮i2 小时前
C++ 第 6 课:switch —— 多状态选择
开发语言·c++·算法
小静AI工程实验室2 小时前
asyncio.Queue 有界队列实战:背压、task_done、join 与异常收尾
python
小凡geo2 小时前
本地商家 GEO:用脚本一键生成 FAQPage 结构化数据,让 AI 切片更稳
开发语言·人工智能·python·microsoft·搜索引擎·ai
Zhou1411362 小时前
SpringBoot_03_Web开发
前端·spring boot·python
weixin199701080162 小时前
《1688物流API接口边界:logistics.trace.get 与 freight.template.list 的隐藏约束》(附Python源码)
windows·python·list