Python 面试准备
编译&解释性语言
Section titled “编译&解释性语言”python
GIL(Global Interpreter Lock,全局解释器锁)
Section titled “GIL(Global Interpreter Lock,全局解释器锁)”CPython 解释器中的一个互斥锁:同一时刻只有一个线程执行 Python 字节码。
为什么 Python 需要 GIL:核心原因:内存管理(尤其是引用计数)。CPython 使用 引用计数(Reference Counting) 来做垃圾回收。
同步锁:
WSGI与ASGI
Section titled “WSGI与ASGI”WSGI = 同步 Web 标准 ASGI = 异步 Web 标准
在 WSGI (2003)出现之前:
Web Server ↔ Python Framework
每个框架都要自己适配服务器。
WSGI 统一之后:
Web Server ↔ WSGI ↔ Framework
任何服务器都可以运行任何框架。
慢慢出现async、websocket、高并发IO,高并发需要多线程、多进程。
ASGI(2016)是异步Web标准接口。 支持:async / await、WebSocket、HTTP、long connections
WSGI常见服务器有Gunicorn、u WSGI、mod_wsgi;常见框架:Flask、Django、Pyramid ASGI常见服务器有unicorn、Hypercorn、Daphne;常见框架:FastAPI、Starlette、Django
| 特性 | WSGI | ASGI |
|---|---|---|
| 发布时间 | 2003 | 2016 |
| 模型 | 同步 | 异步 |
| 接口 | def app() |
async def app() |
| 并发 | 线程/进程 | 事件循环 |
| WebSocket | 不支持 | 支持 |
| HTTP | 支持 | 支持 |
| 长连接 | 不支持 | 支持 |
| ASGI 应用本质上长这样: |
async def app(scope, receive, send):
…
三个参数的含义:
-
scope:连接上下文,包含路径、方法、headers、协议类型等 -
receive:异步接收事件 -
send:异步发送事件
事件循环 Event Loop
Section titled “事件循环 Event Loop”核心:asyncio Event Loop
事件循环是一个不断运行的循环:
面向对象-封装、继承、多态
Section titled “面向对象-封装、继承、多态”封装是指把数据和操作数据的方法封装到类中,并对外隐藏内部实现细节,只暴露必要接口。在 Python 中,通常通过类、方法、`_变量`、`__变量`、以及 `@property` 来体现封装,目的是保护数据、控制访问、提高可维护性。
继承是指子类可以复用父类的属性和方法,并在此基础上进行扩展或重写。Python 使用 `class 子类(父类)` 的方式实现继承,子类可以通过 `super()` 调用父类方法。继承的主要作用是代码复用和建立类层次结构。
多态是指相同的调用作用于不同对象时,会产生不同的行为。在 Python 中,多态既可以通过继承加方法重写实现,也可以通过鸭子类型实现。也就是说,只要对象具有相同的方法接口,就可以被统一处理,从而提高代码扩展性和灵活性。把对象的属性和方法放在一类里,并且控制外部对内部细节的访问。
一个对象内部怎么实现,你不用都知道;你只需要通过它提供的方法去使用它。
为什么需要封装:隐藏实现细节,使用者不需要知道内部怎么实现的,只要知道怎么调用即可;保护数据,不让外部直接乱改对象内部数据,避免出现非法状态;让代码更容易维护,内部实现以后可以修改,但只要对外结构不变,外部代码基本不用动。
无Java那样强制的private、public。
class Student: def __init__(self, name, score): self.name = name self.score = score
def show_info(self): print(f"姓名:{self.name},成绩:{self.score}")“私有属性”和“私有方法”
公有成员:正常命名,谁都能访问
受保护成员(约定俗成):单下划线开头:_name,表示: 这是内部使用的,不建议在类外直接访问 ,但实际上仍然可以访问。
私有成员:双下划线开头:__name,Python 会做 名称重整(name mangling),防止外部直接访问。
class Student: def __init__(self, name, score): self.__name = name self.__score = score
def show_info(self): print(f"姓名:{self.__name},成绩:{self.__score}")因为 Python 实际上把它改成了类似: s._Student__name 虽然技术上还能访问: print(s._Student__name) 但这只是“能”,不代表“应该”。 所以要记住: Python 的私有更像是一种“尽量别动”的保护机制,而不是绝对封锁。
封装的关键,不只是“藏起来”,更重要的是:通过方法控制数据的读写逻辑。
Python 更推荐用 @property,实现优雅封装。
class Student: def __init__(self, name, score): self.name = name self._score = 0 self.score = score
@property def score(self): return self._score
@score.setter def score(self, value): if 0 <= value <= 100: self._score = value else: raise ValueError("分数必须在 0 到 100 之间")s = Student("Cindy", 88)print(s.score) # 88
s.score = 99print(s.score) # 99继承就是:一个类可以拥有另一个类的属性和方法。
为什么需要继承:代码复用,很多类有共同的功能,不需要每个类都重写一遍;建立类之间的层次关系,比如动物–猫、狗;便于扩展,子类在继承父类能力的基础上,还能增加自己的新功能。
继承父类的方法,属性;子类可重写override,但python可以不用加注解。
子类如何调用父类方法:super()
class Animal: def __init__(self, name): self.name = name
def speak(self): print("动物发声")
class Dog(Animal): def __init__(self, name, breed): super().__init__(name) self.breed = breed
def speak(self): super().speak() print(f"{self.name} 在汪汪叫")如果子类定义了自己的 __init__,父类的 __init__ 不会自动执行,需要你手动调用。
可以单继承和多继承,多继承里,如果多个父类都有同名方法,Python 按 MRO(方法解析顺序) 查找。
多态就是:同一个方法调用,作用于不同对象,会产生不同结果。
多态依赖于:继承,方法重写
Python 中多态的特点:鸭子类型,和 Java/C++ 很不一样。Python 是动态语言,它的多态更灵活。Python 不一定要求“必须继承同一个父类”,只要对象支持某个方法,就能拿来用。
Python 更关注:你有没有这个方法,而不是 你是不是某个类的子类。
为什么需要多态:提高扩展性,以后新增一个类,只要实现同样的方法,就能无缝接入原有代码;降低耦合,调用房不需要关心具体类型,只关心对象具备什么行为;代码更通用,同一套逻辑可以处理多种对象。