跳转到内容

搜索仅适用于生产版本。 尝试构建并预览网站以在本地测试。

Python 面试准备

python

GIL(Global Interpreter Lock,全局解释器锁)

Section titled “GIL(Global Interpreter Lock,全局解释器锁)”

CPython 解释器中的一个互斥锁:同一时刻只有一个线程执行 Python 字节码。

为什么 Python 需要 GIL:核心原因:内存管理(尤其是引用计数)。CPython 使用 引用计数(Reference Counting) 来做垃圾回收。

同步锁:

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:异步发送事件

核心:asyncio Event Loop

事件循环是一个不断运行的循环:

封装是指把数据和操作数据的方法封装到类中,并对外隐藏内部实现细节,只暴露必要接口。在 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 = 99
print(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 更关注:你有没有这个方法,而不是 你是不是某个类的子类

为什么需要多态:提高扩展性,以后新增一个类,只要实现同样的方法,就能无缝接入原有代码;降低耦合,调用房不需要关心具体类型,只关心对象具备什么行为;代码更通用,同一套逻辑可以处理多种对象。