跳转至

语法基础

本文介绍 Python 的语法基础,即不 import 任何包的情况下需要涉及到的内容,标准文档见 Reference - Python Docs 官网。

数据类型

Python 是动态类型语言,变量不需要声明类型,赋值时会自动确定类型。

Tip

Python 支持在声明变量时写上预期的数据类型,但并不会主动检查数据类型不匹配的错误,可以借助第三方 类型检查 工具来避免此类错误。

整型

Python
x: int = 10

浮点型

Python
y: float = 3.14

布尔型

Python
is_active: bool = True

字符串

基本用法:

Python
info: str = "Alice"

字符转义:

Python
1
2
3
info = "hello\tworld"  # hello    world

info = r"hello\tworld"  # hello\tworld

其中:

  • Python 会对其中的特殊字符转义,例如 \t 会被转义为一个 tab;
  • r 表示输出原始内容,不会对其中的内容进行转义。

字符模板 (f-string):

Python
1
2
3
age = 18.88
info = (f"My age is {age:.1f}, "
        f"and you?")  # My age is 18.9, and you?

其中:

  • 跨行字符串可以使用小括号包裹;
  • 模板中 :.1f 表示给浮点数四舍五入保留 1 位小数。

列表

可变序列。可以理解为线性表,\(O(1)\) 尾插入、\(O(1)\) 尾删除:

Python
# 初始化
fruits = ["apple", "banana", "cherry"]

# 尾插入
fruits.append("orange")

# 尾删除
fruits.pop()

# 删除第一个匹配到的元素
fruits.remove("banana")

print(fruits[0])    # 访问列表第一个元素
print(fruits[1:3])  # 切片,访问第二到第三个元素

列表推导式是创建列表的一种简洁方式:

Python
squares = [x**2 for x in range(5)]  # 生成 0 到 4 的平方
print(squares)

元组

不可变的序列类型,一旦创建不能修改:

Python
coordinates = (10, 20)
print(coordinates[0])  # 访问元组的第一个元素

字典

由键值对组成:

Python
1
2
3
4
5
person = {"name": "Alice", "age": 25}
person["age"] = 26           # 修改字典中的值
person["city"] = "New York"  # 添加新的键值对

print(person["name"])  # 访问值

集合

一个无序且不重复的元素集合:

Python
1
2
3
4
5
colors = {"red", "green", "blue"}
colors.add("yellow")  # 添加元素
colors.remove("green")  # 删除元素

print(colors)

运算符

Python 有以下 运算符

Bash
1
2
3
+       -       *       **      /       //      %      @
<<      >>      &       |       ^       ~       :=
<       >       <=      >=      ==      !=

Python 的 运算符优先级(越往下等级越低):

运算符 描述
(expressions...) 绑定或加圆括号的表达式
[expressions...] 列表显示
{key: value...} 字典显示
{expressions...} 集合显示
x[index] 抽取
x[index:index] 切片
x(arguments...) 调用
x.attribute 属性引用
await x await 表达式
** 乘方
+x, -x, ~x 正,负,按位非 NOT
*, @, /, //, % 乘,矩阵乘,除,整除,取余
+, - 加和减
<<, >> 移位
& 按位与 AND
^ 按位异或 XOR
| 按位或 OR
in, not in, is, is not, <, <=, >, >=, !=, == 比较运算,包括成员检测和标识号检测
not x 布尔逻辑非 NOT
and 布尔逻辑与 AND
or 布尔逻辑或 OR
if -- else 条件表达式
lambda lambda 表达式
:= 赋值表达式

流程控制

条件语句 ifelifelse 用于分支控制。

Python
1
2
3
4
5
6
age = 20

if age >= 18:
    print("成人")
else:
    print("未成年")

循环语句 forwhile 用于重复控制。

Python
1
2
3
4
5
6
7
8
9
# for 循环
for i in range(5):  # 输出 0 到 4
    print(i)

# while 循环
count = 0
while count < 3:
    print("count:", count)
    count += 1  # 增加 count 的值

函数

Python 使用 def 关键字定义函数。

Python
1
2
3
4
5
def greet(name):
    return "Hello, " + name

message = greet("Alice")
print(message)  # Hello, Alice

解包机制

Python 中的解包机制让参数传递变得更灵活。解包分成两类:

  • 函数定义处,收集参数。*args 用来接收多余的「位置参数」,而 **kwargs 用来接收多余的「关键字参数」;
  • 函数调用处,展开参数。* 用来展开序列(可迭代对象),** 用来展开字典。

解包机制的本质,是让 Python 的参数系统脱离固定形态,转而以更抽象的方式处理数据结构,使得语言表达能力在工程层面保持灵活却不混乱。

位置参数的收集与展开:

  • 函数定义处,用于接收任意数量的「位置参数」并将它们收集为一个元组:

    Python
    1
    2
    3
    4
    5
    6
    7
    8
    9
    def add_all(x, *args):
        print(type(args))  # <class 'tuple'>
        total = 0
        for value in args:
            total += value
        return total
    
    print(add_all(1, 2, 3))  # 5
    print(add_all(1, 2, 3, 4))  # 9
    
  • 函数调用处,把一个序列展开为多个位置参数:

    Python
    1
    2
    3
    4
    5
    6
    7
    8
    def add_all(*args):
        total = 0
        for value in args:
            total += value
        return total
    
    nums = [1, 2, 3]  # 或 set、tuple 等可迭代对象
    print(add_all(*nums))  # 等价于 add_all(1, 2, 3)
    

关键字参数的收集与展开:

  • 函数定义处,用于接收任意数量的「关键字参数」并将它们组织为一个字典:

    Python
    1
    2
    3
    4
    5
    def describe(**kwargs):
        print(type(kwargs))  # <class 'dict'>
        print(kwargs)  # {'name': 'Alice', 'age': 18}
    
    describe(name="Alice", age=18)
    
  • 函数调用处,把一个字典展开为多个关键字参数:

    Python
    1
    2
    3
    4
    5
    def f(**kwargs):
        print(kwargs)  # {'name': 'Bob', 'city': 'Singapore'}
    
    info = {"name": "Bob", "city": "Singapore"}
    f(**info)  # 等价于 f(name="Bob", city="Singapore")
    

    Tip

    字典解包是一种清晰、稳定、可扩展的方式,在 PydanticFastAPI 等框架中极为常见。例如,在构造 Pydantic 模型时,通常会将 JSON 反序列化得到的字典直接展开,模型内部再对字段进行验证:

    Python
    1
    2
    3
    4
    5
    6
    class User(BaseModel):
        name: str
        age: int
    
    data = {"name": "Tom", "age": 20}
    user = User(**data)
    

lambda

lambda 函数是一种简洁的匿名函数,通常用于简单的函数体。

Python
square = lambda x: x**2
print(square(5))  # 25

Python 是面向对象的语言,使用 class 关键字定义类。

Python
class Dog:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    # 强私有方法(前置双下划线)
    def __calculate_dog_years(self):
        """将狗的年龄转换为人类年龄"""
        return self.age * 7

    # 公有方法
    def get_human_age(self):
        # 在类内部可以正常调用
        human_age = self.__calculate_dog_years()
        return f"{self.name} is {human_age} years old in human years."


dog = Dog("Buddy", 3)

# 调用公有方法
print(dog.get_human_age())  # Buddy is 21 years old in human years

# 调用私有方法(报错)
print(dog.__calculate_dog_years())  # AttributeError

# 强制调用私有方法(不推荐)
print(dog._Dog__calculate_dog_years())  # 21

模块

模块即一个以 .py 为后缀的代码文件,其中可以包括类、函数、变量等任意 Python Object。

__all__

模块内的 __all__: list[str] 变量用来约束当前模块暴露出去的对象。有助于明确一个模块中哪些是可以公开调用的,哪些仅仅是内部使用的。

示例模块 cls_all.py
import math

__all__ = ["Demo", "GLOBAL_VAR"]

GLOBAL_VAR = "hello"

class Demo:
    def __init__(self):
        print(f"cos(1) = {math.cos(1)}")

def fun():
    print("this is function")
示例调用 main.py
1
2
3
from cls_all import *

print(globals())
程序输出(调整格式后)
{
    '__name__': '__main__',
    '__doc__': None,
    '__package__': None,
    '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001EA08FAC380>,
    '__spec__': None,
    '__annotations__': {},
    '__builtins__': <module 'builtins' (built-in)>,
    '__file__': 'e:\\python\\demos\\fastapi-demo\\src\\cls_all_main.py',
    '__cached__': None,
    'Demo': <class 'cls_all.Demo'>,
    'GLOBAL_VAR': 'hello'
}
示例模块 cls_all.py
import math

# __all__ = ["Demo", "GLOBAL_VAR"]

GLOBAL_VAR = "hello"

class Demo:
    def __init__(self):
        print(f"cos(1) = {math.cos(1)}")

def fun():
    print("this is function")
示例调用 main.py
1
2
3
from cls_all import *

print(globals())
程序输出(调整格式后)
{
    '__name__': '__main__',
    '__doc__': None,
    '__package__': None,
    '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000028A84E6C380>,
    '__spec__': None,
    '__annotations__': {},
    '__builtins__': <module 'builtins' (built-in)>,
    '__file__': 'e:\\python\\demos\\fastapi-demo\\src\\cls_all_main.py',
    '__cached__': None,
    'math': <module 'math' (built-in)>,
    'GLOBAL_VAR': 'hello',
    'Demo': <class 'cls_all.Demo'>,
    'fun': <function fun at 0x0000028A84EB0900>
}

异常处理

使用 tryexceptfinally 来处理可能的错误。

Python
1
2
3
4
5
6
try:
    x = 10 / 0  # 会抛出除零异常
except ZeroDivisionError:
    print("不能除以零")
finally:
    print("执行完毕")

迭代器与生成器

迭代器是可以遍历的对象,生成器则是使用 yield 来定义的惰性迭代器。

Python
# 迭代器
numbers = iter([1, 2, 3])
print(next(numbers))  # 1
print(next(numbers))  # 2

# 生成器
def count_up_to(limit):
    count = 1
    while count <= limit:
        yield count
        count += 1

gen = count_up_to(3)
print(next(gen))  # 1
print(next(gen))  # 2