【不背八股】8.Pyhton知识点查漏补缺
引言
有些面试官往往喜欢考察一些相对冷门的编程语言知识点,以此来推断求职者的编程功底。
因此,本文整理了一些python语言中较容易忽视的一些内容,作为知识拓展。
本文将回答以下问题:
- 1.
*arg和**kwarg作用是什么? - 2.迭代器和生成器是什么,有什么区别?
- 3.return 和 yield 有什么区别?
- 4.CPython 是什么?
- 5.CPython 的垃圾回收是怎么做的?
- 6.装饰器是什么,本质有什么作用?
- 7.懒加载是什么?
- 8.单例模式和工厂模式有什么区别?
- 9.反射是什么?
- 10.Thread有哪些基本操作?
- 11.await 和 async 有什么作用?
- 12.列表、字典、集合的底层类型是什么?

1. *arg 和 **kwarg 作用是什么?
*args 和 **kwargs 是 Python 里函数定义时常见的“可变参数”写法,用来让函数传入不定数量的实参,具体作用是:
| 语法 | 作用 |
|---|---|
*args | 接收任意个 位置参数,打包成元组 |
**kwargs | 接收任意个 关键字参数,打包成字典 |
示例:
def demo(*args, **kwargs):
print("args:", args) # 元组
print("kwargs:", kwargs) # 字典
demo(1, 2, 3, name="Alice", age=25)
# 输出:
# args: (1, 2, 3)
# kwargs: {'name': 'Alice', 'age': 25}
2. 迭代器和生成器是什么?
迭代器是实现了迭代器协议的对象,用__iter__和__next__魔术方法表示协议[1]。
__iter__(): 返回自身__next__(): 返回下一个值,没值时抛 StopIteration
class Fib(object):
"""迭代器"""
def __init__(self, num):
self.num = num
self.a, self.b = 0, 1
self.idx = 0
def __iter__(self):
return self
def __next__(self):
if self.idx < self.num:
self.a, self.b = self.b, self.a + self.b
self.idx += 1
return self.a
raise StopIteration()
生成器是语法简化版的迭代器。
def fib(num):
"""生成器"""
a, b = 0, 1
for _ in range(num):
a, b = b, a + b
yield a
3. return 和 yield 有什么区别?
return比较常见,结束整个函数并返回一个值。
yield则是暂停函数,把值“产出”出去,下次再从此行后继续,使函数变成生成器。
示例对比:
def add(a, b):
return a + b
print(add(2, 3)) # 5
print(add(2, 3)) # 再次调用重新运行整个函数
一旦执行到 return,函数彻底结束。
def count_up(n):
i = 0
while i < n:
yield i # 暂停并返回 i
i += 1
gen = count_up(3) # 返回生成器对象
print(next(gen)) # 0
print(next(gen)) # 1
print(next(gen)) # 2
# 再 next 会 StopIteration
每次next()执行到yield就暂停,保留局部变量和指令位置。
4. CPython 是什么?
CPython 是用 C 语言写成的 Python 解释器,也是 Python 官方的解释器实现。
CPython 能够把 .py 源码编译成字节码(.pyc),然后用解释器执行。
除此之外,还有其它 Python 解释器版本,对比如下表所示:
| 实现 | 语言 | 特性 |
|---|---|---|
| CPython | C | 官方、最广泛使用 |
| PyPy | RPython | JIT 加速,通常运行更快 |
| Jython | Java | 运行在 JVM,可直接调用 Java 库 |
| IronPython | C# | 运行在 .NET 上 |
| MicroPython | C | 面向嵌入式设备 |
5. CPython 的垃圾回收是怎么做的?
在 CPython 里,“垃圾回收”主要靠引用计数两套机制配合**:
1. 引用计数(Reference Counting)
- 每个对象里有个
ob_refcnt计数器,记录当前有多少地方在引用它。 - 任何赋值、传参、容器保存都会让计数 +1;引用关系解除时 -1。
- 计数降到 0 说明没人再用,解释器立即调用析构、释放内存。
import sys
x = [] # 创建空列表
print(sys.getrefcount(x)) # 引用计数(额外+1因为getrefcount也传参了)
y = x # 再次引用
del x # 计数 -1
del y # 计数归 0,立即释放
缺点:循环引用无法清理(两个对象互相指着对方,计数永远 >0)。
2. 分代垃圾回收(Generational GC)
为解决循环引用问题,CPython 在 gc 模块里实现了 分代垃圾回收:
- 对象分代:0 代(新生)、1 代、2 代。存活越久,代数越高。
- 触发条件:当某代分配-释放次数差值超阈值时触发扫描。
- 扫描规则:标记仍有外部可达性的对象,剩下的就是“仅互相引用”的循环,直接释放。
import gc
print(gc.get_threshold()) # (700, 10, 10) 默认 700 次分配触发 0 代收集
gc.collect() # 手动触发完整收集
3. 整体流程
- 创建对象 →
ob_refcnt = 1 - 多处引用、释放 → 实时增减计数
- 计数归零 → 立即销毁
- 周期性 → 分代 GC 扫描,发现循环 → 强制回收
6. 装饰器是什么?
装饰器本质是一个函数(或类)接收器,它把目标函数作为参数并返回一个新函数,从而在不改源代码的前提下,为目标函数动态增加功能。常见场景有日志、权限控制、缓存等。
以下是一个日志装饰器的示例用法:
def logger(func):
def wrapper(*args, **kwargs):
print(f"[LOG] 调用 {func.__name__}")
return func(*args, **kwargs)
return wrapper
@logger # 等价于 say_hello = logger(say_hello)
def say_hello():
print("Hello")
say_hello()
除了自定义装饰器外,python还内置了以下三种比较常用的装饰器。
| 装饰器 | 用途 |
|---|---|
@staticmethod | 定义静态方法,不需要 self |
@classmethod | 定义类方法,首参是 cls |
@property | 把方法变成只读属性 |
@staticmethod能够通过不用创建示例就调用函数。
class Tool:
@staticmethod
def add(a, b):
return a + b
print(Tool.add(3, 5)) # 8
@classmethod装饰的函数能够通过传入cls直接对类变量进行操作。
class User:
count = 0 # 类变量,所有实例共享
@classmethod
def inc(cls):
cls.count += 1 # 通过cls访问类变量
User.inc() # 直接对类操作,不需要实例
print(User.count) # 1
@property能够让实例像访问属性一样去调用方法。
class Person:
def __init__(self, age):
self._age = age
@property
def age(self):
return self._age
p = Person(20)
print(p.age) # 20,像访问属性一样
7. 懒加载是什么?
“懒加载”(Lazy Loading)是一个设计思想,意思是:需要用到某个资源/对象时再去创建或加载,而不是一开始就占用资源。
下面是一个代理懒加载的示例,初始化对象时先用代理ProxyImage,调用实际方法时,再加载真实类。
class RealImage:
def __init__(self, filename):
self.filename = filename
print(f"加载图片 {filename}")
def display(self):
print(f"显示 {self.filename}")
class ProxyImage:
def __init__(self, filename):
self.filename = filename
self.real_image = None
def display(self):
if self.real_image is None:
self.real_image = RealImage(self.filename)
self.real_image.display()
img = ProxyImage("big_picture.jpg")
img.display() # 第一次调用才加载图片
8. 单例模式和工厂模式有什么区别?
单例模式保证一个类全局只有一个实例;
工厂模式提供一个统一接口创建对象,让客户端不依赖具体类。
单例模式示例,使用__new__创建唯一对象。
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
a = Singleton()
b = Singleton()
print(a is b) # True,全局唯一
应用场景:配置管理、日志对象、数据库连接池。
工厂模式示例:
class Circle:
def draw(self): print("画圆")
class Square:
def draw(self): print("画方")
class ShapeFactory:
@staticmethod
def create_shape(type_):
if type_ == "circle":
return Circle()
elif type_ == "square":
return Square()
shape = ShapeFactory.create_shape("circle")
shape.draw() # 画圆
应用场景:系统需要动态创建不同类型对象,客户端不想依赖具体类。
9. 反射是什么?
反射(Reflection)是指程序在运行时检查和操作对象信息的能力。
反射能实现以下功能:
- 获取对象类型、属性、方法
- 动态调用方法 / 访问变量
- 动态修改、增加属性
- 按名字加载模块、类
常用的反射相关函数:
| 函数 / 关键字 | 作用 |
|---|---|
hasattr(obj, "name") | 判断对象是否有某属性 / 方法 |
getattr(obj, "name", default) | 按名字获取属性 / 方法 |
setattr(obj, "name", value) | 动态设置属性 |
delattr(obj, "name") | 删除属性 |
type(obj) | 获取类型 |
dir(obj) | 列出对象可用成员 |
globals() / locals() | 获取全局 / 局部命名空间 |
__import__("module") | 按字符串导入模块 |
使用示例:
class User:
def __init__(self, name):
self.name = name
def greet(self):
print(f"Hello {self.name}")
u = User("Alice")
# 运行时动态调用 greet
if hasattr(u, "greet"):
method = getattr(u, "greet") # 获取方法对象
method() # 执行 -> Hello Alice
# 动态添加属性
setattr(u, "age", 25)
print(u.age) # 25
10. Thread有哪些基本操作?
Thread类提供了以下函数用来处理多线程操作。
| 函数 | 关键点 | 典型场景 |
|---|---|---|
Lock | 一次只让一个线程进 | 保护共享资源 |
RLock | 同一线程可重复获取 | 递归、嵌套调用 |
Condition | 等条件满足再唤醒指定线程 | 生产者/消费者 |
Event | 广播式开关,全体等待线程同时解除 | 一次性信号、任务启动 |
Semaphore | 限制最大并发数 | 连接池、下载并发 |
Barrier | 一批线程到齐再统一放行 | 阶段同步、分布式并行场景 |
1. Lock(互斥锁)
- 作用:一次只允许一个线程进入“临界区”
- 特点:最简单,只有
acquire()/release()两个动作
import threading
lock = threading.Lock()
count = 0
def task():
global count
with lock: # 等价于 acquire+release
tmp = count
count = tmp + 1 # 这里同一时刻只有一个线程能改
2. RLock(可重入锁)
- 作用:允许同一线程多次 acquire,内部有个计数器,acquire 多少次,就要 release 多少次才能真正释放
rlock = threading.RLock()
rlock.acquire()
rlock.acquire() # OK,同一线程允许重入
print("拿了两次锁")
rlock.release()
rlock.release() # 计数归零,锁真正释放
3. Condition(条件变量)
- 作用:比
Lock多了一个“等条件成立再通知”的机制 - 场景:生产者-消费者模型
cond = threading.Condition()
items = []
def producer():
with cond:
items.append("data")
cond.notify() # 通知等待的消费者
def consumer():
with cond:
while not items:
cond.wait() # 等待生产者唤醒
print(items.pop())
4. Event
- 作用:一个线程发信号,其它等待的线程全都被唤醒
- 特点:只有两种状态:
set()(开)/clear()(关)
evt = threading.Event()
def waiter():
print("wait for signal…")
evt.wait() # 阻塞直到set
print("got signal")
def sender():
evt.set() # 发信号,全体wait()解除阻塞
5. Semaphore(信号量)
- 作用:允许最多 N 个线程同时进入临界区
- 场景:限制并发量
sem = threading.Semaphore(3) # 最多允许3个线程并行
def worker():
with sem:
# 同时最多3个worker在干活
pass
6. Barrier(栅栏/屏障)
- 作用:让一批线程“集合完毕再一起出发”
- 特点:所有线程都
wait(),等数量到齐才放行
bar = threading.Barrier(3)
def job():
print("ready")
bar.wait() # 阻塞直到3个线程都到了
print("go!")
11. await和async有什么作用?
async 和 await 是协程和异步编程的核心关键字:
async 用来定义协程函数,await 用来挂起协程等待耗时操作完成,从而不阻塞事件循环。
协程属于单线程并发,能够提高 IO 效率,节省线程开销。
协程函数和普通函数的区别如下表所示:
| 特性 | 普通函数 | 协程函数 (async def) |
|---|---|---|
| 调用返回 | 函数返回值 | 协程对象(需 await 才执行) |
| 是否可挂起 | ❌ | ✅(用 await 等异步操作) |
| 用途 | CPU 密集计算 | IO 密集操作(网络、文件、数据库) |
使用协程读写文件的示例:
import asyncio
import aiofiles
async def write_file(filename, content):
async with aiofiles.open(filename, 'w') as f:
await f.write(content) # 异步写入文件
async def read_file(filename):
async with aiofiles.open(filename, 'r') as f:
data = await f.read() # 异步读取文件
print(data)
def main():
loop = asyncio.get_event_loop() # 获取事件循环
tasks = [
write_file("test.txt", "Hello, asyncio!"),
read_file("test.txt")
]
loop.run_until_complete(asyncio.gather(*tasks)) # 并发执行协程
loop.close()
if __name__ == "__main__":
main()
12. 列表、字典、集合的底层类型是什么?
列表(list)、字典(dict)、集合(set)的底层类型和操作复杂度如下表所示:
| 数据结构 | 底层类型 | 随机访问 | 插入/删除 | 查找 | 内存特点 |
|---|---|---|---|---|---|
| list | 动态数组 | O(1) | O(n) | O(n) | 内存连续,扩容慢 |
| dict | 哈希表 | N/A | O(1) | O(1) | 内存分散,哈希冲突解决 |
| set | 哈希表(key) | N/A | O(1) | O(1) | 内存分散,哈希冲突解决 |
参考
[1] Python-100-Days:https://github.com/jackfrued/Python-100-Days/blob/master/Day31-35/31.Python%E8%AF%AD%E8%A8%80%E8%BF%9B%E9%98%B6.md
更多推荐


所有评论(0)