简介:面向Python初学者的核心知识点与基础语法完整汇总,内容覆盖数字、字符串、列表、元组、字典、集合与文件等内置对象类型,并系统讲解输入输出、变量定义、数据格式化、索引运算、条件判断及循环控制等基础语法;同时进一步涉及函数、模块、类等编程单元类型,以及与Python实现相关的编译代码堆栈跟踪等进阶概念,适合复习备考和日常查阅。资料包共含862个文件,压缩后约100.52MB,文件类型以c/h源文件、asm汇编、html文档、txt、pdf/docx为主,还包含若干工程配置与工具文件,可配合说明文档对照研读。目前已有218人学习下载,内容组织较为系统,讲解通俗易懂,能够帮助学习者快速构建核心知识框架并查漏补缺。无论用于系统学习还是快速回顾,都能提供扎实的参考。
1. Python知识点不建索引,三个月就还给课程
Python知识点又多又杂,从内置类型到语法糖,再到各种库,如果没有一条主线,刚学完的核心知识点很快就会被遗忘。我最近给团队做了一次基础复盘,发现真正影响写码质量的,不是会不会用框架,而是对对象类型的理解深浅。比如有人把可变对象当默认参数,有人用+拼接大量字符串,还有人看不懂字典查询为什么这么快。这篇文章按“对象类型→基础语法→实战→陷阱”的顺序,把最常用的Python知识点过一遍。适合准备机试、刷PTA、或者想系统梳理Python编程基础的读者。下面所有代码在Python 3.8+验证过,重点是能复现、能排查。
2. 内置对象类型:先搞懂可变与不可变,再做其他
2.1 不可变类型:数字、字符串、元组
2.1.1 数字:int/float/complex/bool
Python常见的数字类型有int、float、complex,布尔型bool是int的子类。这个继承关系有一个直接后果:True参与算术时会被当成1,用is判断时要注意与1的区别。
print(True == 1) # True,值相等 print(True is 1) # False,身份不同 print(isinstance(True, int)) # True逻辑说明:==比较的是值是否相等,is比较的是两个名字是否指向同一个内存对象。在CPython里,小整数有缓存池,但True和1不是一个实例,因此is返回False。所以任何涉及“是不是同一个数字”的判断,都不要用is,否则在-5到256范围之外的整数上会得到意外结果。
数字还有进制表示:0b前缀二进制,0o八进制,0x十六进制。实际写脚本时常用int(x, base)做进制转换,例如int('FF', 16)返回255。遇到“用户输入一个带0x的字符串”这种场景,int(x, 0)可以自动识别前缀,这个细节能省掉很多手工处理。
2.1.2 字符串:索引切片与格式化
字符串是不可变序列,每次修改其实都创建了新对象。最常见的错误是用+在循环里拼接字符串,复杂度是O(n²)。正确做法是先用列表收集,最后''.join()。
words = ['Python', '核心', '知识点'] sentence = ' '.join(words) # 推荐:一次性分配内存 bad = '' for w in words: bad += w + ' ' # 不推荐:每次循环都创建新字符串提示:需要频繁拼接时,用列表或
io.StringIO,不要用+=。
字符串索引用方括号,s[0]取第一个字符,s[-1]取最后一个。切片s[start:stop:step]支持负步长,s[::-1]就是完全逆序。切片越界不会报错,而是自动截断到边界,利用这一点可以安全地取“前三个字符”而不用担心字符串长度不够。
2.1.3 元组:不可变列表的边界
元组的内容不可变,但里面若存放了可变对象,那个可变对象仍然可以改。这个特性经常被误解,面试里也常问。
t = ([1, 2], 3) t[0].append(4) print(t) # ([1, 2, 4], 3)参数说明:元组只保证最外层元素的引用不变,不保证引用指向的对象不变。写多线程程序时,想用元组做只读共享,必须确认内部没有可变对象。如果确实需要可哈希的只读结构,可以使用frozenset或自定义不可变类。
2.2 可变容器:列表、字典、集合
2.2.1 列表的增删改查与内存
列表是动态数组,尾部append和pop是O(1)摊销,头部insert(0, x)和pop(0)是O(n)。如果需要在头部频繁操作,应该用collections.deque。
from collections import deque dq = deque([1, 2, 3]) dq.appendleft(0) dq.popleft()参数说明:deque是双端队列,两端增删都是O(1)。但它不是线程安全的,多进程/多线程场景下加锁方式与列表不同。列表排序也有两个选择:list.sort()原地排序返回None,sorted()返回新列表。用key参数指定排序依据,常见的是key=lambda x: x[1],如果要按字符串长度排,直接key=len。
2.2.2 字典的键约束与查询
字典的键必须可哈希(hashable)。可变对象列表、集合、字典都不能当键,元组只要内部没有可变对象也可以当键。这个约束来自底层哈希表实现,键的哈希值决定存储位置,所以查询速度接近O(1)。字典键不能重复,重复赋值会覆盖旧值。
d = {'a': 1, 'b': 2} print(d.get('c', 0)) # 0,不会抛KeyError merged = {**d, 'c': 3} # Python 3.9+可以用 d | {'c': 3}注意get的第二个参数是默认值,不写则返回None。用d['c']会抛KeyError,在解析外部配置时,get更安全。合并字典时,{**d1, **d2}在Python 3.5+可用,3.9之后推荐d1 | d2,后者语义更直观,且支持原地更新d1 |= d2。
2.2.3 集合的去重与集合运算
集合本质是不重复元素的哈希表。去重时直接用set(list),但顺序可能丢失。如果既要保持顺序又要去重,常见做法是遍历并用set记录已见元素。
items = [3, 1, 3, 2, 1] seen = set() result = [] for x in items: if x not in seen: seen.add(x) result.append(x) print(result) # [3, 1, 2]逻辑说明:这个写法的时间复杂度是O(n),因为x not in seen是哈希查找。如果先用list(set(items))再去排序,时间复杂度变为O(n log n),而且会丢失原始相对顺序。集合运算&、|、-分别对应交集、并集、差集,在做两份数据的共同用户、新增用户分析时非常实用。
2.3 文件对象:读写上下文与缓冲
文件操作推荐用with open(...) as f,离开代码块自动关闭文件,不用手动close()。读写模式需要记清楚:r只读、w覆盖写、a追加、rb/wb二进制。参数encoding要显式指定。
with open('data.txt', 'w', encoding='utf-8') as f: f.write('你好\n') with open('data.txt', 'r', encoding='utf-8') as f: content = f.read()参数说明:encoding='utf-8'必须写明确。在Windows上默认编码可能是gbk,不带encoding直接读写中文很容易报UnicodeEncodeError或UnicodeDecodeError。爬虫拿到网页经常是utf-8或gbk,读取时要先试探编码,比如用chardet判断后再传encoding。另外,read()读全部内容,readline()读一行,readlines()返回行列表;处理大文件时,最省内存的做法是for line in f:,因为它按行迭代,不会一次性读入整个文件。
下表整理了常用内置类型的核心特征,方便对照选择:
| 类型 | 可变性 | 是否可哈希 | 典型用途 |
|---|---|---|---|
| int/float/complex | 不可变 | 是 | 数值计算 |
| str | 不可变 | 是 | 文本 |
| tuple | 不可变 | 可哈希(若元素可哈希) | 只读序列 |
| list | 可变 | 否 | 动态序列 |
| dict | 可变 | 否 | 键值映射 |
| set/frozenset | 可变/不可变 | 否/是 | 去重、集合运算 |
| file | 可变状态 | 否 | I/O |
3. 基础语法:从输入输出到循环,所有脚本都逃不开这几行
3.1 输入输出与变量定义
input()读取一行,返回字符串。如果要做数值计算,必须先转换。这一条看着简单,很多报错都来自忘记转换类型。
a = input("输入数字:") # 此时a是str b = int(a) # 不转换就做乘法,结果会是字符串重复参数说明:input()的提示参数是可选的,但在交互式脚本里写上提示能显著降低使用门槛。变量定义方面,Python是动态类型,不需要声明类型,但建议用类型注解x: int = 1,IDE能提示,运行时也不强制。类型注解在多人协作时帮助很大,配合mypy可以做静态检查。
3.2 数据格式化拼接:f-string、%和format
三种格式化方式中,f-string(Python 3.6+)最直观,运行速度也最快。它支持在花括号里写表达式,比如f"{name.upper()}"。
name = "Python" version = 3.11 print(f"我是{name} {version},今年{2025 - 1991}岁") print("我是%s %s" % (name, version)) # 老式% print("我是{} {}".format(name, version)) # format提示:f-string里的花括号要输出字面量时,写成
{{和}}。
%格式化在日志模块等老代码里很常见,format适合需要模板复用的场景。如果字符串里包含大量花括号,比如JSON模板,用%或format需要转义,这时可以考虑string.Template。
3.3 条件判断与循环控制
if/elif/else靠缩进区分代码块,缩进必须一致,不能混用Tab和空格。循环有for和while,for适合迭代对象,while适合不知次数的循环。break跳出整个循环,continue跳过本次继续下一次。
for i in range(5): if i == 2: continue if i == 4: break print(i) # 输出0 1 3参数说明:range(start, stop, step)的stop是开区间,不包含stop本身。range(5)等价于range(0,5,1)。step可以是负数,比如range(5,0,-1)输出5到1。在数据处理中,range经常配合len来同时访问索引和元素,但更Pythonic的写法是用enumerate。
3.4 索引与切片:从单元素到步长
序列类型都支持索引和切片。索引从0开始,负数从尾部开始。切片[start:stop:step]中,start包含,stop不包含。灵活使用步长的典型场景:取偶数下标l[::2]、逆序l[::-1]、二维列表转置list(zip(*matrix))。
s = "Python知识点" print(s[0]) # P print(s[-1]) # 点 print(s[1:5]) # ytho print(s[::-1]) # 点识知nohtyP参数说明:[::-1]的意思是,从尾部开始,每次步进-1,直到头部,结果就是完全逆序。如果只需要逆序后取前几个,可以写成s[::-1][:n],但更高效的是s[:-n-1:-1],不过可读性差。日常开发中优先保证可读性,用reversed(s)或先逆序再切片都可以。
3.5 enumerate与zip:循环里最常用的两个内置函数
遍历列表时经常需要同时拿索引和值,初学者会用range(len(lst))再取lst[i]。更简洁的写法是enumerate(lst),它返回索引和值组成的元组。
colors = ['red', 'green', 'blue'] for idx, color in enumerate(colors): print(idx, color) # 0 red 1 green 2 bluezip用于并行迭代多个等长序列,返回元组。如果序列长度不一致,zip默认截断到最短,zip_longest可以用填充值补齐。
names = ['A', 'B', 'C'] scores = [88, 92, 85] for name, score in zip(names, scores): print(f"{name}: {score}")参数说明:enumerate还有一个可选的start参数,比如enumerate(colors, start=1)可以让索引从1开始,输出题目序号很方便。zip(*matrix)是二维列表转置的经典写法,*号把外层列表解包成多个参数。如果转置后要恢复列表形式,后面要加list(map(list, ...))。
4. 实战:用核心知识点解PTA“说反话-加强版”
4.1 题目拆解:输入解析与存储
PTA上有一道经典的“说反话-加强版”,要求把一句英文的单词倒序输出,单词之间用一个空格分隔。输入中可能包含连续空格,行首行尾也有空格。核心考点正是字符串分割、列表操作和输出格式控制。
先看输入处理。常见做法是用sys.stdin.readline()读取一行。PTA题目通常有多组测试数据,也可以用sys.stdin.read()读取全部输入后再按行处理。
import sys def main(): line = sys.stdin.readline() if not line: return words = line.split() print(' '.join(words[::-1])) if __name__ == "__main__": main()逻辑说明:split()不传参数时,会把连续空格、Tab、换行全部当成一个分隔符,并且自动过滤掉首尾空格产生的空字符串。这比split(' ')更稳妥,因为split(' ')遇到连续空格会生成空串,需要再过滤。这道题要求输出时单词间只有一个空格,所以用split()配合join是最简洁的方案。
4.2 单词逆序的三种写法
逆序输出有两种思路:一种是切片反转整个列表,另一种是从后往前遍历。切片方式最简洁,但在数据量极大时,要额外生成一个列表;遍历方式可以节约一点内存,但代码稍长。
# 方式一:切片,简单直观 rev = words[::-1] # 方式二:内置 reversed,惰性取值 rev2 = list(reversed(words)) # 方式三:索引倒序遍历,适合边取边处理 for i in range(len(words) - 1, -1, -1): ch = words[i] # 这里可以做额外处理,比如过滤标点参数说明:reversed(words)返回的是迭代器,不能直接打印,要用list()转成列表,或者用' '.join(reversed(words))。第二种写法如果和join搭配,可以不生成中间列表,节省内存。第三种写法适合在倒序遍历时对每个单词做额外操作,比如统一转小写、过滤非字母字符。
4.3 边界处理:多余空格与空行
如果输入为空行,split()得到空列表,join会得到空字符串。此时应该直接输出空行,还是不输出?PTA题目对此有明确要求,需要先读题。通常做法是判断是否有单词再输出。
if words: print(' '.join(words[::-1]))如果输入里包含大写字母、标点,这个写法会把标点留在单词上,比如Hello,输出还是Hello,。如果题目要求只保留字母,就需要用正则re.findall(r'[A-Za-z]+', line)来抽词。这就是“说反话-加强版”比基础题更进一层的地方:它考察了字符串分割的边界情况,而不只是简单的[::-1]。
4.4 多组输入直到EOF
PTA部分题目会连续给多行输入,直到EOF。这时就不能只读一行,需要用sys.stdin.read().splitlines()或for line in sys.stdin。
import sys for line in sys.stdin: words = line.strip().split() if words: print(' '.join(words[::-1]))逻辑说明:for line in sys.stdin会按行迭代,直到文件结束。strip()去掉行尾的换行符,split()再切出单词。这样即使有多个测试用例,循环也能完整跑完。注意,line.strip().split()与line.split()的区别在于:split()本身会丢弃空串,但line.strip()能额外去掉行首行尾的空白字符,让输出更干净。如果输入行里只有空格,words为空,不会输出多余行。
5. 进阶:类型转换与可变对象共享的三个真实陷阱
5.1 隐式类型转换
int和float运算会把结果转成float,这是隐式转换。但是True + 1得到2这个结果,容易让人踩坑。
print(True + 1) # 2 print(int(3.7)) # 3,直接截断小数位 print(int("12", 8)) # 10,把"12"当成八进制解析参数说明:int("12", 8)里的8是基数参数,表示把字符串按八进制解析,结果是十进制的10。很多人不知道int可以接受第二个参数,导致看到int("0x10")报错后一脸茫然。正确做法是int("0x10", 0),基数0表示自动根据前缀识别,或者int("0x10", 16)显式指定。在解析配置文件的颜色值、内存地址时,这个参数很实用。
5.2 可变对象作为默认参数
函数定义时,默认参数会被一次性计算并复用。如果默认参数是列表、字典这类可变对象,每次调用修改会累积。
def add_item(item, cache=[]): cache.append(item) return cache print(add_item(1)) # [1] print(add_item(2)) # [1, 2] 而不是 [2]这个问题的根源是,cache=[]在函数定义时执行一次,之后所有调用共享同一个列表。正确的做法是默认参数写None,函数体里再创建新对象:
def add_item(item, cache=None): if cache is None: cache = [] cache.append(item) return cache逻辑说明:is None判断的是身份而非值,因为None是单例,所以这是判断默认参数是否被传入的常用写法。这个知识点在面试里出现频率很高,也是初学者最容易忽略的Python陷阱之一。
5.3 用生成器流式处理大文件
最后一个技巧:处理超大文本时,不要用read().split()把整份数据全载入内存,改用流式迭代。
def iter_words(file_path): with open(file_path, encoding='utf-8') as f: for line in f: for word in line.split(): yield word for w in iter_words("huge.txt"): process(w)参数说明:yield让函数变成生成器,每次迭代只保留当前状态。相比一次性readlines(),内存占用从O(全文大小)降到O(单行大小)。如果后续要做多进程,multiprocessing.Pool的imap可以配合生成器分批消费,但生成器对象本身不能跨进程传递,需要先转换成块列表。在Python 3.3+,子生成器用yield from委托,比手动for循环转发更简洁。协程里的async for本质是在生成器基础上加了调度语义,调试时可以用asyncio.run单步跟踪。
本文还有配套的精品资源,点击获取