刚开始接触Python的时候,我也有过那种“打开教程十分钟,关掉教程两行泪”的体验。3月15号这一天,我把之前零散折腾的东西重新梳理了一遍,从装环境到跑通一个小项目,踩了一圈坑,也理顺了不少概念。这篇文章就是当天学习记录的完整存档,适合刚起步的人照着走一遍,也适合那些装过几次环境、但始终没搞明白“为什么这么配”的朋友。
我们先划个范围:这一天主要解决四件事——把Python环境彻底装干净、理解变量与数据结构这些真正的基础、搞定numpy和pandas这两个绕不开的库、最后用一个小爬虫加一个简单的量化策略示例把前面的知识串起来。内容会有一点多,但都是实操过的,顺序也是按我当天踩坑的顺序来的,跟着走基本不会再被卡住。
1. 环境搭建:把Python装明白,别在第一步摔跤
1.1 安装与环境变量:双击下一步之外的事
很多初学者卡在第一步,不是不会下载,而是下载完了不知道怎么让系统认这个解释器。我这里说的“认”,就是要让cmd或者终端里直接敲python能进交互环境。
去官网下载安装包,Windows下注意勾选“Add Python to PATH”这个选项,这是最关键的。我见过太多人没勾这个,装完发现命令行里输入python显示“不是内部或外部命令”,然后去百度搜环境变量配置,越配越乱。其实这个选项就是帮你把Python的可执行文件路径写进系统环境变量的Path里,勾上就完事。
如果是Linux系统,建议直接用系统包管理器。Ubuntu和Debian系执行sudo apt install python3和sudo apt install python3-pip就行。这里有个坑,就是系统自带的Python版本可能比较旧,官网最新的Python 3.12或者3.13不一定在源里。我个人的建议是,学习阶段就用系统源里的Python 3.10或3.11,完全够用,不用非得追新版。
装完之后验证三件事。第一,命令行里输入python --version能显示版本号。第二,输入pip --version能显示pip版本。第三,命令行里敲python能进入交互模式,看到>>>提示符,说明解释器就跑起来了。
1.2 pip源配置与库安装:一次把numpy、sklearn、opencv装好
Python的库安装用的是pip,但默认官方源在国内访问速度不稳定,我当天安装numpy就卡了半天。解决办法是配置国内镜像源,最常用的是清华源和阿里源。
临时指定源安装的方法是:
pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple这样每次都得加参数,很麻烦。更靠谱的做法是永久配置。Windows用户在当前用户目录下建一个pip文件夹,里面建一个pip.ini文件,写入:
[global] index-url = https://pypi.tuna.tsinghua.edu.cn/simple [install] trusted-host = pypi.tuna.tsinghua.edu.cnLinux和macOS下文件路径是~/.pip/pip.conf,内容一样。配好之后,pip install的速度会明显提升。
我当天安装的库包括numpy、pandas、scikit-learn、opencv-python,命令如下:
pip install numpy pandas scikit-learn opencv-python这里有个很容易踩的坑,就是opencv的库名。PyPI上的包名不是cv2,而是opencv-python,导入的时候才写import cv2。直接把pip install cv2是装不上的,我见过太多人在这里卡住。另外,numpy和pandas这两个库如果是在官网下的Python安装包里装,基本不会遇到编译问题,因为官方源都有预编译的whl轮子文件。
还有一个小建议,装库之前先把pip升级一下,用python -m pip install --upgrade pip,这样能避免一些依赖解析的旧版障碍。
1.3 用VSCode把开发环境理顺
如果只用命令行里写代码,语法高亮和调试都是问题。我推荐装Visual Studio Code,原因无他,免费、轻量、插件生态好。
装完之后要装两个东西,Python插件和Pylance插件。Python插件提供运行和调试支持,Pylance负责代码补全和类型提示。装完插件之后有一个细节,就是必须选择正确的Python解释器。按下快捷键Ctrl+Shift+P,输入Python: Select Interpreter,然后选择你刚安装的那个Python版本。
为什么必须选解释器?因为VSCode本身不包含Python运行环境,它只是一个编辑器,运行代码要调用外部解释器。如果不选,插件会自动找一个解释器,很可能找到的是Windows应用商店下载的那个版本,跟你在官网装的路劲不一样,最后出现“明明装了库但VSCode里import报错”的问题。
我当天就遇到这个情况。命令行里import numpy很正常,VSCode里却报No module named 'numpy'。排查了半天,发现是解释器选错了,VSCode默认用的那个Python目录和pip安装包的目录不是同一个。这个问题几乎每个初学者都会遇到,必须记住一点:命令行里pip list能看到的包,和你当前解释器环境里的包,必须是一一对应的。判断方法是在VSCode终端里执行python -c "import sys; print(sys.executable)",看看当前Python解释器的路径,再执行pip --version看看pip绑定的路径,两者一致才说明环境是干净的。
2. 语法核心:变量、类型转换、函数、切片一次讲透
2.1 变量与类型:从内存角度理解“动态类型”
Python里的变量和Java、C语言有个很大的区别,就是变量本身没有类型,只有绑定的对象有类型。这句话听起来有点绕,我用生活里的例子解释一下。
变量名就像一张便利贴,你可以把它贴在手机上,也可以撕下来贴到遥控器上,便利贴本身没有“手机属性”或“遥控器属性”。Python里执行a = 1,就是把标签a贴在整数对象1上;执行a = "hello",就是把同一个标签撕下来贴到字符串对象"hello"上。这就是“动态类型”的意思。
但是有个细节要注意,整型和字符串之间的转换。我当天练习时写了一个求长方体体积的程序,需要用户输入长宽高,然后相乘。用户输入进来的默认都是字符串,直接用*号会报错,因为字符串不能和字符串相乘。这个时候就要类型转换:
length = float(input("请输入长:")) width = float(input("请输入宽:")) height = float(input("请输入高:")) volume = length * width * height print(f"长方体的体积是:{volume}")用float()而不是int()是有讲究的,因为长宽高有可能是小数,用int()会把小数部分直接砍掉,计算出来的体积就错了。
Python里常见的类型转换函数有int()、float()、str()、list()、tuple()、set()。这里有一个隐藏的点,就是bool()的转换规则。空列表、空字典、空字符串、0、None转换成布尔值时都是False,其他都是True。我当时做变量类型练习题的时候,老是记错这一点,后来总结了记忆方法:“空的东西都是假”。
2.2 列表与切片:下标从0开始再复习一遍
列表是Python里最常用的数据结构,切片操作更是高频中的高频。切片的语法是list[start:stop:step],左闭右开,也就是说start包含,stop不包含。
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 取前三个元素 print(numbers[0:3]) # [0, 1, 2] # 从第2个取到第6个 print(numbers[1:6]) # [1, 2, 3, 4, 5] # 每隔一个取一个 print(numbers[::2]) # [0, 2, 4, 6, 8] # 反转列表 print(numbers[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]倒序切片[::-1]这个写法很实用,比如判断一个字符串是不是回文,直接用s == s[::-1]就行。
切片还有一个容易被忽略的操作,就是通过切片批量替换元素。numbers[1:4] = [100, 200]会把索引1到3的元素替换成两个新元素。这个操作在处理数据清洗时很有用,比如把异常值批量替换掉。
2.3 定义函数:不要只关注def这一行
定义函数用def关键字,这个大家都会写,但初学者容易忽略两个点:参数默认值和返回值。
参数默认值适合处理“大部分情况用同一个值”的场景。比如写一个计算圆面积的函数,圆周率大多数时候取3.14就够了,偶尔要更精确的可以再传值:
def circle_area(radius, pi=3.14): return pi * radius ** 2 print(circle_area(5)) # 78.5 print(circle_area(5, 3.14159)) # 78.53975这里要记住花生口诀:带默认值的参数必须放在不带默认值的参数后面,否则解释器直接报语法错误。
Python函数还有一个特殊之处,就是返回多个值其实返回的是元组。def func(): return 1, 2,你拿到的是一个元组(1, 2),用两个变量接收时自动解包。我学到这里时做过一个练习,写一个函数同时返回商和余数,很自然就用上了这种特性。
关于函数的题外话是作用域。函数内部定义的变量默认是局部变量,不影响外部同名变量。如果确实需要在函数内部修改全局变量,要用global关键字声明。不过我个人建议,学习阶段尽量不要用global,先用“函数输入参数、返回值传结果”的模式,代码逻辑会更清晰,写复杂项目的时候少很多莫名奇妙的bug。
2.4 结构化数据与DataFrame:从字典到表格思维
学Python到一定阶段,就不能只处理单个变量了,要开始面对结构化数据。最简单的结构化数据形式是字典列表,也就是每个元素都是一个字典的列表。比如我当天练手时构造了三天的学习记录数据:
study_records = [ {"date": "3月13日", "hours": 2.5, "topic": "环境搭建"}, {"date": "3月14日", "hours": 3.0, "topic": "基础语法"}, {"date": "3月15日", "hours": 4.5, "topic": "数据分析基础"}, ]这种结构可以遍历,也可以根据需要筛选。但一旦数据量变大,比如几千条记录,用Python原生的列表和字典处理效率就低了,这时候就用上pandas的DataFrame。
DataFrame可以理解为一张“Excel表格”:有行有列,列有列名。从字典列表创建DataFrame只需要一行代码:
import pandas as pd df = pd.DataFrame(study_records) print(df)输出结果就是一张规整的表格。筛选数据也很直观,想看学习时长超过3小时的记录:
long_study = df[df["hours"] > 3] print(long_study)这里的df["hours"] > 3会生成一个布尔序列,True和False对每一行做个标记,然后df[...]只保留标记为True的行。这种方式叫做布尔筛选,刚接触会有点绕,但实际用起来频率极高,尤其是在后面做数据分析时,几乎每天都要写。
DataFrame的创建方式还有其他几种,比如直接传入嵌套列表再指定列名,或者从CSV读取。当天我只练了从字典列表创建,主要目的是把“列表操作”和“表格思维”衔接起来。
3. 常用库实战:numpy、pandas、cv2、sklearn的真实用法
3.1 numpy数组:为什么不能只用Python列表
很多人在学习numpy之前会有疑问:Python列表不是也能存储和操作数据吗,为什么还要单独装numpy?这个问题我在3月15号之前也有,后来彻底想明白了。
Python列表里每个元素都是完整的Python对象,内存开销大;而numpy数组存储的是连续的同类型数据,像C语言的数组一样紧凑。更重要的是,numpy支持“向量化运算”,也就是对整个数组直接进行数学运算,不用写循环。
比如要对一个列表里所有元素加1:
# 纯Python方式 data = [1, 2, 3, 4, 5] new_data = [x + 1 for x in data] # numpy方式 import numpy as np arr = np.array([1, 2, 3, 4, 5]) new_arr = arr + 1两种方式在一百万个元素的时候差距就非常明显了,numpy几乎是瞬间完成,而列表推导式要慢很多。
numpy创建数组的常用方法有np.array()从现有列表转换、np.arange()生成等差数列、np.linspace()生成指定数量的等间隔数列、np.zeros()和np.ones()生成全0或全1数组。
3.2 邻接矩阵:用numpy把图结构变成数组
当天还练习了构建邻接矩阵,这是图论和后续很多算法的基础。邻接矩阵就是用一个二维数组表示图中节点之间的连接关系。
假设有四个节点,节点之间的连接关系是:1连2、1连3、2连4、3连4。构建邻接矩阵的代码是:
import numpy as np size = 4 adj_matrix = np.zeros((size, size), dtype=int) edges = [(0, 1), (0, 2), (1, 3), (2, 3)] for i, j in edges: adj_matrix[i][j] = 1 adj_matrix[j][i] = 1 # 无向图需要对称 print(adj_matrix)输出结果:
[[0 1 1 0] [1 0 0 1] [1 0 0 1] [0 1 1 0]]这里需要注意索引从0开始,所以节点1对应下标0,节点4对应下标3。如果不做adj_matrix[j][i] = 1这一步,得到的就是有向图的邻接矩阵。这个练习虽然简单,但它把“数据结构”和“numpy数组操作”用实际场景串起来了,比单纯背语法有用得多。
3.3 pandas进阶:筛选、排序、汇总一次搞定
DataFrame除了创建和筛选,我当天还练了三个高频操作:排序、分组汇总、列计算。
排序用sort_values(),指定by参数为列名:
df_sorted = df.sort_values(by="hours", ascending=False)分组汇总用groupby()结合聚合函数。比如按主题统计学习总时长:
summary = df.groupby("topic")["hours"].sum()列计算就是通过已有列生成新列:
df["minutes"] = df["hours"] * 60这三个操作合起来基本覆盖了日常数据操作的大部分需求。这里有一个心得:pandas的groupby刚学的时候容易懵,它的处理逻辑其实是“拆分-应用-合并”三步。先按照某个列把大表拆成若干小组,然后对每个小组应用聚合函数(求和、平均、计数等),最后把结果合并回一张表。脑子里带着这个流程去看groupby,就不会觉得它是魔术,而是一个自然的数据加工流水线。
3.4 opencv与rapidocr:图像处理的入门组合
这次也简单练习了一下opencv-python,主要就是读取图片、改尺寸、显示。代码非常简单:
import cv2 img = cv2.imread("test.jpg") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) cv2.imwrite("test_gray.jpg", gray)这里有个新手坑:cv2.imread()如果路径不对不会报错,而是返回一个None,后续调用cvtColor就会报“'NoneType' object has no attribute”的错误。排查这个问题很简单,在读取后加一行判断:
if img is None: print("图片读取失败,请检查路径")后来我还试着用了rapidocr做文字识别。这个库的名字你可能不熟,它是一个基于paddleocr的轻量级OCR库,安装命令是pip install rapidocr_onnxruntime。当时跑通之后发现CPU占用特别高,识别一张图要等几秒。这个很正常,OCR本质上是目标检测加文字识别两个深度学习模型的串行推理,没有GPU加速的情况下CPU跑模型就是吃满核心。
如果要在CPU上优化体验,我的建议是先把图片压缩再送识别,或者在代码里限制推理线程数。rapidocr的配置参数里有cpu_math_thread_num,可以把默认线程数调低,减少CPU突发占用,识别速度变化不大,但机器不会突然卡顿。
3.5 sklearn:机器学习库的安装与第一个模型
scikit-learn是Python机器学习最常用的库,安装名字是scikit-learn,导入名字是sklearn。当天我用它跑了一个最简单的分类模型,数据集就用内置的鸢尾花数据:
from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import accuracy_score data = load_iris() X_train, X_test, y_train, y_test = train_test_split( data.data, data.target, test_size=0.2, random_state=42 ) model = KNeighborsClassifier(n_neighbors=3) model.fit(X_train, y_train) y_pred = model.predict(X_test) print("准确率:", accuracy_score(y_test, y_pred))这里面的train_test_split很重要,它的作用是把数据分成训练集和测试集,测试集大小通过test_size指定,random_state则是固定随机种子。固定随机种子这个细节很关键,如果不设置,每次运行拆分结果都不同,模型准确率也会波动,别人就没法复现你的结果;设置了之后,大家每次拆出的训练集和测试集完全一致,实验结果才能对比。
4. 两个应用方向:爬虫与量化策略的入门实践
4.1 写一个尊重规则的学习型爬虫
学完基础语法之后,很多人都会想爬点数据练手。我那天写了一个非常简单的爬虫,爬取一个公开的静态网页,然后提取标题信息。代码骨架如下:
import requests from bs4 import BeautifulSoup url = "https://example-news.com" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" } resp = requests.get(url, headers=headers, timeout=10) resp.encoding = "utf-8" soup = BeautifulSoup(resp.text, "html.parser") for title in soup.find_all("h2", class_="news-title"): print(title.text.strip())这里有几个细节值得说。第一,headers里设置User-Agent是必要的,很多网站会反爬,不设UA直接返回403或验证页面。第二,timeout=10是超时控制,避免请求挂住不放。第三,resp.encoding = "utf-8"是手动指定网页编码,因为有些网站没有在响应头里正确声明编码,requests自动判断可能会用ISO-8859-1解析中文,导致乱码。
关于爬虫,必须强调一个底线:爬虫只能爬取公开且有授权的数据,必须遵守目标网站的robots.txt规则,不能对网站造成访问压力,不能爬取个人隐私和敏感数据。爬虫的学习重点是理解HTTP请求、响应解析和数据处理流程,而不是“通吃一切”,更不能用爬虫做任何攻击性的行为。我这一天练的爬虫只跑了一次,没有做任何高频率请求,就是为了保证服务器和网站都安全。
4.2 一个极简的“金叉死叉”量化策略骨架
量化交易听着高级,但入门的关键其实还是数据处理和策略表达。我当天用pandas写了一个非常基础的移动均线策略骨架,没有接行情接口,也没有交易接口,纯粹是为理解策略结构而写的。
思路很简单:短周期均线上穿长周期均线时买入信号出现,下穿时卖出信号出现。
import pandas as pd # 模拟一组价格数据,实际使用时替换为真实行情 prices = pd.Series([10, 10.5, 10.8, 11.2, 11.0, 10.7, 10.9, 11.3, 11.6, 11.4]) df = pd.DataFrame({"close": prices}) df["ma5"] = df["close"].rolling(5).mean() df["ma10"] = df["close"].rolling(10).mean() df["signal"] = 0 df.loc[df["ma5"] > df["ma10"], "signal"] = 1 df.loc[df["ma5"] < df["ma10"], "signal"] = -1rolling(window).mean()是滚动均值计算,窗口大小就是均线周期。signal列只有1和-1两种取值,代表持币方向。完整的量化策略还包括回测和资金管理,但那个范围就大了,需要补充很多金融基础。
这里我要慎重提醒一下:量化策略的代码骨架用于学习完全没有问题,但真正拿去实盘是完全不够的。市场有交易成本、滑点、极端行情,还有过拟合风险。刚学Python的朋友不要把网上那些“源码”直接当成财富密码,先把数据处理基本功练扎实,再谈模型和策略。这一年我见过的所有靠量化赚钱的人,没有一个是在代码层面取巧的,都是先用大量时间研究数据和规则。
4.3 用中文词云做一个可视化小项目
爬虫拿到的数据或者单纯用文本数据,可以做一个可视化小项目来综合练手。词云的思路是统计一个文本中关键词的出现次数,然后用字体大小表示次数多少。
用wordcloud库加matplotlib实现:
from wordcloud import WordCloud import matplotlib.pyplot as plt text = "python numpy pandas sklearn opencv python python" wordcloud = WordCloud(font_path="simhei.ttf", width=800, height=600, background_color="white").generate(text) plt.imshow(wordcloud, interpolation="bilinear") plt.axis("off") plt.show()中文词云有一个必踩的坑:必须指定font_path为系统中文字体,比如simhei.ttf(黑体),否则生成的图片上全是方框。这个项目虽然简单,但它把文件读取、字符串处理、第三方库调用、可视化输出全部串起来了,作为阶段性的综合练手非常适合。
5. 常见问题排查与速查表
5.1 pip安装报错的三个高频原因
我这一天光在pip上就踩了几个坑,整理一下基本规律。
第一个报错是“WARNING: pip is being invoked by an old script wrapper”,说明你的pip命令路径不对,最稳妥的解决方法是改用python -m pip来执行所有pip命令,比如python -m pip install numpy。这样可以确保pip和当前Python解释器绑定在同一个环境。
第二个是“Could not find a version that satisfies the requirement”,常见原因有两个:库名拼写错误,或者Python版本太旧。比如新版本pandas要求Python 3.9以上,你装的是Python 3.7就会报这个错误。解决方法是先确认Python版本,再确认包名,如果包名没问题,去PyPI官网查一下这个包支持的Python版本范围。
第三个是编译错误,像error: Microsoft Visual C++ 14.0 is required。这种情况在Windows上装某些含C扩展的库时会出现,解决方法是优先下载预编译的whl文件安装,而不是直接让pip去编译源码。到PyPI官网搜索包名,在“Download files”页面找到对应系统和Python版本的whl文件,下载后用pip install 文件名.whl安装。
5.2 列表筛选与数据清洗的五个小技巧
当天在pandas和列表操作上总结了几个常用技巧。
一是列表去重并保持顺序:Python的set()去重会打乱顺序,要想保持原顺序,用字典的fromkeys方法:
data = [1, 2, 2, 3, 3, 3, 4] unique = list(dict.fromkeys(data))二是查找列表里重复元素的下标:
indices = [i for i, x in enumerate(data) if x == 3]三是DataFrame去重:df.drop_duplicates(subset=["date"]),只针对指定列判断重复,而不是要求整行完全一致。
四是DataFrame缺失值处理:df.dropna()删除含缺失值的行,df.fillna(0)用0填充。实际中我更常用fillna,因为删数据会损失信息,填充是更保守的做法。
五是根据条件批量修改数据,这也是pandas常用的loc操作:
df.loc[df["hours"] < 2, "level"] = "低强度" df.loc[df["hours"] >= 2, "level"] = "中高强度"5.3 一张常用问题排查速查表
| 现象 | 大概率原因 | 解决思路 |
|---|---|---|
| 命令行输入python无反应 | 环境变量没配好 | 安装时勾选Add to PATH,或手动添加Python目录 |
| VSCode里import不到已安装的库 | 解释器选错 | Ctrl+Shift+P选择正确解释器路径 |
pip install cv2报错 | 包名不对 | 正确包名是opencv-python,导入名才是cv2 |
| 爬虫中文乱码 | 编码解析错误 | 手动指定resp.encoding = "utf-8" |
| cv2读取图片后报NoneType错误 | 路径不对或文件名含中文 | 用绝对路径,并加if img is None判断 |
| matplotlib画图横坐标标签挤在一起 | 刻度标签密度过大 | 使用plt.xticks(rotation=45)旋转或plt.xticks(ticks, labels)手动控制 |
| DataFrame列名访问报错 | 列名拼写错误或含空格 | 用df.columns查看实际列名,字符串列名用df["my col"]访问 |
| numpy运算时报shape不匹配 | 数组维度不一致 | 用arr.shape逐个检查列维度,必要时用reshape或expand_dims |
| 函数修改外部变量无效 | 局部变量作用域问题 | 改用返回值返回结果,少用global |
| Python命令与pip命令对应版本不同 | 多个Python环境并存 | 统一用python -m pip执行安装;或使用虚拟环境venv |
我当天很大一部分时间其实都耗在排查这些问题上,后来发现规律:大多数环境问题,核心就是“各个工具绑定的解释器是不是同一个”。把这个本质想通了,很多报错都不用背,自己就能推导出来。
6. 学习记录之外的几点体会
这一天学下来,我最强烈的感受是:学Python不是背语法,而是把每个知识点放到场景里去用。就像切片,光是记住list[start:stop:step]没有任何意义,但当你想反转一个字符串、剔除一段异常数据、批量取某几列的时候,它就成了顺手的工具。刚入门时容易陷入“我再多看一章就动手”的状态,其实这是最无效的学习方式,代码能力百分之八十是在报错和修bug中长出来的。
我给自己定了一个小规矩,每天至少写一个小程序,不管多简单。哪怕只是一个“输入题目自动打分”的练习脚本,只要完整跑通了,语法、逻辑、查错的能力就都在涨。3月15号这天就是从环境搭建一路跑到策略骨架,每一步都亲手敲过代码,这份记录里所有代码片段我都运行过,你照着敲的时候如果遇到问题,回来看第5章的排查表,大概率能找到答案。
最后再分享一个小技巧。如果你也准备每天记录学习内容,建议用一个固定的Markdown文件存档,把当天遇到的报错原文、原因、解决方法、示例代码都写进去。这比看十篇别人的教程都有用,因为它是你亲自踩坑得出的经验,三个月后回来看就是自己专属的速查手册。我自己就是从这类记录里攒出了最初的排错直觉,后面写代码遇到奇怪问题,第一时间想起的不是网上教程,而是自己某天记录里的一句话。