Python基础速通指南

2026-08-27 Python

一、Python 基础语法与数据结构

1.1 基础语法:不仅仅是“hello world”

Python 语法简洁,但企业级开发对代码的可读性健壮性有更高要求。核心包括:

  • 变量与数据类型:动态类型,但建议使用类型注解(Type Hints)提升代码可维护性。
  • 控制流if/elif/elseforwhile
  • 函数定义:使用def,支持默认参数、关键字参数、可变参数*args**kwargs注*)。
  • 异常处理:使用try...except...finally优雅地处理错误,避免程序崩溃。

入门案例:带类型注解与异常处理的用户数据处理器

from typing import Dict, List, Optional

def process_user_data(raw_data: List[Dict[str, str]]) -> Optional[Dict[str, int]]:
    """
    处理用户原始数据,统计活跃用户数量。
    企业级实践:使用类型注解增强可读性,加入异常处理增强健壮性。
    """
    try:
        active_count = 0
        for user in raw_data:
            # 使用 .get() 安全地获取字段,避免 KeyError
            if user.get('status') == 'active':
                active_count += 1
        return {"active_users": active_count}
    except Exception as e:
        # 记录异常日志(实际项目中会用 logging 模块)
        print(f"An error occurred: {e}")
        return None  # 优雅降级

# 测试数据
users = [{"name": "Alice", "status": "active"}, {"name": "Bob", "status": "inactive"}]
result = process_user_data(users)
print(result)  # 输出: {'active_users': 1}

注: """ 是跨行注释吗?

1.2 核心数据结构:选型决定性能

数据结构 特点 适用场景 时间复杂度(平均)
列表(List) 有序、可变 ,用方括号[]表示,如 fruits =["apple", "banana"] 频繁增删元素、需要保持顺序的集合 索引:O(1), 追加:O(1), 插入/删除:O(n)
元组(Tuple) 有序、不可变,用圆括号()表示,如 colors = ("red", "green") 作为字典的键、函数返回多个值、不需要修改的数据 索引:O(1)
字典(Dict) 键值对集合、无序(Python 3.7+ 保留插入顺序)、可变,用花括号{}表示,如 person = {"name": "Bob", "age": 25} 快速查找、关联数据 查找/插入/删除:O(1)
集合(Set) 无序、元素唯一,用花括号{}表示,如 unique_nums = {1, 2, 3} 去重、快速成员测试、集合运算(交集、并集) 查找/插入/删除:O(1)

入门案例:利用集合高效去重与交集运算

# 场景:分析两个数据源的客户ID,找出共同客户和所有唯一客户
customers_a = [101, 102, 103, 104]
customers_b = [103, 104, 105, 106]

set_a = set(customers_a)
set_b = set(customers_b)

# 共同客户(交集)
common_customers = set_a & set_b  # 或 set_a.intersection(set_b)
print(f"共同客户: {common_customers}")  # 输出: {103, 104}

# 所有唯一客户(并集)
all_customers = set_a | set_b  # 或 set_a.union(set_b)
print(f"所有客户: {all_customers}")  # 输出: {101, 102, 103, 104, 105, 106}

企业最佳实践:数据结构选型与优化详解*

  1. 优先使用元组代替列表:若数据无需修改,使用元组更安全、性能略优。元组可作为字典键,而列表不行。
  2. 用集合/字典进行成员判断:需要频繁检查元素是否存在时(如if x in container),使用集合或字典,其O(1)的查找速度远优于列表的O(n)。
  3. 列表头部操作频繁时用dequecollections.deque(双端队列)在列表两端进行插入/删除操作时性能远优于list。
  4. 善用推导式:列表、字典、集合推导式不仅简洁,且通常比显式循环更快。

二、文件操作 (File I/O)

2.1 基础回顾:安全读写

文件操作的核心是open()函数,务必使用with语句自动管理资源。

入门案例:安全地读取配置文件

# ✅ 最佳实践:使用 with 语句,文件会在代码块结束后自动关闭
try:
    with open('config.txt', 'r', encoding='utf-8') as file:
        content = file.read()
        print(content)
except FileNotFoundError:
    print("配置文件未找到,请检查路径。")
except Exception as e:
    print(f"读取文件时发生未知错误: {e}")

2.2 进阶技巧与最佳实践

  • 处理大文件永远不要一次性读取大文件(如几GB的日志)。应逐行读取或分块读取。
  • 批量操作:减少I/O次数,一次性写入大量数据比多次小量写入快得多。
  • 使用pathlib:Python 3.4+ 推荐的面向对象的路径操作库,比os.path更优雅。

企业最佳实践:高效处理大型日志文件

from pathlib import Path
import logging

# 配置日志(实际项目中会更复杂)
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

def process_large_log(file_path: Path, keyword: str) -> int:
    """
    逐行读取大型日志文件,统计包含特定关键字的行数。
    企业级实践:使用 pathlib,逐行处理避免内存溢出。
    """
    if not file_path.exists():
        logging.error(f"文件不存在: {file_path}")
        return 0

    count = 0
    try:
        # 使用 with 和 pathlib 打开文件
        with file_path.open('r', encoding='utf-8') as file:
            for line in file:  # 逐行迭代,内存友好
                if keyword in line:
                    count += 1
        logging.info(f"在 {file_path.name} 中找到 {count} 行包含 '{keyword}'")
        return count
    except Exception as e:
        logging.error(f"处理文件 {file_path} 时出错: {e}")
        return 0

# 使用示例
log_dir = Path("/var/log/myapp/")
# Path 对象支持 / 运算符拼接路径
process_large_log(log_dir / "app.log", "ERROR")

三、异步IO (asyncio)

3.1 基础概念与入门

asyncio 是处理 I/O 密集型任务(网络请求、数据库查询、文件读写)的利器。它通过单线程事件循环(Event Loop) 在等待 I/O 时切换到其他任务,实现并发。核心是 async/await 语法。

入门案例:并发执行多个模拟I/O任务

import asyncio
import time

async def task(name: str, duration: int):
    print(f"任务 {name} 开始,预计耗时 {duration} 秒")
    await asyncio.sleep(duration)  # 模拟 I/O 操作,如网络请求
    print(f"任务 {name} 完成")
    return f"{name} 的结果"

async def main():
    start = time.time()
    # asyncio.gather 并发执行所有协程
    results = await asyncio.gather(
        task("A", 2),
        task("B", 1),
        task("C", 3)
    )
    print(f"所有结果: {results}")
    print(f"总耗时: {time.time() - start:.2f} 秒")  # 约3秒,而非6秒

# 运行异步主函数
asyncio.run(main())

gather() 的核心作用是并发执行多个异步任务,并等待全部完成后,将结果按原始顺序汇总。这种设计保证了结果与输入的一一对应关系,方便在后续处理时知道哪个结果来自哪个任务。

那如何按任务完成的顺序获取结果?

如果业务逻辑需要在任务一完成就立刻处理其结果,而不是等待所有任务结束,可以使用 asyncio.as_completed()

asyncio.as_completed() 返回一个迭代器,你可以异步地遍历它。每次迭代会 await 出一个任务的结果,这个结果的顺序就是任务实际完成的顺序。

import asyncio

async def task(name, delay):
   await asyncio.sleep(delay)
   return f"{name} (耗时{delay}s)"

async def main():
   tasks = [
       task("A", 2),
       task("B", 1),
       task("C", 3)
   ]

   # as_completed 按完成顺序产出结果
   for coro in asyncio.as_completed(tasks):
       result = await coro
       print(f"完成: {result}")

   # 可能的输出顺序(任务B先完成,接着是A,最后是C):
   # 完成: B (耗时1s)
   # 完成: A (耗时2s)
   # 完成: C (耗时3s)

asyncio.run(main())

3.2 企业级最佳实践

  1. 区分I/O密集与CPU密集asyncio 对 I/O 密集型任务效果显著,但对 CPU 密集型任务无效,甚至会因阻塞事件循环而拖慢程序。
  2. 控制并发数量:使用 asyncio.Semaphore(信号量)限制同时运行的协程数量,避免压垮下游服务。
  3. 设置超时:使用 asyncio.wait_forasyncio.timeout (Python 3.11+) 为任务设置超时,防止无限等待。
  4. 使用 TaskGroup (Python 3.11+):更现代的结构化并发管理方式,能自动处理任务组的错误传播。
  5. 分层架构:将异步层(I/O)与同步业务逻辑层分离,便于测试和维护。

企业最佳实践:带流量控制和超时的异步HTTP客户端

import asyncio
import httpx  # 支持异步的 HTTP 客户端,比 aiohttp 更易用
from typing import List

async def fetch_url(client: httpx.AsyncClient, url: str, semaphore: asyncio.Semaphore):
    """使用信号量控制并发,并设置超时"""
    async with semaphore:  # 获取信号量,控制并发数
        try:
            # 设置单次请求超时 10 秒
            response = await client.get(url, timeout=10.0)
            return {"url": url, "status": response.status_code}
        except httpx.TimeoutException:
            return {"url": url, "error": "Timeout"}
        except Exception as e:
            return {"url": url, "error": str(e)}

async def fetch_all(urls: List[str], max_concurrent: int = 5):
    """并发获取多个 URL,控制最大并发数"""
    semaphore = asyncio.Semaphore(max_concurrent)
    async with httpx.AsyncClient() as client:
        tasks = [fetch_url(client, url, semaphore) for url in urls]
        # asyncio.gather 并发执行所有任务
        results = await asyncio.gather(*tasks)
    return results

# 使用示例
urls = ["https://httpbin.org/delay/1"] * 20  # 模拟20个耗时1秒的请求
results = asyncio.run(fetch_all(urls, max_concurrent=10))
success_count = sum(1 for r in results if 'error' not in r)
print(f"成功请求: {success_count}/{len(urls)}")

四、Requests 库

4.1 基础用法回顾

Requests 是同步 HTTP 客户端库的首选。

入门案例:发送GET请求并处理JSON响应

import requests

try:
    response = requests.get('https://api.github.com/events', timeout=5)
    response.raise_for_status()  # 如果状态码不是 2xx,会抛出 HTTPError
    data = response.json()  # 自动解析 JSON
    print(f"获取到 {len(data)} 条事件")
except requests.exceptions.RequestException as e:
    print(f"请求失败: {e}")

4.2 企业级最佳实践

  1. 使用 Session 对象复用连接requests.Session 会复用底层的 TCP 连接,显著提升性能(减少30%+连接耗时)。同时保持 Cookies 和 Headers 状态。
  2. 强制设置超时永远不要使用没有超时的请求,否则程序可能永久挂起。应分别设置 connectread 超时。
  3. 处理重试:使用 requests.adapters.HTTPAdapter 配置重试策略,应对网络抖动。
  4. 安全加固
    • 令牌管理:从环境变量或密钥管理服务(如 Vault)读取,禁止硬编码。
    • SSL验证:生产环境必须启用 SSL 证书验证(verify=True),这是默认行为。
  5. 日志与可观测性:记录请求ID、耗时、状态码等,便于问题追踪。

企业最佳实践:封装一个生产级的API客户端

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
import logging
import os
from uuid import uuid4

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class EnterpriseAPIClient:
    """企业级 API 客户端封装"""
    def __init__(self, base_url: str):
        self.base_url = base_url.rstrip('/')
        self.session = requests.Session()
        # 1. 配置重试策略
        retry_strategy = Retry(
            total=3,  # 总重试次数
            backoff_factor=1,  # 重试间隔
            status_forcelist=[429, 500, 502, 503, 504],  # 需要重试的HTTP状态码
        )
        adapter = HTTPAdapter(max_retries=retry_strategy)
        self.session.mount("http://", adapter)
        self.session.mount("https://", adapter)

        # 2. 设置默认 Headers
        self.session.headers.update({
            'User-Agent': 'MyApp/1.0',
            'X-Request-Id': self._generate_request_id()
        })

        # 3. 从环境变量读取令牌(安全实践)
        self.token = os.environ.get('API_TOKEN')
        if self.token:
            self.session.headers.update({'Authorization': f'Bearer {self.token}'})

    def _generate_request_id(self) -> str:
        """生成全局唯一的请求ID,用于链路追踪"""
        return f"req-{uuid4().hex[:16]}"

    def _log_request(self, method: str, url: str, **kwargs):
        """记录请求日志(脱敏处理)"""
        # 实际中可记录更详细的信息
        logger.info(f"Request: {method} {url}")

    def get(self, endpoint: str, params=None, **kwargs):
        """发送 GET 请求"""
        url = f"{self.base_url}/{endpoint.lstrip('/')}"
        self._log_request('GET', url)
        try:
            # 4. 强制设置超时 (连接超时5秒,读取超时30秒)
            response = self.session.get(url, params=params, timeout=(5, 30), **kwargs)
            response.raise_for_status()  # 抛出HTTP错误
            return response.json()
        except requests.exceptions.RequestException as e:
            logger.error(f"API请求失败: {e}", exc_info=True)
            # 可在这里实现更细粒度的错误处理,如401时刷新令牌
            raise

    def close(self):
        """清理资源"""
        self.session.close()

# 使用示例
if __name__ == "__main__":
    client = EnterpriseAPIClient("https://api.example.com")
    try:
        data = client.get("/users", params={"page": 1})
        print(data)
    finally:
        client.close()  # 确保会话被关闭

五、NumPy 库

5.1 基础回顾:向量化操作

NumPy 的核心是 ndarray,其精髓在于向量化操作——对整个数组执行运算,避免慢速的 Python 循环。

入门案例:向量化 vs. 循环的性能对比

import numpy as np
import time

# 创建一个大数组
size = 10_000_000
data = np.random.rand(size)

# 1. 使用 Python 循环
start = time.time()
result_loop = [x**2 for x in data]
print(f"循环耗时: {time.time() - start:.4f} 秒")

# 2. 使用 NumPy 向量化操作
start = time.time()
result_vectorized = data ** 2
print(f"向量化耗时: {time.time() - start:.4f} 秒")
# 向量化通常比循环快几十到几百倍

5.2 企业级性能最佳实践

  1. 优先使用内置函数 (ufunc):NumPy 的通用函数(如 np.sum, np.mean, np.dot)都是高度优化的 C 代码实现。
  2. 利用广播 (Broadcasting):对不同形状的数组进行运算时,善用广播机制,避免创建不必要的中间数组。
  3. 避免不必要的数组复制:理解视图(View)副本(Copy) 的区别。切片通常返回视图,修改视图会影响原数组,这能节省内存;需要独立数据时再显式使用 .copy()
  4. 选择合适的数据类型 (dtype):使用 float32 而非默认的 float64 可以节省一半内存,在精度允许的情况下提升性能。
  5. 考虑内存布局:根据操作是行优先还是列优先,选择 order='C'order='F'
  6. 使用 np.memmap 处理超大数据集:对于无法完全加载到内存的数据,使用内存映射文件。
  7. 利用 NumbaNumExpr 加速:对于极度复杂的计算,可以使用 Numba 的 JIT 编译或 NumExpr 加速。

企业最佳实践:优化的数据预处理管道

import numpy as np
from typing import Tuple

def preprocess_data(data: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
    """
    企业级数据预处理:标准化 + 特征工程
    实践:向量化操作、视图、选择合适dtype
    """
    # 1. 确保数据是 float32 以节省内存
    if data.dtype != np.float32:
        data = data.astype(np.float32)

    # 2. 计算均值和标准差(使用内置函数)
    mean = np.mean(data, axis=0)
    std = np.std(data, axis=0)

    # 3. 标准化 (使用广播)
    # 注意:这里 data - mean 会创建一个新数组,但这是必要的
    normalized = (data - mean) / (std + 1e-8)  # 避免除以零

    # 4. 特征工程:创建新特征(使用视图和向量化操作)
    # 假设 data 的最后一列是目标值,我们基于前两列创建交互特征
    # 使用视图避免复制
    feature1 = normalized[:, 0]
    feature2 = normalized[:, 1]
    interaction = feature1 * feature2  # 向量化乘法

    # 5. 合并特征 (使用 column_stack 而非多次 concatenate)
    # 注意:interaction 需要 reshape 成列向量
    features = np.column_stack([normalized, interaction.reshape(-1, 1)])

    return features, mean, std

# 生成模拟数据: 100万行,5列
data = np.random.rand(1_000_000, 5).astype(np.float32)
features, mean, std = preprocess_data(data)
print(f"处理后的特征形状: {features.shape}")  # (1000000, 6)

六、Pandas 库(企业级数据处理)

6.1 基础回顾:DataFrame 核心操作

Pandas 的 DataFrame 是数据分析的核心。

入门案例:数据加载、清洗与分组聚合

import pandas as pd

# 1. 创建示例数据
df = pd.DataFrame({
    'Name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
    'Department': ['HR', 'Engineering', 'Engineering', 'HR', 'Marketing'],
    'Salary': [70000, 85000, 90000, 72000, 65000]
})

# 2. 数据查看
print(df.head())
print(df.info())

# 3. 分组聚合:计算每个部门的平均薪资
avg_salary_by_dept = df.groupby('Department')['Salary'].mean()
print(avg_salary_by_dept)

6.2 企业级最佳实践

  1. 按需读取与类型优化:读取大型CSV时,指定 usecols 只读取需要的列,用 dtype 参数指定列类型以节省内存。
  2. 链式操作:使用 .query() 进行过滤,用 .assign() 创建新列,使代码更清晰。
  3. 使用 category 类型:将低基数的类别型列(如性别、地区)转为 category 类型,可大幅节省内存并提升 groupby 等操作的速度。
  4. 避免在循环中修改DataFrame:使用向量化操作或 apply(),但 apply() 本质上仍是循环,应优先使用内置的向量化方法。
  5. 建立数据管道:将清洗、转换、聚合等步骤封装成函数,形成可重复、可测试的数据处理管道。
  6. 从数据库读取时使用 read_sql_query:明确指定SQL语句,比 read_sql 更安全,可避免 SQL 注入风险。

企业最佳实践:构建可复用的数据清洗与报告管道

import pandas as pd
from pathlib import Path
from typing import Optional
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class DataPipeline:
    """企业级数据处理管道"""
    def __init__(self, raw_data_path: Path):
        self.raw_data_path = raw_data_path
        self.df: Optional[pd.DataFrame] = None

    def load_data(self) -> 'DataPipeline':
        """加载数据,并进行类型优化"""
        logger.info(f"Loading data from {self.raw_data_path}")
        # 企业实践:指定 dtype 和 usecols 优化内存
        dtypes = {
            'user_id': 'int32',
            'gender': 'category',  # 低基数列转为 category
            'age': 'int8',
        }
        self.df = pd.read_csv(
            self.raw_data_path,
            dtype=dtypes,
            parse_dates=['signup_date'],  # 自动解析日期
            encoding='utf-8-sig'  # 处理带 BOM 的 CSV
        )
        logger.info(f"Loaded {len(self.df)} rows, {len(self.df.columns)} columns")
        return self  # 支持链式调用

    def clean_data(self) -> 'DataPipeline':
        """清洗数据:处理缺失值、重复值、异常值"""
        if self.df is None:
            raise ValueError("Data not loaded. Call load_data() first.")

        logger.info("Cleaning data...")
        # 1. 删除完全重复的行
        initial_len = len(self.df)
        self.df.drop_duplicates(inplace=True)
        logger.info(f"Removed {initial_len - len(self.df)} duplicate rows")

        # 2. 处理缺失值:数值列用中位数,类别列用众数
        for col in self.df.select_dtypes(include=['number']).columns:
            self.df[col].fillna(self.df[col].median(), inplace=True)
        for col in self.df.select_dtypes(include=['category', 'object']).columns:
            if not self.df[col].mode().empty:
                self.df[col].fillna(self.df[col].mode()[0], inplace=True)

        # 3. 异常值检测 (IQR方法)
        for col in self.df.select_dtypes(include=['number']).columns:
            Q1 = self.df[col].quantile(0.25)
            Q3 = self.df[col].quantile(0.75)
            IQR = Q3 - Q1
            lower = Q1 - 1.5 * IQR
            upper = Q3 + 1.5 * IQR
            # 将异常值截断到边界(或标记,这里选择截断)
            self.df[col] = self.df[col].clip(lower=lower, upper=upper)

        return self

    def generate_report(self) -> pd.DataFrame:
        """生成聚合报告"""
        if self.df is None:
            raise ValueError("Data not loaded. Call load_data() first.")

        logger.info("Generating report...")
        # 使用 category 类型可加速 groupby
        report = self.df.groupby('gender').agg({
            'age': ['mean', 'std', 'count'],
            'user_id': 'count'
        })
        report.columns = ['_'.join(col).strip() for col in report.columns.values]
        return report

# 使用示例
if __name__ == "__main__":
    pipeline = DataPipeline(Path("./data/raw/users.csv"))
    # 链式调用,清晰直观
    report = pipeline.load_data().clean_data().generate_report()
    print(report)
    # 保存报告
    report.to_csv("./data/output/user_report.csv")

总结

模块 核心要点 企业级关键词
基础语法 类型注解、异常处理 可读性、健壮性
数据结构 列表、元组、字典、集合 选型、时间复杂度、内存优化
文件操作 with 语句、逐行读取 pathlib、资源管理、大文件处理
异步IO async/awaitasyncio.gather 信号量、超时、结构化并发
Requests Session、超时、异常处理 重试、安全令牌、可观测性
NumPy 向量化、广播、视图vs副本 内存布局、dtype、避免循环
Pandas DataFrame、groupby、链式操作 类型优化、数据管道、category

学习建议

  1. 循序渐进:确保基础语法和数据结构扎实,这是所有高级库的基石。
  2. 实践驱动:为每个模块编写小型项目,如用 asyncio + httpx 写一个并发爬虫,用 Pandas 分析一份真实的公开数据集(如Kaggle数据)。
  3. 性能意识:在编写代码时,时刻思考时间复杂度和内存占用,尤其是在处理大规模数据时。
  4. 参考官方文档:上述库的官方文档是最权威、最详尽的学习资源(https://docs.python.org/zh-cn/3.14/)。