import math # 引入模块
print(math.sqrt(4)) # 调用模块内部的一个函数sqrt()
2.0
一个.py
文件,就是一个模块module,里面的函数、变量等等,可以被其他代码所调用。 (一个包含多个.py
文件的文件夹通常称为“包(package)”,下文单独说明)
写任何一个程序之前,我们一般会尽量调用别人写好的代码(别人写好的不用白不用),这些代码一般也是用模块的形式组织。包括我们后面主要用到的数据分析三件套。
Python作为一个发展了很多年的流行的编程语言,自带非常多的模块。我们安装的Anaconda,也格外把很多数据分析、科学计算等等的模块打包在一起。
例如用于数学运算的math
,这是Python自带的模块,其中有大量数学函数(顾名思义),例如开平方根sqrt
就在其中。
引入模块也很简单
import <模块名>
import <模块名> as <模块的简称>
注意:只要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
,可能你的代码中使用特别多,所以懒得打math.sqrt()
,只想打sqrt()
同样,import一次,后续即可一直使用。
from math import sqrt
print(sqrt(9))
print(sqrt(4))
3.0
2.0
还可以一次性引入模块下的所有名字
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.718281828459045
5
4
5.0
2.718281828459045
3.0
8.0
4.0
1.0
1.0
3.141592653589793
2.718281828459045
用于生成随机数、抽样与打乱。设置种子以便结果可复现。
import random
42) # 固定种子,结果可复现
random.seed(print(random.random()) # 0~1 间随机浮点数
print(random.randint(1, 6)) # 含端点的随机整数
print(random.choice(['A','B','C']))
print(random.sample(range(10), 3)) # 不放回抽样
= [1,2,3,4,5]
data # 就地打乱
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
= [1, 2, 2, 3, 4]
xs 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
= {"name": "Alice", "scores": [95, 88], "passed": True}
obj = json.dumps(obj, ensure_ascii=False, indent=2) # 转为 JSON 字符串
s print(s)
# JSON -> Dict/List
= json.loads(s) # 还原为 Python 对象(字典)
obj2 print(obj2["name"], obj2["scores"][0])
{
"name": "Alice",
"scores": [
95,
88
],
"passed": true
}
Alice 95
演示:将字典(或列表)写入本地 JSON 文件 → 读取 → 修改 → 重新写到本地文件:
import json, os
from pathlib import Path
= Path("example_data.json")
path
# 初始写入:dict -> 本地 JSON 文件
= {"name": "Alice", "score": 95, "passed": True}
data with path.open("w", encoding="utf-8") as f:
=False, indent=2)
json.dump(data, f, ensure_ascii
# 读取:本地 JSON 文件 -> dict
with path.open("r", encoding="utf-8") as f:
= json.load(f)
obj print("读取:", obj)
# 修改并写回(覆盖写入)
"score"] += 3
obj["tags"] = ["midterm", "bonus"]
obj[with path.open("w", encoding="utf-8") as f:
=False, indent=2)
json.dump(obj, f, ensure_ascii
# 再次读取验证
print("修改后:", json.loads(path.read_text(encoding="utf-8")))
读取: {'name': 'Alice', 'score': 95, 'passed': True}
修改后: {'name': 'Alice', 'score': 98, 'passed': True, 'tags': ['midterm', 'bonus']}
用来处理日期和时间
# datetime模块的一些常见用法
import datetime
# datetime.datetime.now(): 获取当前日期和时间。
= datetime.datetime.now()
now print(f"当前的日期和时间是: {now}") # 输出当前日期和时间
# datetime.date.today(): 获取当前日期。
= datetime.date.today()
today print(f"当前的日期是: {today}") # 输出当前日期
# datetime.timedelta(): 表示时间间隔。
# 创建一个时间间隔对象,表示1天和5分钟。
= datetime.timedelta(days=1, minutes=5)
delta
# 时间加减
= now + delta # 当前时间加上时间间隔
future print(f"1天05分钟后的时间是: {future}") # 输出未来的日期和时间
= now - delta # 当前时间减去时间间隔
past print(f"1天05分钟之前的时间是: {past}") # 输出过去的日期和时间
# datetime.datetime.strftime(): 格式化日期和时间。
= now.strftime("%Y-%m-%d %H:%M:%S")
formatted_date print(f"时间格式化(注意会返回一个字符串): {formatted_date}") # 输出格式化后的日期和时间
# datetime.datetime.strptime(): 从字符串解析日期和时间。
= datetime.datetime.strptime("2022-01-01 12:34:56", "%Y-%m-%d %H:%M:%S")
parsed_date print(f"从字符串解析出日期和时间: {parsed_date}") # 输出从字符串解析出的日期和时间
当前的日期和时间是: 2025-10-11 14:51:48.159113
当前的日期是: 2025-10-11
1天05分钟后的时间是: 2025-10-12 14:56:48.159113
1天05分钟之前的时间是: 2025-10-10 14:46:48.159113
时间格式化(注意会返回一个字符串): 2025-10-11 14:51:48
从字符串解析出日期和时间: 2022-01-01 12:34:56
注意:上述例子也表明了,datetime的对象和一个包含了日期的字符串是不同的。类比就是数字1
和字符串"1"
的区别。
此外,常用的 time
与 calendar
模块也很有用:
import time, calendar
# 计时:用于简单性能测量
= time.perf_counter()
t0 0.1) # 休眠 0.1 秒
time.sleep(= time.perf_counter() - t0
elapsed 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.105 秒
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) 计算两个日期相差多少天
= date(2024, 1, 1)
d1 = date(2024, 3, 15)
d2 print(f"从 {d1} 到 {d2} 相差 {(d2 - d1).days} 天")
# 2) 今天的 N 天之后是什么日期
= 30
N = date.today()
today print(f"今天是 {today} ,{N} 天后是 {today + timedelta(days=N)}")
# 3) 某年每个月的第三个星期四(使用 calendar.monthcalendar)
= 2024
year = []
third_thursdays for month in range(1, 13):
= calendar.monthcalendar(year, month)
cal = calendar.THURSDAY # 星期四的索引
th # 若第一周就有星期四,则第三个星期四在 cal[2][th];否则在 cal[3][th]
= cal[2][th] if cal[0][th] else cal[3][th]
day
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 天
今天是 2025-10-11 ,30 天后是 2025-11-10
第三个星期四: ['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个函数,显然都可以归类为计算函数,我们把这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
= 3.14 my_pi
在我们后续的任务中,如果要调用这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
),否则导入时会优先导入你的文件,导致冲突。 - 若需要在模块内放少量自测代码,可使用:
def add(x, y):
return x + y
if __name__ == "__main__":
# 仅当直接运行本文件时执行,不会在被导入时执行
print(add(1, 2))
Python 导入模块的搜索路径由当前工作目录和 sys.path
决定。可用下述方法查看:
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
,多个目录可被视为同一个包的不同部分;初学阶段使用普通包更直观。