第一次遇到技术面,由于我问题没答上来几道并且时间排不开,所以无疾而终……
这个岗位的背景:会用Linux进行定位和调试,需要用Python+Django技术栈编写一些简单的运维工具。
第一部分:根据简历进行自我介绍
第二部分:技术面试:
1. Python 中什么场景用Django合适?什么时候用FastAPI合适?
Django 适合的场景:
全功能型 Web 应用
需要内置完整功能(如 Admin 后台、ORM、用户认证、模板引擎)。
适合内容管理系统(CMS)、电商平台、社交网站等业务逻辑复杂、需要快速原型开发的项目。
强调开发效率与“开箱即用”
团队希望减少重复造轮子,直接使用 Django 的成熟组件(如 Session 管理、路由、中间件)。
项目需求明确,遵循 MVC 模式,适合中大型长期维护的系统。
强数据驱动型项目
ORM 对复杂查询和数据库迁移支持完善,适合对数据一致性要求高的场景(如金融、企业信息化系统)。
FastAPI 适合的场景:
高性能 API 服务
对并发和响应速度要求高(如微服务架构中的独立服务、实时数据处理接口)。
利用异步支持(Async/Await)处理高并发 I/O 操作(如大量外部请求、WebSocket)。
轻量级或微服务架构
项目仅需提供 RESTful/GraphQL API,不需要内置前端模板或后台管理功能。
适合前后端分离场景,前端独立部署(如 Vue/React 项目搭配 FastAPI 后端)。
快速迭代的现代技术栈
团队希望使用类型注解(Pydantic)、自动文档生成(OpenAPI)、依赖注入等现代特性。
适合新兴领域如 IoT 数据接口、AI 模型服务、快速实验性项目。
选型决策建议(补充说明):
团队熟悉度:若团队长期使用 Django 且业务匹配,切换成本低;若团队熟悉异步编程,FastAPI 更易上手。
生态扩展:Django 插件市场丰富(如 Django REST Framework 可构建 API),FastAPI 轻量但依赖社区组合工具链。
性能边界:99% 的项目两者均能满足性能需求,除非涉及极端高并发(如每秒数万请求),否则优先考虑开发效率。
2. Python 中装饰器是什么 如何实现的?装饰器返回的是什么?
装饰器是 Python 中一种强大的语法特性,它允许在不修改原始函数或类代码的情况下,为它们添加额外功能。以下是核心要点:
- 装饰器是什么
装饰器本质上是一个可调用对象,通常是一个函数或类,它可以:
接收一个函数或类作为参数
扩展或修改其功能
返回一个新的函数或类
通过 @decorator语法糖在定义时应用 - 如何实现装饰器
装饰器的核心实现基于 闭包和函数作为一等公民 的特性:
基本实现模板:
def decorator(original_func): # 接收原始函数
def wrapper(*args, **kwargs): # 定义包装函数
# 添加额外功能(如日志、权限校验)
result = original_func(*args, **kwargs) # 调用原始函数
# 添加后续处理
return result
return wrapper # 返回包装函数实际应用场景:
日志记录:自动记录函数执行情况
性能测试:计算函数执行时间
权限校验:检查用户权限
缓存机制:实现结果缓存
单例模式:确保类只有一个实例
3. 面向对象的三大特性是什么?具体含义是什么?怎么用呢?
封装
核心思想:将数据(属性)和操作数据的方法(行为)捆绑在一起,并隐藏内部实现细节,仅对外暴露有限的接口。
主要目的:
保护数据的完整性,防止外部直接修改对象状态。
降低模块间的耦合,提高代码安全性。
举例:比如定义一个BankAccount类,将余额(balance)设为私有属性,提供公有的deposit()和withdraw()方法进行存取,外部无法直接修改余额。
继承
核心思想:允许一个类(子类)基于另一个类(父类)来构建,从而获得父类的属性和方法,并可以在此基础上进行扩展或修改。
主要目的:
实现代码复用,避免重复编写相同逻辑。
建立类之间的层次关系,便于抽象和扩展。
举例:比如有一个Vehicle(车辆)父类,包含move()方法;子类Car和Bicycle可以继承Vehicle,并重写或扩展move()方法。
多态
核心思想:同一操作(如方法调用)作用于不同类的对象时,可以产生不同的行为。多态通常依赖于继承或接口实现。
主要目的:
增强代码的灵活性,允许程序在运行时根据对象类型决定具体行为。
支持“面向接口编程”,降低代码依赖。
举例:比如Animal类有makeSound()方法,子类Dog和Cat分别重写该方法。当调用不同子类对象的makeSound()时,会分别输出“汪汪”和“喵喵”,而代码可以通过父类类型统一处理。
4.进程、线程与协程的含义是什么?如何区分?场景是什么?
进程
定义:进程是操作系统进行资源分配和调度的基本单位。简单说,一个运行起来的程序就是一个进程。每个进程都拥有自己独立的地址空间、内存、数据栈以及各种系统资源(如文件句柄)。
核心理解:进程是资源的“集装箱”,是程序的一次执行过程。进程间是相互隔离的,一个进程崩溃通常不会影响其他进程。
线程
定义:线程是操作系统能够进行运算调度的最小单位,是进程内的一个执行流。一个进程可以包含多个线程,这些线程共享进程的地址空间和大部分资源(如内存、文件)。
核心理解:线程是进程内的“车间”,是CPU调度的基本单位。线程共享资源带来了高效的通信,但也带来了数据同步和线程安全的挑战。
协程
定义:协程是一种用户态的、更轻量级的“微线程”。它不由操作系统内核直接调度,而是由程序员在用户空间控制其创建、切换和销毁。协程的调度发生在用户态,没有线程切换的开销。
核心理解:协程是线程内的“工人”,是协作式的。一个线程内可以运行成千上万个协程,由协程自己主动让出控制权,而不是被系统强制抢占。
我们可以从以下几个维度进行清晰区分:
| 维度 | 进程 | 线程 | 协程 |
|---|---|---|---|
| 调度单位 | 操作系统 | 操作系统 | 用户/程序员(运行时库) |
| 切换开销 | 很高(切换页表、寄存器、内核栈等) | 高(需要内核介入,切换线程上下文) | 极低(只是保存/恢复少量寄存器,在用户态完成) |
| 资源拥有 | 资源分配的基本单位,独立拥有内存、IO等 | 共享进程的资源,拥有独立的栈、计数器 | 共享线程的资源,拥有独立的上下文(栈、寄存器状态) |
| 内存隔离 | 完全隔离,需IPC通信 | 共享内存,需同步机制(锁) | 共享内存,但通常单线程内顺序执行,同步压力小 |
| 并发性 | 可多核并行 | 可多核并行 | 本质是协作式,单线程内并发,可利用多线程实现并行 |
| 健壮性 | 高,一个进程崩溃不影响其他进程 | 低,一个线程崩溃可能导致整个进程退出 | 取决于实现,未处理的异常可能导致整个线程/进程终止 |
| 比喻 | 一个独立的“工厂”,有独立的地皮和资源 | 工厂里的“车间”,共享工厂资源,独立工作 | 车间里的“工人”,协同完成一项任务,可随时停下换人 |
典型使用场景
- 进程的场景
- 需要高安全性和隔离性的任务:如浏览器(每个标签页一个进程)、Chrome;数据库服务器为每个连接创建独立进程(如PostgreSQL的早期模式)。
- 需要利用多核优势的独立程序:系统服务、独立的守护进程。
- 进程崩溃不能影响主程序的场景。
- 线程的场景
- 需要高性能并发且需要共享数据的任务:如Web服务器(如Tomcat, Nginx的worker进程内部用线程处理请求)、桌面GUI应用(一个线程处理UI,一个线程处理后台计算)。
- 多核CPU上进行密集型并行计算:如数据处理、科学计算,但要注意线程安全。
- IO密集型应用,利用阻塞IO时的多线程来提高吞吐。
- 协程的场景
- 超高并发的IO密集型应用:这是协程的“主战场”。例如:
- 高性能网络服务:如微服务网关、即时通讯(IM)后端,单机可轻松支撑数万甚至十万级连接(如Go的net/http, Python的gevent/aiohttp)。
- 爬虫:高效管理成千上万个网络请求。
- 需要大量轻量级“并发”任务的游戏开发:每个游戏对象可以是一个协程,管理自己的状态机。
- 简化异步回调的“回调地狱”:用同步的代码写法实现异步的性能(async/await语法)。
- 超高并发的IO密集型应用:这是协程的“主战场”。例如:
第三部分:学校允许实习吗?时间怎么协调的?未来方向是什么?
文章评论