躬身入局,干货分享,2023年春招后端技术岗(Python)面试实战教程,Offer今始为君发

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 早春二月,研发倍忙,杂花生树,群鸥竟飞。为什么?因为春季招聘,无论是应届生,还是职场老鸟,都在摩拳擦掌,秣马厉兵,准备在面试场上一较身手,既分高下,也决Offer,本次我们打响春招第一炮,躬身入局,让2023年的第一个Offer来的比以往快那么一点点。

早春二月,研发倍忙,杂花生树,群鸥竟飞。为什么?因为春季招聘,无论是应届生,还是职场老鸟,都在摩拳擦掌,秣马厉兵,准备在面试场上一较身手,既分高下,也决Offer,本次我们打响春招第一炮,躬身入局,让2023年的第一个Offer来的比以往快那么一点点。

打开某垂直招聘平台,寻找2023年的第一个猎物:

投递简历之后,如约进行面试。

笔试题

正规公司的面试一般都是笔试先行,笔试题的作用非常务实,就是直接筛掉一批人,提高面试效率,需要注意的是,在这个环节中,往往无法用搜索引擎进行检索,所以,你的大脑就是Python解释器,你的笔将会代替程序的输出:

# 实现字符串反转,以逗号作为切割符,切割的子串以单词作为单元反转  
# 输入:hello world, god bless you  
# 输出:world hello, you bless god

这道题网上没有原题,但其实并不难,考点在于应聘者对于Python基础和复合数据类型内置方法的熟悉程度,题目中所谓的字符串反转并不是真正意义的字符串反转,而是以单词为单元的反转,同时加入了逗号分割逻辑,所以只要对字符串内置方法split,rstrip和列表内置方法join以及reverse的用法足够了解,就可以直接写出解法:

def reseverWords(s:str) ->  str:  
    all_str =   ""  
    s   =    s.split(',')  
    for x   in  s:  
        lis=    x.split()  
        lis.reverse()  
        all_str +=  ' '.join(lis)+', '  
    all_str=all_str.rstrip(', ')  
    return  all_str  
print(reseverWords(str1))

第二题是SQL语句题目,请写一条sql,按照地区的分组聚合数据进行排序:

id    name       location  
--    -----      --------  
1     Mark       US  
2     Mike       US  
3     Paul       Australia  
4     Pranshu    India  
5     Pranav     India  
6     John       Canada  
7     Rishab     India

排序后结果:

id    name       location  
--    -----      --------  
4     Pranshu    India  
5     Pranav     India  
7     Rishab     India  
1     Mark       US  
2     Mike       US  
3     Paul       Australia  
6     John       Canada

这道题也无法在网上查证,一般的分组聚合只是查一个数,这个是按照数量进行排序,并且其实并不展示数量,也可以理解为展示的为分组数据的明细排行榜:

SELECT x.*   
  FROM my_table x   
  JOIN (SELECT location, COUNT(*) total FROM my_table GROUP BY location) y  
    ON y.location = x.location  
 ORDER   
    BY total DESC  
     , id;

思路是先分组,随后按照分组的聚合数据根据地区字段连表排序即可。

自我介绍

通过笔试题筛选后,进入自我介绍环节,一般介绍技术栈和简单的项目经历即可,参考示例:

您好(下午好/上午好),我是19年毕业的,在RD(Research and Development engineer即研发工程师岗位)岗差不多有三年左右的工作经验,一开始在一家创业型公司起步,当时主力开发语言是python,,使用mtv架构,在公司主要和业务打交道,开发和维护后台的API,大概沉淀了两年左右吧,我跳槽到了第二家公司,薪酬实现了double,在新的技术团队里,我接触到了前后端分离项目,也学习了异步编程思想,主力框架是tornado,前端技术也有所涉猎,比如vue框架,了解了数据双向绑定理念,同时也学习了在业务解耦和服务封装层面比较流行的docker容器技术,这项技术使我平时开发和测试工作都提高了效率,最近一年左右吧,我经常使用的web框架是tornado,这个框架我个人非常喜欢,它的异步非阻塞特性让我对异步编程思想的认识更深入了。我也尝试过remote这种工作形式,也锻炼了我在团队中的沟通能力,其实三四年下来,做过的东西解决过的问题也挺多的,待过大团队也经历过小团队,给我的感觉就是互联网企业随着发展,技术和行业边界其实是越来越模糊的,也就是说技术都是具有相通性的,我个人来讲,优势就是技术涉猎比较广,前后端都接触过,踩得坑也比较多,在特定领域有一定的深入,比如异步编程这块。另外我觉得搞开发的,学习能力,总结能力很重要,所以我一直保持着写技术博客的习惯,这样经过沉淀,可以提高一个人的分析能力,也就是解决问题的能力,我的介绍完了,谢谢。

进程、线程和协程的区别

进程、线程和协程,从来就是Python面试中聚讼不休的一个话题,只要我们还在使用Python,就一定逃离不了三程问题:

进程

首先明确一下进程和线程的概念,进程系统进行资源分配的基本单位,一台机器上可以有多个进程,每个进程执行不同的程序,每个进程相对独立,拥有自己的内存空间,隔离性和稳定性比较高,进程之间互不影响,但是资源共享相对麻烦,系统资源占用相对高,同时进程可以利用cpu多核资源,适合cpu密集型任务,比如一些统计计算任务,比如计算广告转化率,uv、pv等等,或者一些视频的压缩解码任务,进程还有一个使用场景,就是后期部署项目的时候,nginx反向代理后端服务,往往需要开启多个tornado服务来支持后台的并发,就是利用了多进程的互不干扰,就算某个进程僵死,也不会影响其他进程,进程使用的是mulitprossing库 ,往往是先声明进程实例,里面可以传入消费方法名称和不定长参数args,然后将实例放入指定进程数的容器中(list),通过循环或者列表推导式,使用start方法开启进程,join方法阻塞主进程。

线程

线程是系统进行资源调度的最小单位,它属于进程,每一个进程中都会有一个线程,由于线程操作是单进程的,所以线程之间可以共享内存变量,互相通信非常方便,它的系统开销比进程小,它是线程之间由于共享内存,会互相影响,如果一个线程僵死会影响其他线程,隔离性和稳定性不如进程,同时,线程并不安全,如果对同一个对象进行操作,需要手动加锁,另外从性能上讲,多线程会触发python的全局解释器锁,导致同一时间点只会有一个线程运行的交替运行模式,线程适用于io密集型任务,所谓io密集型任务就是大量的硬盘读写操作或者网络tcp通信的任务,一般就是爬虫和数据库操作,文件操作非常频繁的任务,比如我负责开发的审核系统,需要同时对mysql和redis有大量的读写操作,所以我使用多线程进行消费。线程使用的是Threading库 ,往往是先声明线程实例,里面可以传入消费方法名称和不定长参数args,然后将实例放入指定线程数的容器中(list),通过循环或者列表推导式,使用start方法开启线程,join方法阻塞主线程。

协程

协程是一种用户态的轻量级线程,协程的调度完全由用户控制,不像进程和线程是系统态,所以在不主动切换协程的情况下,操作全局变量的时候,可以无需加锁(这里有坑,协程库内置也是有锁的,但是看场景,如果使用场景内没有主动切换协程(await)写操作就不需要加锁,如果单协程执行过程中,主动切换了协程,写操作则需要加锁 协程是否加锁问题),只需要判断资源状态即可,效率非常高,同时协程是单线程的,即可以共享内存,又不需要系统态的线程切换,同时也不会触发gil全局解释器锁,所以它性能比线程要高。具体使用场景和线程一样,适合io密集型任务,所谓io密集型任务就是大量的硬盘读写操作或者网络tcp通信的任务,一般就是爬虫和数据库操作,文件操作非常频繁的任务,比如我负责开发的审核系统,需要同时对mysql和redis有大量的读写操作,所以我后期将多线程改造成协程进行消费。协程我使用的python原生协程库asyncio库,首先通过asyncio.ensure\_future(doout(4))方法建立协程对象,然后根据当天审核员数量指定开启协程数,和多线程以及多进程的区别是,协程既可以直接传实参,也可以传不定长参数,很方便,然后通过await asyncio.gather(*tasks)方法启动协程,需要注意的是,主方法需要声明成async方法,并且通过asyncio.run(main())来启动。协程虽然是python异步编程的最佳方式,但是我认为它也有缺点,那就是异步写法导致代码可读性下降,同时对编程人员的综合素质要求高,并不是所有人都能理解协程的工作方式,以及python原生协程的异步写法。

Python中的深拷贝和浅拷贝

仅次于三程问题的明星面试题,一般情况下,大家都会说浅拷贝修改复制对象会影响原对象,而深拷贝不会,但其实,浅拷贝会有三种细分的情况:

1.拷贝不可变对象:只是增加一个指向原对象的引用,改变会互相影响。

>>> a = (1, 2, [3, 4])  
>>> b = copy.copy(a)  
>>> b  
... (1, 2, [3, 4])  
# 改变一方,另一方也改变  
>>> b[2].append(5)  
>>> a  
... (1, 2, [3, 4, 5])

2.拷贝可变对象(一层结构):产生新的对象,开辟新的内存空间,改变互不影响。

>>> import copy  
  
>>> a = [1, 2, 3]  
>>> b = copy.copy(a)  
>>> b  
... [1, 2, 3]  
# 查看两者的内存地址,不同,开辟了新的内存空间  
>>> id(b)  
... 1833997595272  
>>> id(a)  
... 1833997595080  
>>> a is b  
... False  
# 改变了一方,另一方不会改变  
a = [1, 2, 3]    b = [1, 2, 3]  
>>> b.append(4)  
>>> a  
... [1, 2, 3]  
>>> a.append(5)  
>>> b  
... [1, 2, 3, 4]

3.拷贝可变对象(多层结构):产生新的对象,开辟新的内存空间,不改变包含的子对象则互不影响、改变包含的子对象则互相影响。

>>> import copy  
  
>>> a = [1, 2, [3, 4]]  
>>> b = copy.copy(a)  
>>> b  
... [1, 2, [3, 4]]  
# 查看两者的内存地址,不同,开辟了新的内存空间  
>>> id(b)  
1833997596488  
>>> id(a)  
1833997596424  
>>> a is b  
... False  
# 1.没有对包含的子对象进行修改,另一方关我卵事  
a = [1, 2, [3, 4]]    b = [1, 2, [3, 4]]  
>>> b.append(5)  
>>> a  
... [1, 2, [3, 4]]  
>>> a.append(6)  
>>> b  
... [1, 2, [3, 4], 5]  
# 2.对包含的子对象进行修改,另一方也随之改变  
a = [1, 2, [3, 4]]    b = [1, 2, [3, 4]]  
>>> b[2].append(5)  
>>> a  
... [1, 2, [3, 4, 5]]  
>>> a[2].append(6)  
>>> b  
... [1, 2, [3, 4, 5, 6]]

高并发如何进行处理的

既然JD(Job Describe)中提到了高并发,那么就一定会问高并发问题,一般情况下,涉及高并发场景的基本上都是外部系统,此时需要简单介绍一下系统的容量是多少,比如有注册用户数、日活、QPS等等。然后就是提供具体方案,一般的手段是加缓存,数据库读写分离,数据库 sharding 等等。高并发背景下,整个系统瓶颈一般都在数据库。

除了上述的一些常规方案,业内最常用的缓解高并发的手段是使用异步任务队列:

为了解决生产者和消费者过度耦合的效率低下问题,我设计了一个缓冲区,生产者不会直接和消费者产生关系,而是通过缓冲区解耦,这个缓冲区就是异步任务队列,队列容器我采用redis数据库,因为redis性能优势比较明显,同时内置的list数据类型比较契合队列这种数据结构,工具类内置了,初始化方法,入队方法,出队方法,队列长度,以及查重唯一方法。每当商户提交表单,此时并不会修改状态,而是将表单数据入库,同时将商户uid进行入队操作,遵循fifo原则,在消费者端使用异步的方式进行消费,也就是出队操作,每一个线程对应一个审核员,通过消费方法进行传参,每次将出队的商户uid和线程传入的审核员id进行组合分配,出队之后并发数已经得到了控制,随后在mysql端进行update操作,达到异步分配审核的目的。

保持幂等性

如果面试中提到了异步任务队列(消息队列),那么幂等性操作几乎一定会在后续的问题中提及,所谓幂等性,简单来说就是对于同一个系统,在同样条件下,一次请求和重复多次请求对资源的影响是一致的,就称该操作为幂等的。比如说如果有一个接口是幂等的,当传入相同条件时,其效果必须是相同的。在RabbitMQ中消费幂等就是指给消费者发送多条同样的消息,消费者只会消费其中的一条。例如,在一次购物中提交订单进行支付时,当网络延迟等其他问题造成消费者重新支付,如果没有幂等性的支持,那么会对同一订单进行两次扣款,这是非常严重的,因此有了幂等性,当对同一个订单进行多次支付时,可以确保只对同一个订单扣款一次。

具体手段:

事实上,当审核任务出队之后,如果在消费端出现意外,这个意外包含但不限于出对后tornado宕机、mysql宕机等等,导致出队任务没有进行流程化处理,所以我采用了ack验证机制,也就是缓冲区队列从单队列升级为双队列,把rpop出队改成redis内置的rpoplpush的原子性操作,出队后立即进入确认队列,在消费端完成审核任务后,对ack队列进行确认移除操作,如此,一次审批任务才算完结,如果任务生命周期内,任务一直存在于确认队列没有出队,那么轮询任务会将任务id移出确认队列,重新在缓冲区队列进行入队操作,这样就避免了,僵审任务的问题。

结语

技术面试虽然是一种信息不对等的较量,但是只要认真研究JD(Job Describe),做好相关的知识储备,基础常识不要翻车(包含但不限于Python基础/数据库基础),那么作为应聘者拿一个Offer也不是想象中的那么难,本次面试的实战录音可以在B站(Youtube)搜索刘悦的技术博客查阅,欢迎诸君品鉴。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
6天前
|
API 数据库 数据安全/隐私保护
Flask框架在Python面试中的应用与实战
【4月更文挑战第18天】Django REST framework (DRF) 是用于构建Web API的强力工具,尤其适合Django应用。本文深入讨论DRF面试常见问题,包括视图、序列化、路由、权限控制、分页过滤排序及错误处理。同时,强调了易错点如序列化器验证、权限认证配置、API版本管理、性能优化和响应格式统一,并提供实战代码示例。了解这些知识点有助于在Python面试中展现优秀的Web服务开发能力。
22 1
|
4天前
|
前端开发 测试技术 C++
Python自动化测试面试:unittest、pytest与Selenium详解
【4月更文挑战第19天】本文聚焦Python自动化测试面试,重点讨论unittest、pytest和Selenium三大框架。unittest涉及断言、TestSuite和覆盖率报告;易错点包括测试代码冗余和异常处理。pytest涵盖fixtures、参数化测试和插件系统,要注意避免过度依赖unittest特性。Selenium的核心是WebDriver操作、等待策略和测试报告生成,强调智能等待和元素定位策略。掌握这些关键点将有助于提升面试表现。
19 0
|
4天前
|
数据采集 存储 JSON
Python爬虫面试:requests、BeautifulSoup与Scrapy详解
【4月更文挑战第19天】本文聚焦于Python爬虫面试中的核心库——requests、BeautifulSoup和Scrapy。讲解了它们的常见问题、易错点及应对策略。对于requests,强调了异常处理、代理设置和请求重试;BeautifulSoup部分提到选择器使用、动态内容处理和解析效率优化;而Scrapy则关注项目架构、数据存储和分布式爬虫。通过实例代码,帮助读者深化理解并提升面试表现。
13 0
|
6天前
|
SQL 中间件 API
Flask框架在Python面试中的应用与实战
【4月更文挑战第18天】**Flask是Python的轻量级Web框架,以其简洁API和强大扩展性受欢迎。本文深入探讨了面试中关于Flask的常见问题,包括路由、Jinja2模板、数据库操作、中间件和错误处理。同时,提到了易错点,如路由冲突、模板安全、SQL注入,以及请求上下文管理。通过实例代码展示了如何创建和管理数据库、使用表单以及处理请求。掌握这些知识将有助于在面试中展现Flask技能。**
12 1
Flask框架在Python面试中的应用与实战
|
7天前
|
数据可视化 Python
Python模型评估与选择:面试必备知识点
【4月更文挑战第17天】本文深入探讨了Python模型评估与选择在面试中的关键点,包括性能度量、过拟合与欠拟合识别、模型比较与选择、模型融合和偏差-方差权衡。强调了避免混淆评估指标、忽视模型验证和盲目追求高复杂度模型的常见错误,并提供相关代码示例,如交叉验证、网格搜索和超参数调优。通过理解这些概念和技巧,可在面试中展示出色的数据科学能力。
31 12
|
7天前
|
机器学习/深度学习 搜索推荐 Python
Python特征工程面试:从理论到实践
【4月更文挑战第17天】本文探讨了Python在数据科学面试中的特征工程,涵盖基础概念如特征选择和提取,实战技能如缺失值和异常值处理,以及特定场景应用。强调避免过度依赖单一方法,忽视数据分布和相关性,以及保持特征工程的可解释性。提供代码示例展示了处理缺失值、标准化、特征选择和异常值检测的基本操作。建议结合业务理解,灵活运用多种方法并注重模型解释性。
21 9
|
7天前
|
数据采集 机器学习/深度学习 数据挖掘
Python数据清洗与预处理面试题解析
【4月更文挑战第17天】本文介绍了Python数据清洗与预处理在面试中的常见问题,包括Pandas基础操作、异常值处理和特征工程。通过示例代码展示了数据读取、筛选、合并、分组统计、离群点检测、缺失值和重复值处理、特征缩放、编码、转换和降维。强调了易错点,如忽视数据质量检查、盲目处理数据、数据隐私保护、过度简化特征关系和忽视模型输入要求。掌握这些技能和策略将有助于在面试中脱颖而出。
23 8
|
7天前
|
缓存 自然语言处理 数据处理
Python自然语言处理面试:NLTK、SpaCy与Hugging Face库详解
【4月更文挑战第16天】本文介绍了Python NLP面试中NLTK、SpaCy和Hugging Face库的常见问题和易错点。通过示例代码展示了如何进行分词、词性标注、命名实体识别、相似度计算、依存关系分析、文本分类及预训练模型调用等任务。重点强调了理解库功能、预处理、模型选择、性能优化和模型解释性的重要性,帮助面试者提升NLP技术展示。
24 5
|
7天前
|
NoSQL MongoDB Redis
Python与NoSQL数据库(MongoDB、Redis等)面试问答
【4月更文挑战第16天】本文探讨了Python与NoSQL数据库(如MongoDB、Redis)在面试中的常见问题,包括连接与操作数据库、错误处理、高级特性和缓存策略。重点介绍了使用`pymongo`和`redis`库进行CRUD操作、异常捕获以及数据一致性管理。通过理解这些问题、易错点及避免策略,并结合代码示例,开发者能在面试中展现其技术实力和实践经验。
129 8
Python与NoSQL数据库(MongoDB、Redis等)面试问答
|
7天前
|
SQL 关系型数据库 MySQL
Python与MySQL数据库交互:面试实战
【4月更文挑战第16天】本文介绍了Python与MySQL交互的面试重点,包括使用`mysql-connector-python`或`pymysql`连接数据库、执行SQL查询、异常处理、防止SQL注入、事务管理和ORM框架。易错点包括忘记关闭连接、忽视异常处理、硬编码SQL、忽略事务及过度依赖低效查询。通过理解这些问题和提供策略,可提升面试表现。
28 6