import math # 引入模块
print(math.sqrt(4)) # 调用模块内部的一个函数sqrt()2.0
一个.py文件,就是一个模块module,里面的函数、变量等等,可以被其他代码所调用。 (一个包含多个.py文件的文件夹通常称为“包(package)”,下文单独说明)
写程序时,我们通常会复用已有代码,而不是从头写所有功能。这些已有代码一般也是用模块的形式组织。包括我们后面主要用到的数据分析三件套。
常见模块大致可以分为三类:
math、random、datetime。通常不需要额外安装。numpy、pandas、matplotlib。本课程使用 Anaconda,许多常用第三方模块已经安装好。.py 文件,例如后面会用到的 my_calc.py。本章内容较多,可以按两个层次学习。
必修主线:导入模块、使用常用模块、编写自己的模块
.py 文件就是模块import 模块名import 模块名 as 别名模块名.函数名 使用模块内容from 模块名 import 对象名from 模块名 import *help()mathrandomstatisticsjson.dump() / json.load():读写本地 JSON 文件encoding="utf-8" 和 ensure_ascii=Falsedatetime.datetime.now()、datetime.date.today()、datetime.timedeltamy_calc.pyModuleNotFoundError 的基本排查进阶学习:字符串转换、导入路径、包和更多标准库用法
json.dumps() / json.loads():JSON 字符串与 Python 对象互转indent=2Pathos 模块time 模块calendar 模块strftime()、strptime()if __name__ == "__main__"sys.path 与导入路径__init__.pyPython作为一个发展了很多年的流行的编程语言,自带非常多的模块。我们安装的Anaconda,也格外把很多数据分析、科学计算等等的模块打包在一起。
例如用于数学运算的math,这是Python自带的模块,其中有大量数学函数,例如开平方根的sqrt。
引入模块也很简单
import <模块名>
import <模块名> as <模块的简称>
注意:在同一次 Python 运行过程、同一个脚本或 Notebook 中,import 一次后,后续代码就可以使用。因此,一般会把 import 语句放在代码的最前面。
我们可以用<模块名>.<函数名/变量名>来调用里面的函数或者变量,例如我们要调用math模块下的平方根sqrt()。
此时,模块内部的所有东西(函数、变量等),都必须通过<模块名>.来调用。
import math # 引入模块
print(math.sqrt(4)) # 调用模块内部的一个函数sqrt()2.0
或者math中的圆周率。
print(math.pi)3.141592653589793
也可以采用简称或者缩写,比如我们后面用到的NumPy,习惯上缩写成np
import numpy as np
print(np.sqrt(4)) # NumPy也有自己的开方函数!后面会讲2.0
这种方法让模块内部的函数或者变量名,直接出现在当前命名空间中(调用时不用再挂着模块的名字)。如果这个模块下的某些东西特别常用,这样可以少打一些字。
from <模块名> import <项目名>
from <模块名> import <项目名> as <项目别名>
还是引入math中的开平方函数sqrt。如果代码中频繁使用这个函数,可以直接导入 sqrt,后面就不需要每次都写 math.sqrt()。
同样,在同一次 Python 运行过程、同一个脚本或 Notebook 中,导入一次后,后续代码就可以使用。
from math import sqrt
print(sqrt(9))
print(sqrt(4))3.0
2.0
还可以一次性引入模块下的所有名字
from <模块名> import *
这样你引用模块下的所有对象,都不必通过模块名来调用。
注意: 这种方式一般不推荐。一个模块里面可能有大量函数和子模块。除非你很明白自己在做什么,否则引入大量你可能用不到、甚至不知道存在的名称,容易产生命名冲突或掩盖已有名称,降低可读性与可维护性。
一般建议:
import 模块名,例如 import math。import numpy as np。from 模块名 import 对象名。from 模块名 import *。注意,这里只列出少量常用模块。除了 sqrt() 这类含义比较明确的函数,一般不需要刻意记忆具体函数名。
重要:如何找到合适的模块和函数?
import math
help(math) # 查看math模块的帮助文档
help(math.sqrt) # 查看math.sqrt函数的帮助文档帮助文档很长,各位可以自行尝试。
常用的数学模块
# 部分math模块的函数
import math
# math.ceil(x): 返回大于或等于 x 的最小整数。
print(math.ceil(4.2)) # 输出 5
# math.floor(x): 返回小于或等于 x 的最大整数。
print(math.floor(4.8)) # 输出 4
# math.fabs(x): 返回 x 的绝对值。
print(math.fabs(-5)) # 输出 5.0
# math.exp(x): 返回 e^x。
print(math.exp(1)) # 输出 e
# math.log(x[, base]): 返回 x 的自然对数(底为 e)或指定底数的对数。
print(math.log(8, 2)) # 输出 3.0
# math.pow(x, y): 返回 x^y。
print(math.pow(2, 3)) # 输出 8.0
# math.sqrt(x): 返回 x 的平方根。
print(math.sqrt(16)) # 输出 4.0
# math.sin(x): 返回 x(弧度)的正弦。
print(math.sin(math.pi / 2)) # 输出 1.0
# math.cos(x): 返回 x(弧度)的余弦。
print(math.cos(0)) # 输出 1.0
# math.pi: 圆周率 π。
print(math.pi) # 输出 3.141592653589793
# math.e: 自然数 e。
print(math.e) # 输出 2.7182818284590455
4
5.0
2.718281828459045
3.0
8.0
4.0
1.0
1.0
3.141592653589793
2.718281828459045
用于生成随机数、抽样与打乱。设置种子以便结果可复现。
import random
random.seed(42) # 固定种子,结果可复现
print(random.random()) # 0~1 间随机浮点数
print(random.randint(1, 6)) # 含端点的随机整数
print(random.choice(['A','B','C']))
print(random.sample(range(10), 3)) # 不放回抽样
data = [1,2,3,4,5]
random.shuffle(data) # 就地打乱
print(data)0.6394267984578837
1
C
[4, 3, 8]
[5, 4, 3, 1, 2]
用于基础统计量。注意:stdev/variance 为“样本”统计量(n-1),pstdev/pvariance 为“总体”统计量(n)。
import statistics as stats
xs = [1, 2, 2, 3, 4]
print(stats.mean(xs)) # 均值
print(stats.median(xs)) # 中位数
print(round(stats.stdev(xs), 3)) # 样本标准差
print(round(stats.pstdev(xs), 3)) # 总体标准差2.4
2
1.14
1.02
和操作系统交互,处理文件等等
import os
# 获得当前目录
print("当前工作目录是:", os.getcwd())
# 获得当前目录下的文件列表
print("当前目录下的文件列表:", os.listdir())
# 测试一个路径(可以是文件或者文件夹)是否存在
print(os.path.exists('某个文件.txt'))JSON格式非常类似于字典。如果要把 Python 中的字典、列表数据对象保存到本地文件,可以先转为 JSON 格式再保存;读取时则反过来。
数据(字典、列表等) -> JSON 格式 -> 保存到本地文件(*.json)
从本地文件(*.json)中读取JSON对象 -> 数据(字典、列表等)
import json
# 对象 <-> JSON 字符串(便于本地文件/网络传输等场景)
# Dict/List -> JSON
obj = {"name": "Alice", "scores": [95, 88], "passed": True}
s = json.dumps(obj, ensure_ascii=False, indent=2) # 转为 JSON 字符串
print(s)
# JSON -> Dict/List
obj2 = json.loads(s) # 还原为 Python 对象(字典)
print(obj2["name"], obj2["scores"][0]){
"name": "Alice",
"scores": [
95,
88
],
"passed": true
}
Alice 95
演示:将字典(或列表)写入本地 JSON 文件 → 读取 → 修改 → 重新写到本地文件。
注意:下面的代码会创建或覆盖当前工作目录下的 example_data.json,因此这里不自动执行。
import json
from pathlib import Path
path = Path("example_data.json")
# 初始写入:dict -> 本地 JSON 文件
data = {"name": "Alice", "score": 95, "passed": True}
with open(path, "w", encoding="utf-8") as f:
json.dump(data,f, ensure_ascii=False, indent=2)
# 读取:本地 JSON 文件 -> dict
with open(path, "r", encoding="utf-8") as f:
obj = json.load(f)
print("读取:", obj)
# 修改并写回(覆盖写入)
obj["score"] += 3
obj["tags"] = ["midterm", "bonus"]
with open(path, "w", encoding="utf-8") as f:
json.dump(obj, f, ensure_ascii=False, indent=2)
# 再次读取验证
with open(path, "r", encoding="utf-8") as f:
obj = json.load(f)
print("读取:", obj)用来处理日期和时间
# datetime模块的一些常见用法
import datetime
# datetime.datetime.now(): 获取当前日期和时间。
now = datetime.datetime.now()
print(f"当前的日期和时间是: {now}") # 输出当前日期和时间
# datetime.date.today(): 获取当前日期。
today = datetime.date.today()
print(f"当前的日期是: {today}") # 输出当前日期
# datetime.timedelta(): 表示时间间隔。
# 创建一个时间间隔对象,表示1天和5分钟。
delta = datetime.timedelta(days=1, minutes=5)
# 时间加减
future = now + delta # 当前时间加上时间间隔
print(f"1天05分钟后的时间是: {future}") # 输出未来的日期和时间
past = now - delta # 当前时间减去时间间隔
print(f"1天05分钟之前的时间是: {past}") # 输出过去的日期和时间
# datetime.datetime.strftime(): 格式化日期和时间。
formatted_date = now.strftime("%Y-%m-%d %H:%M:%S")
print(f"时间格式化(注意会返回一个字符串): {formatted_date}") # 输出格式化后的日期和时间
# datetime.datetime.strptime(): 从字符串解析日期和时间。
parsed_date = datetime.datetime.strptime("2022-01-01 12:34:56", "%Y-%m-%d %H:%M:%S")
print(f"从字符串解析出日期和时间: {parsed_date}") # 输出从字符串解析出的日期和时间当前的日期和时间是: 2026-05-17 21:48:55.032684
当前的日期是: 2026-05-17
1天05分钟后的时间是: 2026-05-18 21:53:55.032684
1天05分钟之前的时间是: 2026-05-16 21:43:55.032684
时间格式化(注意会返回一个字符串): 2026-05-17 21:48:55
从字符串解析出日期和时间: 2022-01-01 12:34:56
注意:上述例子也表明了,datetime的对象和一个包含了日期的字符串是不同的。类比就是数字1和字符串"1"的区别。
此外,常用的 time 与 calendar 模块也很有用:
import time, calendar
# 计时:用于简单性能测量
t0 = time.perf_counter()
time.sleep(0.1) # 休眠 0.1 秒
elapsed = time.perf_counter() - t0
print(f"耗时约: {elapsed:.3f} 秒")
# 时间格式化(time 模块)
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(0))) # 本地时区的 1970-01-01
# 月历与每月天数(calendar 模块)
print(calendar.month(2024, 1))
print(calendar.monthrange(2024, 2)) # (该月第一天是星期几, 当月天数)耗时约: 0.104 秒
1970-01-01 08:00:00
January 2024
Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
(calendar.THURSDAY, 29)
更多范例:
from datetime import date, timedelta
import datetime, calendar
# 1) 计算两个日期相差多少天
d1 = date(2024, 1, 1)
d2 = date(2024, 3, 15)
print(f"从 {d1} 到 {d2} 相差 {(d2 - d1).days} 天")
# 2) 今天的 N 天之后是什么日期
N = 30
today = date.today()
print(f"今天是 {today} ,{N} 天后是 {today + timedelta(days=N)}")
# 3) 某年每个月的第三个星期四(使用 calendar.monthcalendar)
year = 2024
third_thursdays = []
for month in range(1, 13):
cal = calendar.monthcalendar(year, month)
th = calendar.THURSDAY # 星期四的索引
# 若第一周就有星期四,则第三个星期四在 cal[2][th];否则在 cal[3][th]
day = cal[2][th] if cal[0][th] else cal[3][th]
third_thursdays.append(datetime.date(year, month, day))
print("第三个星期四:", [d.strftime("%Y-%m-%d") for d in third_thursdays])从 2024-01-01 到 2024-03-15 相差 74 天
今天是 2026-05-17 ,30 天后是 2026-06-16
第三个星期四: ['2024-01-18', '2024-02-15', '2024-03-21', '2024-04-18', '2024-05-16', '2024-06-20', '2024-07-18', '2024-08-15', '2024-09-19', '2024-10-17', '2024-11-21', '2024-12-19']
要完成一个特定的项目,你可能会写很多代码。没有必要把所有代码都放在一个.py文件里。
一般可以把相关的代码放在一个.py文件中,然后在其他文件里用模块的方式调用。
例如,我们前面写过一个add函数,可以把2个数相加。
def add(x,y):
return x + y
print(add(1,2))3
也写过一个翻倍函数
def do_double(x):
return x * 2
print(do_double(2))4
这2个函数都可以归类为计算函数。我们可以把它们放到一个专门的文件中,例如my_calc.py。
你还可以保存变量,例如my_pi = 3.14
新建一个文件my_calc.py,把以下内容放进去,存盘。
注意: 为了方便,这里要求把my_calc.py文件放在你现在正在工作的.py的同一个目录下。
my_calc.py即可。否则:很可能会出现 ModuleNotFoundError: No module named 'my_calc' 的错误
def add(x,y):
return x + y
def do_double(x):
return x * 2
my_pi = 3.14在我们后续的任务中,如果要调用这2个函数,或者你自己定义的变量my_pi,就可以用 import 导入。
import my_calc
print(my_calc.add(3,2))
print(my_calc.my_pi)当然,如简称、直接导入名称等等,和前述一样。
以后,你就可以按照自己的逻辑组织模块。比如,把同类函数、常量和与特定任务相关的代码放在同一个模块中。
按逻辑把你的代码分类组织,是一个好习惯。
import my_calc as mc
from my_calc import add, my_pi
print(add(3, 2), my_pi)小提示: - 避免将你的文件命名为与标准库同名(如math.py、datetime.py),否则导入时会优先导入你的文件,导致冲突。 - 如果已经在同一个 Python 会话中导入过 my_calc,再修改 my_calc.py 后,重新 import my_calc 不一定会加载新内容。初学阶段最简单的做法是重启内核,或者重新运行脚本。 - 若需要在模块内放少量自测代码,可使用:
def add(x, y):
return x + y
if __name__ == "__main__":
# 仅当直接运行本文件时执行,不会在被导入时执行
print(add(1, 2))Python 导入模块时,会按照一定的路径顺序查找。这个查找范围和当前工作目录、sys.path 有关。注意,“当前工作目录”不一定等于“正在编辑的 .py 文件所在目录”。可用下述方法查看:
import sys
print(sys.path)常见 ModuleNotFoundError 排查: - 确认 .py 文件是否在当前工作目录或已被加入到 sys.path 的路径中。 - 如果文件就在旁边但仍然导入失败,检查运行代码时的当前工作目录是否正确。 - 检查文件/文件夹命名是否与标准库或已安装第三方包冲突。 - 确认是否在正确的环境中运行(如虚拟环境/conda 环境)。
包(package)是按目录组织的一组模块。一个包通常是一个包含多个 .py 文件的文件夹:
本课程前期主要会使用模块。包只需要先认识基本结构,知道它是“用文件夹组织多个模块”的方式即可。
my_pkg/
__init__.py
calc.py
utils.py
calc.py 示例:
def add(x, y):
return x + y使用方式:
from my_pkg.calc import add
print(add(1, 2))说明: - __init__.py 用于标识“普通包”,有助于明确包的边界,并可在其中暴露常用接口。 - Python 3.3+ 也支持“命名空间包”,可不含 __init__.py,多个目录可被视为同一个包的不同部分;初学阶段使用普通包更直观。