Contents

常见问题

Contents

参考资料

一、基础与进阶概念

1. *args**kwargs

功能:用于在函数定义时接收不定长度的参数。

  • *args:接收非键值对的可变数量参数列表,以元组形式存储。
  • **kwargs:接收不定长度的键值对参数,以**字典**形式存储。

注意

  • argskwargs 只是习惯命名,可以替换成其他单词。
  • 可以在函数定义时同时使用两者,*args 必须在 **kwargs 之前。

在函数调用时的使用

1
2
3
4
5
args = ("two", 3, 5)
test_args_kwargs(*args)  # 解包元组

kwargs = {"arg3": 3, "arg2": "two", "arg1": 5}
test_args_kwargs(**kwargs)  # 解包字典

2. self 关键字

  • 在类的方法定义中,self 作为第一个参数,指代新创建的实例化对象本身
  • 可以随便起其他名字,但一般统一写作 self,并放在参数的最前面。
  • 相当于 C++ 的 self 指针,Java 的 this 关键字。

调用本质

1
2
3
4
a = Student('小明', 95)
a.get_score()
# 解释器翻译为:
# Student.get_score(a)
  • 调用实例方法时不需要也不能传入参数 self,解释器会自动传入。

3. 实例属性和方法

  • 本质上都可以认为是对象
  • 属性:相当于 class 中的变量。
  • 方法:相当于 class 中的函数。
  • class 实例化后,可以调用这些属性和方法。

4. 函数 vs. 方法

对比项 函数 方法
本质 完成功能的语句块 完成功能的语句块
定义位置 类外部 类内部
调用方式 直接调用 func() 通过 obj.method() 调用
参数要求 无需 self 必须包含 self(或 cls
从属性 独立存在 从属于特定实例对象

5. 类中的不同类型方法

类型 装饰器 第一个参数 调用方式 特点
实例方法 self 只能通过实例调用 可访问实例属性和类属性
类方法 @classmethod cls 类或实例调用,推荐类调用 只能访问类属性和其他类方法
静态方法 @staticmethod 类或实例调用 不能访问类/实例属性,相当于普通函数

注意

  • Python 不支持方法重载,一个类中定义多个同名的方法只有最后一个生效。
  • 可以动态地为类添加新方法:class.method = new_method

6. 私有化与封装

  • 双下划线开头的属性/方法(如 __attr)被约定为私有的,实现封装。
  • 若需要在类外部访问私有属性:_类名__私有属性方法名(名称修饰)。
  • 方法本质上也是属性

7. @property 装饰器

作用:将一个方法的调用转换成属性的调用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Employee:
    @property
    def salary(self):
        return 30000

emp1 = Employee()
print(emp1.salary)          # 30000(像属性一样访问,无需括号)
print(type(emp1.salary))    # <class 'int'>
print(emp1.salary())        # 报错:'int' object is not callable
emp1.salary = 20000         # 报错:can't set attribute

8. 变量与作用域

LEGB 搜索顺序

  1. Local:本地作用域
  2. Enclosing:当前作用域被嵌入的本地作用域(嵌套函数)
  3. Global:全局作用域(模块级别)
  4. Built-in:内置作用域

global 和 nonlocal

关键字 使用范围 功能
global 任何地方,包括最上层函数和嵌套函数 标识变量是全局变量,修改会影响全局
nonlocal 仅限嵌套函数中,且外层函数必须定义该变量 标识变量是上一级函数的局部变量

注意:减少 global 变量的使用,减少资源消耗。

9. __name__ 变量

  • 直接执行:当 .py 文件被直接运行时,__name__ 的值为 '__main__'
  • 作为模块导入:当文件被其他模块导入时,__name__ 的值是该模块的文件名(不含 .py)。
  • 用途:常用于 if __name__ == '__main__': 编写测试代码,在导入时不会被执行。

10. __str____repr__

  • print() 会优先调用 __str__,若未定义则调用 __repr__
  • __repr__:主要用于调试和开发,输出包括对象的类型、值等信息。
  • __str__:输出更加直观和易读,面向用户。

11. __call__() 方法

当需要额外运行某些内容时,可以重写 __call__() 函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class A:
    def __call__(self, name):
        print(f'我的名字是:{name}')
        return self.forward(name)
    def forward(self, input_):
        print('forward 函数被调用了')
        return input_

a = A()
result = a('python')  # 实例对象可以像函数一样被调用

12. 对象操作相关函数

  • dir(obj):获取对象的属性、方法列表。
  • obj.__dict__:以字典形式返回对象的属性。
  • isinstance(obj, type):判断对象是否是某个类型。
  • hasattr(obj, attr):判断对象是否包含指定名称的属性或方法。
  • getattr(obj, attr):获取对象中指定属性的值。
  • setattr(obj, attr, value):修改属性值或动态添加属性/方法。

13. 模块、包、库、utils

概念 定义 特点
模块 (Module) 一个 .py 文件 包含函数和变量,规模较小
包 (Package) 包含 __init__.py 的文件夹 组织多个模块,包本身也是模块
库 (Library) 模块或包的集合 无严格定义,是通俗说法
utils 文件夹 存放工具函数的文件夹 提高代码复用性

__init__.py 的作用

  • 将一个文件夹变为 Python 模块。
  • 可包含初始化代码,在包被 import 时自动执行。

14. PYTHONPATH 环境变量

作用:告诉 Python 解释器在哪些目录下搜索模块。

Python 模块搜索路径顺序

  1. 当前工作目录
  2. PYTHONPATH 中的所有目录
  3. Python 默认安装目录

设置方法

  • Windows (cmd):set PYTHONPATH=项目根目录 && python run.py
  • Windows (PowerShell):$env:PYTHONPATH="项目根目录" && python run.py
  • Linux/Mac:export PYTHONPATH=项目根目录; python run.py

最佳实践:将项目根目录添加到 PYTHONPATH,便于使用绝对导入,提高代码可靠性。

15. sys.path vs os.path

  • sys.path:Python 解释器的系统环境参数,包含模块搜索路径列表。
  • os.path:系统路径文件操作模块(如 joinexistsdirname 等)。

16. if __name__ == '__main__' 详解

每一个模块(.py 文件)都有 __name__ 属性:

  • 当模块被直接执行时,__name__ == '__main__'
  • 当作为外部模块被其他模块导入时,__name__ 为模块文件名。

注意:被导入时,程序会执行被导入模块的所有代码,因此测试代码需要放在 if __name__ == '__main__': 条件下。


二、高级技巧与常用操作

1. 两次排序获取元素排名

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import torch
a = torch.rand(2, 5)

# 第一次排序:获取排序后的值和原始索引
a1, a11 = a.sort(dim=1, descending=True)  # 降序排列
# a1: 排序后的数组
# a11: 各元素原本的下标值

# 第二次排序:对索引数组排序
b1, b11 = a11.sort(dim=1)  # 默认升序
# b11: 原始数组中每个元素在降序排列后的位置(排名)

NumPy 版本

1
2
3
4
import numpy as np
a = np.array([4, 2, 1, 100, -4])
b = a.argsort()  # 直接得到排序后对应的下标
sorted_a = a[b]   # 排好序的数组

带 enumerate 的排序(保留原索引):

1
2
3
4
a = ['ab', 'abcde', 'abc', 'abcd', 'a']
temp = sorted(enumerate(a), key=lambda x: len(x[1]), reverse=True)
idx = [i[0] for i in temp]     # 原索引
problem = [i[1] for i in temp] # 排序后的数组

2. 递归与回溯

递归

  • 函数内部调用函数自身。
  • 包含两个部分:
    • Base Case(基本情况):问题划分到最小规模,可直接解决。
    • Recursive Case(递归情况):将问题分解为更小规模的子问题,通过调用自身解决。

调用栈:每个递归调用在内存中形成栈帧,存储局部变量、返回地址等。递归结束时,栈帧从栈顶依次弹出。

回溯思想:在递归过程中,当某条路径走不通时,撤销之前的决策,尝试其他路径。常与递归结合。

典型应用

  • 树的路径问题
  • 汉诺塔问题
  • 八皇后问题

汉诺塔示例

1
2
3
4
5
def TowersOfHanoi(numberOfDisks, startPeg=1, endPeg=3):
    if numberOfDisks > 0:
        TowersOfHanoi(numberOfDisks-1, startPeg, 6-startPeg-endPeg)
        print(f"Move disk {numberOfDisks} from peg {startPeg} to peg {endPeg}")
        TowersOfHanoi(numberOfDisks-1, 6-startPeg-endPeg, endPeg)

八皇后示例(yield 生成器版本):

1
2
3
4
5
6
7
8
def play(row=0, solution=[]):
    if row == 8:  # Base case
        yield solution
    else:
        for col in range(8):
            if not is_conflict(solution, (row, col)):
                for sol in play(row+1, solution+[(row, col)]):
                    yield sol

3. yield 与生成器

执行逻辑

  1. 函数中有 yield 关键字时,函数不会立即执行,而是返回一个生成器对象
  2. 调用 next() 时,函数开始执行,遇到 yield 时暂停并返回值。
  3. 再次调用 next() 时,从暂停处继续执行。
  4. send(value) 可以向生成器发送值,作为 yield 表达式的返回值。
1
2
3
4
5
6
7
8
9
def foo():
    print("starting...")
    while True:
        res = yield 4
        print("res:", res)

g = foo()
print(next(g))      # starting... \n 4
print(g.send(7))    # res: 7 \n 4

优势

  • 实现惰性计算,按需生成数据。
  • 极大节省内存,尤其适合处理大数据序列。

4. is vs. ==

操作符 比较内容 说明
is 对象身份(内存地址) id(a) == id(b)
== 对象值 ab 的值相等

注意

  • Python 启动时,[-5, 256] 范围的整数被预先创建为单例对象。
  • 空元组 () 也是单例,因为不可变;空列表 [] 不是,因为可变。
  • 对于字符串,CPython 有 string interning 优化,会复用某些字符串对象。
1
2
3
4
5
6
a = 256; b = 256; a is b  # True
a = 257; b = 257; a is b  # False(交互式环境)
a, b = 257, 257; a is b   # True(同一行赋值,编译时优化)

() is ()      # True
[] is []      # False

5. 浅拷贝 vs. 深拷贝

操作 方法 特点
赋值 b = a 只是引用,指向同一对象
浅拷贝 b = a[:] / b = copy.copy(a) / b = list(a) 创建新对象,但内部元素是原对象的引用
深拷贝 b = copy.deepcopy(a) 完全独立的新对象,递归复制所有子对象

注意

  • 数字、字符串等非容器类型,没有拷贝一说(不可变)。
  • 浅拷贝时,若原对象包含可变对象(如嵌套列表),修改该可变对象会影响浅拷贝后的对象。
1
2
3
4
5
6
# 经典坑:创建二维列表
board = [[''] * 3] * 3  # 浅拷贝,三行指向同一列表
board[0][0] = 'X'       # 结果:[['X','',''], ['X','',''], ['X','','']]

# 正确方式
board = [[''] * 3 for _ in range(3)]

6. 装饰器

定义:本质是一个函数,接收一个函数作为参数,并返回一个新函数(或可调用对象)。

语法

1
2
3
4
5
6
@decorator_name
def function_name():
    pass

# 等价于
function_name = decorator_name(function_name)

多个装饰器执行顺序

1
2
3
4
5
6
@funA
@funB
@funC
def fun():
    pass
# 等价于:fun = funA(funB(funC(fun)))

常见用途

  • 插入日志
  • 性能测试(计时)
  • 事务处理
  • 缓存(如 @lru_cache
  • 权限校验
  • 类方法定义(@classmethod@staticmethod@property

7. 字符串与时间处理

strptime vs. strftime

函数 含义 输入 输出
strptime parse(分析) 字符串 + 格式 时间对象
strftime format(格式化) 时间对象 + 格式 字符串
1
2
3
4
5
6
7
from datetime import datetime

# 字符串 → 时间对象
time_obj = datetime.strptime('2025-02-21 09:55:00', '%Y-%m-%d %H:%M:%S')

# 时间对象 → 字符串
time_str = datetime.strftime(time_obj, '%Y/%m/%d %H:%M')

8. 海象操作符(Walrus Operator):=

  • 引入于 Python 3.8。
  • 允许在表达式中同时进行变量赋值和表达式求值
  • 注意:两边的圆括号不能少。
1
2
3
4
5
6
7
(a := 123)           # 123
(a := [2, 4, 6])     # [2, 4, 6]
(a := 'hello')       # 'hello'

# 实用场景:while 循环中避免重复调用
while (line := file.readline()) != "":
    process(line)

9. np.where() 函数

1
2
3
4
import numpy as np
nums = np.arange(1, 11)[::-1]  # [10, 9, 8, ...]
index = np.where(nums > 3)      # 返回满足条件的下标(元组)
index[0]                        # 取下标数组

10. zip() 函数

1
2
3
4
5
6
7
8
9
a = [1, 2, 3]
b = ['hello', 'world']
c = [a, b]

list(zip(c))        # [([1,2,3],), (['hello','world'],)]
list(zip(*c))       # [(1, 'hello'), (2, 'world')]  # 解压

# 矩阵逆时针旋转
list(zip(*matrix))  # 相当于转置

11. np.swapaxes()

1
2
3
4
5
6
import numpy as np
arr = np.arange(24).reshape((2, 3, 4))

arr.swapaxes(0, 1)  # (3, 2, 4)
arr.swapaxes(0, 2)  # (4, 3, 2)
arr.swapaxes(1, 2)  # (2, 4, 3)

12. 独热编码生成方式

1
2
3
4
5
6
# 方法一:sklearn
from sklearn.preprocessing import OneHotEncoder

# 方法二:pandas
import pandas as pd
pd.get_dummies(df['column'])

13. 奇异值分解(SVD)与特征值分解

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import numpy as np
A = np.array([[0, 1], [1, 1], [1, 0]])

# 直接 SVD
u, s, vT = np.linalg.svd(A)

# 手动推导
A1 = A.T @ A  # 右奇异矩阵
eval1, evec1 = np.linalg.eig(A1)  # 特征值为奇异值的平方
evec2 = A @ evec1 / np.sqrt(eval1)  # 计算左奇异向量

关键关系

  • 奇异值 = 特征值的平方根
  • A = U·Σ·V^T

三、包、模块与项目组织

1. 模块导入方式

导入方式 语法 特点
直接导入模块 import module 使用 module.func()
导入并别名 import module as alias 使用 alias.func()
导入特定函数 from module import func 直接使用 func()
导入所有 from module import * 不推荐,可能命名冲突

2. 包的 __init__.py

  • 将一个文件夹变为 Python 模块。
  • 可包含初始化代码(如批量导入模块)。
  • 即使为空文件也必须存在(Python 3.3+ 中可省略,但仍推荐保留)。

3. 动态添加类方法

1
2
3
4
5
6
7
class MyClass:
    pass

def new_method(self):
    return "Hello"

MyClass.new_method = new_method

四、并发与并行编程

1. 核心概念对比

概念 定义 资源 适用场景
进程 程序的一次执行,独立内存空间 内存不共享 CPU 密集型
线程 CPU 调度最小单位,共享进程资源 内存共享 I/O 密集型
协程 用户态轻量级线程,程序控制切换 共享且开销小 大量并发 I/O

2. GIL(全局解释器锁)

  • 仅存在于 CPython 解释器
  • 确保同一时刻只有一个线程执行 Python 字节码
  • 影响:多线程无法实现真正的并行计算
  • 释放时机:时间片结束或遇到 I/O 操作。

执行流程

  1. 线程获取 GIL
  2. 执行 Python 字节码
  3. 释放 GIL(时间片结束或 I/O 等待)
  4. 其他线程竞争获取 GIL
  5. 重复上述过程

3. 全双工通信示例(socket + threading)

服务器端

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import socket, threading

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('0.0.0.0', 8000))
server_socket.listen()
connection, address = server_socket.accept()

def receive_data():
    while True:
        data = connection.recv(1024).decode()
        if not data: break
        print(f'Received: {data}')

def send_data():
    while True:
        data = input('Enter message: ')
        connection.sendall(data.encode())
        if data == 'quit': break

threading.Thread(target=receive_data).start()
threading.Thread(target=send_data).start()

4. 异步编程示例(aiohttp / aiofiles)

异步网络请求

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import aiohttp, asyncio

async def fetch_url(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

async def main():
    urls = ["https://example.com", ...]
    tasks = [fetch_url(url) for url in urls]
    responses = await asyncio.gather(*tasks)

异步文件操作

1
2
3
4
5
import aiofiles, asyncio

async def write_to_file(filename, data):
    async with aiofiles.open(filename, 'w') as f:
        await f.write(data)

五、内存管理与性能优化

1. 可变 vs. 不可变类型

类型 特点 包含类型
不可变 值改变时,内存地址改变 数值、字符串、元组
可变 值改变时,内存地址不变 列表、字典、集合

关键点

  • 字典的键必须是不可变类型。
  • 对不可变类型做深浅拷贝无效,仍指向同一地址。
1
2
3
4
a = 5
print(id(a))    # 某个地址
a = 6
print(id(a))    # 新地址(不可变)

2. Python 内存管理三层架构

  • 第 0 层:C 语言的 malloc / free 函数
  • 第 1-2 层:内存池(256 字节以下的小对象)
  • 第 3 层:Python 对象直接操作

内存池机制

  • 小于等于 256 字节的小对象在内存池分配。
  • 大于 256 字节的对象直接调用 malloc
  • 可通过修改源码更改 256 这个阈值。

3. 垃圾回收机制

机制 说明
引用计数 每个对象记录被引用次数,为 0 时立即回收。缺点:无法处理循环引用
标记-清除 解决循环引用问题,标记活动对象,清除不可达对象
分代回收 将对象分为三代,新对象在 0 代,回收次数多则晋升。每隔一定时间回收较老一代

获取引用计数

1
2
import sys
sys.getrefcount(object)

4. 内存泄漏与预防

  • 定义:程序未能释放已不再使用的内存。
  • 后果:运行速度减慢,系统崩溃。
  • 预防
    • 使用 del object 删除不再使用的对象引用。
    • 使用 sys.getrefcount() 监控引用计数。
    • 避免循环引用(或使用 weakref 模块)。

5. 性能优化建议

场景 建议
CPU 密集型 使用多进程
I/O 密集型 使用多线程协程
频繁操作 尽量使用内置函数(如 sum(), map()
变量访问 多使用局部变量(访问速度快于全局)
循环优化 避免在循环内重复计算不变量

六、常见坑点与特殊行为

1. 字符串保留(String Interning)

CPython 为优化内存,会尝试复用某些不可变对象。

保留规则

  • 所有长度为 0 和长度为 1 的字符串。
  • 字符串在编译时被保留(如 "hello")。
  • 不是由 ASCII 字母、数字或下划线组成的字符串不会被保留(如 "hello!")。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
a = "hello"
b = "hello"
a is b          # True

c = "hello!"
d = "hello!"
c is d          # False(交互式环境)

# 同一行声明
a, b = "hello!", "hello!"
a is b          # True(编译时优化)

常数折叠

1
2
'a' * 20 is 'aaaaaaaaaaaaaaaaaaaa'    # True(长度 < 21)
'a' * 21 is 'aaaaaaaaaaaaaaaaaaaaa'   # False(长度 >= 21)

2. 链式操作

1
2
3
4
5
6
7
1 > 0 < 1
# 等价于
(1 > 0) and (0 < 1)   # True

(1 > 0) < 2
# 等价于
True < 2              # True(True 被当作 1)

3. 哈希与字典键

1
2
3
4
5
6
7
some_dict = {}
some_dict[5.5] = "JavaScript"
some_dict[5.0] = "Python"
some_dict[5] = "Ruby"
some_dict[5 + 0j] = "C"

print(some_dict)  # {5.5: 'JavaScript', 5.0: 'C'}

解释

  • 字典键的唯一性基于等价性==),而非同一性(is)。
  • 5 == 5.0 == 5+0j 为 True。
  • 值相等的对象有相同的哈希值(hash(5) == hash(5.0))。
  • 注意:哈希值相同的对象值不一定相同(哈希冲突时)。

4. try...finally 中的 break / return

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
def one_more_func():
    try:
        for i in range(3):
            try:
                1 / i
            except ZeroDivisionError:
                raise ZeroDivisionError("error")
            finally:
                print("Iteration", i)
                break   # 注意这里的 break
    except ZeroDivisionError as e:
        print("Error:", e)

one_more_func()  # 输出: Iteration 0(异常被丢弃)

规则

  • finally 子句总会执行
  • 函数的返回值由最后执行的 return 决定。
  • 如果 finally 子句执行 returnbreak临时保存的异常将被丢弃

5. for 循环中的变量赋值

1
2
3
4
for i in range(4):
    print(i)
    i = 10
# 输出: 0, 1, 2, 3

原因:每次迭代开始时,迭代器提供的下一项被解包并赋给目标变量,循环体内的赋值不影响下次迭代。

6. 生成器表达式的绑定时机

1
2
3
4
5
6
7
8
9
array_1 = [1, 2, 3, 4]
gen_1 = (x for x in array_1)
array_1 = [1, 2, 3, 4, 5]
list(gen_1)   # [1, 2, 3, 4](仍引用旧对象)

array_2 = [1, 2, 3, 4]
gen_2 = (x for x in array_2)
array_2[:] = [1, 2, 3, 4, 5]  # 原地修改
list(gen_2)   # [1, 2, 3, 4, 5](引用被更新的对象)

注意:只有最外层的 for 表达式会立即计算,其他表达式推迟到运行时计算。

7. 类变量与继承

1
2
3
4
5
6
7
8
class A: x = 1
class B(A): pass
class C(A): pass

B.x = 2
print(A.x, B.x, C.x)  # 1, 2, 1
A.x = 3
print(A.x, B.x, C.x)  # 3, 2, 3

规则:类变量在内部以字典形式存储。当前类字典中找不到变量名时,在父类中搜索。

8. is 与类方法比较

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class SomeClass:
    def method(self): pass
    @classmethod
    def classm(cls): pass
    @staticmethod
    def staticm(): pass

o1, o2 = SomeClass(), SomeClass()

o1.method is o1.method        # False(每次访问创建新方法对象)
o1.method == o1.method        # True
o1.classm is o1.classm        # False
o1.classm == o2.classm        # True(类方法相同)
o1.staticm is SomeClass.staticm  # True(静态方法相同)

解释:函数是描述符。每次访问属性时,描述符被调用并创建一个新的方法对象,这就是为什么 o1.method is o1.methodFalse

9. NaN 的特殊行为

1
2
3
4
5
6
7
float('inf') == float('inf')  # True
float('nan') != float('nan')  # True(NaN 不等于自身)
None == None                  # True

import numpy as np
np.NaN is np.NaN    # True(同一对象)
np.NaN == np.NaN    # False

10. 转义字符

1
2
3
4
5
# 普通字符串:反斜杠转义
"hello\"hi"     # 'hello"hi'

# 原始字符串:r 前缀,反斜杠按原样传递
r'hello\"hi'    # 'hello\\"hi'

11. 运算符优先级

1
2
not x == y      # 等价于 not (x == y)
x == not y      # 报错(语法错误)

12. 变量的下划线约定

命名 含义
_something 前置单下划线:提示供内部使用,from module import * 不会导入
something_ 后置单下划线:防止与 Python 关键字重名
__something 前置双下划线:名称修饰,避免子类命名冲突
__something__ 前后双下划线:Python 特殊方法(如 __init__),一般不自定义
_ 单独下划线:表示用不到的变量(如 for _ in range(n)

七、实用代码片段

1. 打字效果

1
2
3
4
5
6
7
8
9
import time, random

text = 'hello world'
for ch in text:
    print('|', end='', flush=True)
    time.sleep(0.2)
    print('\b', end='', flush=True)
    time.sleep(random.randrange(1, 30) / 100)
    print(ch, end='', flush=True)

2. 绘图相关

Matplotlib 多子图

1
2
fig, axes = plt.subplots(2, 2)
axes[0, 0].plot(x1, y1)

Seaborn FacetGrid

1
2
grid = sns.FacetGrid(data, col='category', row='subcategory')
grid.map(plt.plot, 'x', 'y')

Plotly 多子图

1
2
fig = make_subplots(rows=2, cols=2)
fig.add_trace(go.Scatter(x=x1, y=y1), row=1, col=1)

Color bar 设置

1
2
3
sns.heatmap(a, annot=True, cbar=False)
mycbar = ax.figure.colorbar(ax.collections[0])
mycbar.ax.tick_params(labelsize=15)

3. pd.DataFrame 操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import pandas as pd

# 删除行
df.drop(index=df.loc[df['table'] == 'sc'].index, inplace=False)

# 删除列
df.drop(columns=['table'])

# a.empty, a.all(), a.any()
a.empty  # 判断是否为空
a.all()   # 判断是否全为 True
a.any()   # 判断是否存在 True

4. input 内容处理

1
a, b, c = map(int, input().split(','))

5. URL 参数提取

1
2
3
4
5
from urllib.parse import urlparse, parse_qs

url = 'https://www.google.com/search?newwindow=1&biw=1091'
params = parse_qs(urlparse(url).query)
print(params['newwindow'])  # ['1']

注意:导入特定函数比导入整个模块更高效,减少内存使用和加载时间。

6. subprocess 使用

1
2
3
4
5
import subprocess

p = subprocess.Popen("df -h", shell=True, stdout=subprocess.PIPE)
out = p.stdout.readlines()
p.communicate()  # 推荐使用 communicate() 避免死锁

7. 脚本参数传入(argparse)

1
2
3
4
5
6
import argparse

parser = argparse.ArgumentParser(description='My script')
parser.add_argument('--path', type=str, default=None, help='图片路径')
parser.add_argument('--resize', type=str, default='512x512', help='修改大小')
args = parser.parse_args()

8. 文件打包下载(Jupyter)

1
2
3
!zip -q -r output.zip "文件夹路径/*"
from IPython.display import FileLink
FileLink('output.zip')

9. mp4 转 gif

1
2
3
4
from moviepy.editor import *

clip = VideoFileClip("input.mp4").subclip(1, 2).resize(0.5)
clip.write_gif("output.gif", fps=15)

10. @lru_cache 缓存

1
2
3
4
5
6
7
8
9
from functools import lru_cache

@lru_cache(maxsize=None)  # 等价于 @cache
def test(a, b):
    print('计算中...')
    return a + b

test(1, 2)  # 计算中...
test(1, 2)  # 直接返回缓存结果

11. zip(*nums) 矩阵旋转

1
2
nums = [[7,2,1], [6,4,2], [6,5,3], [3,2,1]]
list(zip(*nums))  # 逆时针旋转(转置)

12. 可交互 3D 图像(ipywidgets)

1
2
3
4
5
6
7
8
9
from ipywidgets import interact, fixed

def plot_3D(elev=20, azim=50, x=x, y=y, z=z):
    fig = plt.figure(figsize=(10, 8))
    ax = plt.subplot(projection='3d')
    ax.plot_surface(x, y, z, cmap='RdBu_r')
    ax.view_init(elev=elev, azim=azim)

interact(plot_3D, elev=[20, 90], azim=(-180,180), x=fixed(x), y=fixed(y), z=fixed(z))

八、面试常考题汇总

1. Python 简介

  • 解释型语言:无需编译,需要解释器,运行速度慢于编译型语言。
  • 动态类型语言:声明变量时无需说明类型。
  • 强类型语言:不允许不同类型相加(如 '1' + 1 报错)。
  • 适合面向对象编程:支持组合与继承。

2. 赋值、浅拷贝、深拷贝

操作 内存 嵌套对象
赋值 b = a 指向同一对象 共享
浅拷贝 copy.copy(a) 新对象 共享引用
深拷贝 copy.deepcopy(a) 新对象 完全独立

3. Python 自省

程序运行时检查对象类型和属性的能力。

函数 功能
dir(obj) 查看对象属性名称
type(obj) 查看对象类型
getattr(obj, attr) 查看对象属性
hasattr(obj, attr) 判断是否有某属性
isinstance(obj, type) 判断是否为某类型

4. Python 提升性能的手段

  • 使用多进程处理 CPU 密集型任务
  • I/O 阻塞采用 I/O 多路复用
  • 尽量使用 Python 内置函数
  • 尽量使用局部变量
  • 对性能影响较大的部分用 C/C++ 编写

5. 字典的 items() vs iteritems()

Python 2 Python 3
items() 返回列表 items() 返回视图(可迭代)
iteritems() 返回迭代器 无,直接用 items()

6. 字典 vs JSON

对比 字典 JSON
本质 数据结构 数据表现形式
要求 value 需要可哈希 value 必须是字符串
引号 单双引号均可 必须用双引号

7. Python 2 vs Python 3 区别

项目 Python 2 Python 3
print 语句(不需要括号) 函数(需要括号)
input() 返回 int(raw_input 返回 str) 返回 str
除法 / 整数除法(取整) 真除法(返回浮点数)
地板除 // 取整 取整
range() 返回列表 返回迭代器
xrange() 创建迭代对象 移除,用 range()

8. 编码解码

1
2
3
s = "hello world"
b = s.encode("gbk")      # 编码为字节序列
s1 = b.decode("gbk")     # 解码为字符串

9. 回调函数

把函数的指针(引用)作为参数传递给另一个函数。简单讲:一个函数作为另一个函数的参数被传入。

10. 方法重写(Override)vs 方法重载(Overload)

对比 方法重写 方法重载
发生位置 子类和父类之间 同一个类中
方法名 相同 相同
参数列表 相同 不同(类型、个数)
返回类型 相同或是其子类 可以不同
Python 支持 ✅ 支持 ❌ 不支持(只有最后一个生效)

11. GET vs POST

对比 GET POST
用途 获取数据 提交数据
参数位置 URL 中 请求体中
安全性 较低(暴露在 URL) 较高
长度限制 有(浏览器/服务器限制)
缓存 可以 不可以
书签 可以收藏 不可以

12. 生成器 vs 迭代器

对比 迭代器 生成器
定义 实现 __iter__()__next__() 的类 使用 yield 的函数或生成器表达式
创建方式 iter(container) (x for x in range(10)) 或函数含 yield
特点 逐个访问容器元素 更简洁、高效、节省内存