python面试问题210902
面试进**代科技(北京)有限责任公司44分钟
我答:
我是做了3年的python开发。
第一年主要做些python后端,然后利用flask、django处理数据,以及协助开发CRM系统。
第二年主要做了些系统运维、python、sql处理数据并生成可视化数据等。
第三年在第二年基础上做系统运维、python开发、数据处理采集分析外,还做项目经理的工作。
面试官问:
就是负责和外包公司协调么?
我答:
除了和外包公司,还有本公司、甲方公司、甲方分包协调,然后也参与制定整个项目组的工作计划、成果、周报等。
优化
我答:
我是做了3年的python开发。
第一年主要做些python后端,然后利用flask、django处理数据,以及协助开发CRM系统。
第二年主要做了些系统运维、python、sql处理数据并生成可视化数据等。
第三年在第二年基础上做系统运维、python开发、数据处理采集分析外,还做项目经理的工作。就是还得和外包公司、外包服务公司、甲方公司、甲方分包协调,然后制定整个项目组的工作计划、成果、周报等。
最后协助推动了项目完成终验,并在做项目经理的期间给我们服务的公司拿回项目回款一百五十多万。
1.django中间件作用和装饰器的区别
我答:
就是在请求过来后,然后预处理数据,返回给视图,再做处理。
面试官:
就这么简单?
我答:
好像还有请求、相应、异常等多个处理。
面试官:
和装饰器有什么区别和联系?
我答:
感觉和装饰器差不多,装饰器也是走函数前处理,把函数当做参数。感觉差不多,区别不知道。
面试官:
区别也很简单。
网上搜:
抄自https://blog.csdn.net/SpringBears/article/details/106688342
装饰器是Python的一种语法应用,利用闭包的原理去更改一个函数的功能,即让一个函数执行之前先到另外一个函数中执行其他需求语句,在执行该函数。在开发项目中,通常使用装饰器来管理权限,登录等等,配上Python的 @ 语法糖,轻松实现代码的重用性和低耦合性。
而Django中的中间件是利用面向切面的编程思想,对Django服务器访问过程中间进行干预。
是一个轻量级、底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出。
二、联系及区别
联系:中间件是利用装饰器原理实现的,具体通过两个函数嵌套、或通过改写类中的__ call __方法实现一个装饰器功能。使之过来的Request的请求,先到call方法中进行处理。配置中间件,实现过程干预。
区别:一个是Python的语法功能,一个是Django 框架自带的轻量级插件系统。
中间件《the django book》
在有些场合,需要对Django处理的每个request都执行某段代码。 这类代码可能是在view处理之前修改传入的
request,或者记录日志信息以便于调试,等等。
这类功能可以用Django的中间件框架来实现,该框架由切入到Django的request/response处理过程中的钩子
集合组成。 这个轻量级低层次的plug-in系统,能用于全面的修改Django的输入和输出。
View预处理函数:
process_view(self, request, view, args, kwargs)
Response后处理函数: process_response(self, request, response)
Exception后处理函数: process_exception(self, request, exception)
这个方法只有在request处理过程中出了问题并且view函数抛出了一个未捕获的异常时才会被调用。 这个钩子可以用来发送错误通知,将现场相关信息输出到日志文件, 或者甚至尝试从错误中自动恢复。
内置的中间件
认证支持中间件 request.user
通用中间件(咱没搞懂)
压缩中间件 这个中间件自动为能处理gzip压缩(包括所有的现代浏览器)的浏览器自动压缩返回]内容
条件化的GET中间件
反向代理支持 (X-Forwarded-For中间件)
2.flask蓝图
我答:就是处理路由的把。忘了。
面试官:然后呢。
网上搜:
Blueprint 是一种组织一组相关视图及其他代码的方式。与把视图及其他 代码直接注册到应用的方式不同,蓝图方式是把它们注册到蓝图,然后在工厂函数中 把蓝图注册到应用。
3.session和cookie的区别
忘了。好像cookie不如session安全,然后cookie网上生成,然后session自己写的。
狼书
http是无状态的,但是有的客户端信息又必须被记住,根据用户的状态返回不同的响应,才有了cookie。通过在请求和响应报文中添加cookie数据来保存客户端的状态信息。
cookie可以保存状况,但是,浏览器端可以看到,然后,还可以修改,不安全可能会有人伪造
session是将cookie的内容,利用秘钥加密,浏览器端看到的是密文,也没法修改。保证了安全性。
4.jwt和session认证的区别
我:
是那个跨域请求伪造么?
面试官:
不是,是两个,这个是认证。
我:不会
网上:https://zhuanlan.zhihu.com/p/108999941
Authentication和Authorization的区别:
Authentication:用户认证,指的是验证用户的身份,例如你希望以小A的身份登录,那么应用程序需要通过用户名和密码确认你真的是小A。
Authorization:授权,指的是确认你的身份之后提供给你权限,例如用户小A可以修改数据,而用户小B只能阅读数据。
基于session的认证流程如下:
1.用户输入其登录信息
2.服务器验证信息是否正确,并创建一个session,然后将其存储在数据库中
3.服务器为用户生成一个sessionId,将具有sesssionId的Cookie将放置在用户浏览器中
4.在后续请求中,会根据数据库验证sessionID,如果有效,则接受请求
5.一旦用户注销应用程序,会话将在客户端和服务器端都被销毁
基于token(令牌)的用户认证
1.用户输入其登录信息
2.服务器验证信息是否正确,并返回已签名的token
3.token储在客户端,例如存在local storage或cookie中
4.之后的HTTP请求都将token添加到请求头里
5.服务器解码JWT,并且如果令牌有效,则接受请求
6.一旦用户注销,令牌将在客户端被销毁,不需要与服务器进行交互一个关键是,令牌是无状态的。后端服务器不需要保存令牌或当前session的记录。
5.你们在项目上有没有数据库调优
我:没有,一般是查询语句改下,表结构一般不敢动
网上东西讲的好乱,可以的话,以后自己总结答案。
从《高性能mysql》看
1.Schema与数据类型优化(设计最优的库表结构):
防止Schema设计陷阱、选择优化的数据类型、满足范式、同张表中保存衍生的冗余数据或生成简单获取数据的缓存表或聚合数据的汇总表
2.创建高性能的索引:
哈希、全文、空间数据、其他索引等
3.合理的设计查询:
优化数据访问(防止返回不需要的、全部的、重复查询相同的)、查看是否mysql存在额外扫描,然后设立策略、重构查询的方式
。。。。等把,今天不写了,太多了,到高性能sql6.3节
6.mysql的底层数据结构
B+树
7.mysql和psql的区别和相同
我答:
mysql和psql的一些语法不一样,建表也一些不一样,mysql提供了更多的集成的函数,psql得自己写;建表比如mysql可以直接添加自增,psql需要设置series或者先创建序列然后再加到表中。
还有,据大数据框架书了解,大数据存储通常用psql,然后组成MPP框架,可以用来存储很大级别数据,上家存储一个市的数据库就是用的psql,大数据存储方面可能psql比mysql更擅长。(为什么存储大数据集我没说,弱鸡)
网上说4、PG主表采用堆表存放,MySQL采用索引组织表,能够支持比MySQL更大的数据量。
网上:
https://zhuanlan.zhihu.com/p/46405604
https://www.cnblogs.com/macT/p/11582435.html
一.PostgreSQL相对于MySQL的优势
1、在SQL的标准实现上要比MySQL完善,而且功能实现比较严谨;
2、存储过程的功能支持要比MySQL好,具备本地缓存执行计划的能力;
3、对表连接支持较完整,优化器的功能较完整,支持的索引类型很多,复杂查询能力较强;
4、PG主表采用堆表存放,MySQL采用索引组织表,能够支持比MySQL更大的数据量。
5、PG的主备复制属于物理复制,相对于MySQL基于binlog的逻辑复制,数据的一致性更加可靠,复制性能更高,对主机性能的影响也更小。
6、MySQL的存储引擎插件化机制,存在锁机制复杂影响并发的问题,而PG不存在。
二、MySQL相对于PG的优势:
1、innodb的基于回滚段实现的MVCC机制,相对PG新老数据一起存放的基于XID的MVCC机制,是占优的。因此MySQL的速度是高于PG的;
2、MySQL采用索引组织表,这种存储方式非常适合基于主键匹配的查询、删改操作,但是对表结构设计存在约束;
3、MySQL的优化器较简单,系统表、运算符、数据类型的实现都很精简,非常适合简单的查询操作;
4、MySQL分区表的实现要优于PG的基于继承表的分区实现,主要体现在分区个数达到上千上万后的处理性能差异较大。
总结:
PG具备更高的可靠性,对数据一致性完整性的支持高于MySQL,因此PG更加适合严格的企业应用场景(比如金融、电信、ERP、CRM);而MySQL查询速度较快,更加适合业务逻辑相对简单、数据可靠性要求较低的互联网场景(比如google、facebook、alibaba)。
8.redis的5种数据类型
没太答上,就知道列表、集合、有序集合了
来自《redis实战》↓
STRING(字符串)、LIST(列表)、SET(集合)、HASH(散列)、ZSET(有序集合)
9.Django orm查询和sql查询的区别(就这些?)
我答:
orm是封装了sql语句,然后用python解析,python解析会慢,不过,用python写起来比较方便。然后原装的sql查询速度较快。
面试官:
你平时不用orm?
我:用sql(其实是orm不熟)
网上:(没太找到好的解答)
文档
如何使用原生sql
Django 允许你用两种方式执行原生 SQL 查询:你可以使用 Manager.raw() 来 执行原生查询并返回模型实例,或者完全不用模型层 直接执行自定义 SQL。
>>> Person.objects.raw('SELECT id, first_name, last_name, birth_date FROM myapp_person')
索引查询¶
raw() 支持索引,所以,若你只需要第一个结果就这样写:
>>> first_person = Person.objects.raw('SELECT * FROM myapp_person')[0]
直接执行自定义 SQL¶
from django.db import connection
def my_custom_sql(self):
with connection.cursor() as cursor:
cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz])
cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])
row = cursor.fetchone()
return row
https://blog.csdn.net/panjunxiao/article/details/100715354
ORM(对象—关系映射)
为什么orm慢:http://xiaorui.cc/archives/2048
django orm model的介绍,这django模型不简单呀,他的返回值是querysets类型。 也就是说,他会把orm执行的结果,转换成queryset结构 。 就因为这样被封装,所以我们每次用orm感觉特别友好的原因。
SQL注入是什么,如何避免SQL注入?
抄自:http://c.biancheng.net/view/8283.html
SQL 注入(SQL Injection)是发生在 Web 程序中数据库层的安全漏洞,是网站存在最多也是最简单的漏洞。主要原因是程序对用户输入数据的合法性没有判断和处理,导致攻击者可以在 Web 应用程序中事先定义好的 SQL 语句中添加额外的 SQL 语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步获取到数据信息。
SQL 注入的原理主要有以下 4 点:
1)恶意拼接查询
2)利用注释执行非法命令。
3)传入非法参数
4)添加额外条件
避免SQL注入
1. 过滤输入内容,校验字符串
2. 参数化查询
3. 安全测试、安全审计
下面是在开发过程中可以避免 SQL 注入的一些方法。
1. 避免使用动态SQL
2. 不要将敏感数据保留在纯文本中
3. 限制数据库权限和特权
4. 避免直接向用户显示数据库错误
10.orm中q查询的作用:
我:
就是那种查询的时候,某一个字段,判断大于或小于,范围的那种把,条件判断
面试官:
复杂的判断查询
Django官网
如果你要执行更复杂的查询(例如,由 OR 语句连接的查询),你可以使用 Q 对象。
如:
LIKE
Q(question__startswith='What')
"OR" 关系:
Q(question__startswith='Who') | Q(question__startswith='What')
Q 对象也可通过 ~ 操作符反转,允许在组合查询中组合普通查询或反向 (NOT) 查询:
Q(question__startswith='Who') | ~Q(pub_date__year=2005)
每个接受关键字参数的查询函数 (例如 filter(), exclude(), get()) 也同时接受一个或多个 Q 对象作为位置(未命名的)参数。若你为查询函数提供了多个 Q 对象参数,这些参数会通过 "AND" 连接。例子:
Poll.objects.get(
Q(question__startswith='Who'),
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)
= SELECT * from polls WHERE question LIKE 'Who%' AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
F查询
使用 F() 对象来生成一个 SQL 表达式,在数据库层面描述所需的操作。
python写法
reporter = Reporters.objects.get(name='Tintin')
reporter.stories_filed += 1
reporter.save()
F后,作用于数据库
from django.db.models import F
reporter = Reporters.objects.get(name='Tintin')
reporter.stories_filed = F('stories_filed') + 1
reporter.save()
让数据库,而不是 Python 来完成工作
减少某些操作所需的查询次数
避免了竞争条件:如果两个 Python 线程执行上面第一个例子中的代码,一个线程可以在另一个线程从数据库中获取一个字段的值后,检索、递增并保存它。第二个线程保存的值将基于原始值,第一个线程的工作将丢失。
11.Django以及restframework这种平时遇到的组件
admin/model/form/view/url/templates/settings
就这些把
差不多
12.flask是mvc框架吗
我答:flask不知道,django是。
面试官:嗯,flask是典型的mvc框架。django是基于mvc框架改进的MVT框架。
13.Django模板有什么数据类型
我答:不知道有什么数据类型,就写个基本的html模板,然后其他的html extend引用他的,然后写各个块。
面试官:嗯,Django模板有数据类型,这样的是比较常用的抽象数据类型。
网上:没找到答案啊。是不是他说错了。
14.怎么减少数据访问次数、访问时间?(见问题5)
我答:
1.优化查询语句:比如select count(1) 比count(*)快很多。
2.有一个懒惰的框架组件,调用时使用
3.加索引
4.把要查询的数据,先处理到中间表中,直接调用
网上:
有一个懒惰的框架组件。orm
QuerySet 是惰性的¶
QuerySet 是惰性的 —— 创建 QuerySet 并不会引发任何数据库活动。你可以将一整天的过滤器都堆积在一起,Django 只会在 QuerySet 被 计算 时执行查询操作。
>>> q = Entry.objects.filter(headline__startswith="What")
>>> q = q.filter(pub_date__lte=datetime.date.today())
>>> q = q.exclude(body_text__icontains="food")
>>> print(q)
虽然这看起来像是三次数据库操作,实际上只在最后一行 (print(q)) 做了一次。一般来说, QuerySet 的结果直到你 “要使用” 时才会从数据库中拿出。当你要用时,才通过数据库 计算 出 QuerySet。
15.用过docker部署么?项目不考虑性能么?
没有,正在学习docker中;
项目是直接部署在服务器上,因为面对的用户几十个,不像面对个人成千上万那种系统,更注重的是安全与稳定。
下次应该做到,实际项目中没有,自学过,部署过自己的项目,加油
16.解释下socket
我:就是一种用来传输数据的,然后基于udp/tcp实现
面试官:嗯,基于tcp、ip
我:不是udp、tcp么?
面试官:只是两种类型
我:好像还有多线程的socket
面试官:你说长连接么?
我:不是
网上: https://www.cnblogs.com/dolphinx/p/3460545.html
socket
我们知道两个进程如果需要进行通讯最基本的一个前提能能够唯一的标示一个进程,在本地进程通讯中我们可以使用PID来唯一标示一个进程,但PID只在本地唯一,网络中的两个进程PID冲突几率很大,这时候我们需要另辟它径了,我们知道IP层的ip地址可以唯一标示主机,而TCP层协议和端口号可以唯一标示主机的一个进程,这样我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程。
能够唯一标示网络中的进程后,它们就可以利用socket进行通信了,什么是socket呢?我们经常把socket翻译为套接字,socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。
socket通信流程
socket是"打开—读/写—关闭"模式的实现
服务器根据地址类型(ipv4,ipv6)、socket类型、协议创建socket
服务器为socket绑定ip地址和端口号
服务器socket监听端口号请求,随时准备接收客户端发来的连接,这时候服务器的socket并没有被打开
客户端创建socket
客户端打开socket,根据服务器ip地址和端口号试图连接服务器socket
服务器socket接收到客户端socket请求,被动打开,开始接收客户端请求,直到客户端返回连接信息。这时候socket进入阻塞状态,所谓阻塞即accept()方法一直到客户端返回连接信息后才返回,开始接收下一个客户端谅解请求
客户端连接成功,向服务器发送连接状态信息
服务器accept方法返回,连接成功
客户端向socket写入信息
服务器读取信息
客户端关闭
服务器端关闭
17.django可以使用redis来做什么,django的默认缓存
我:用来计数
面试官:还有呢?
我:处理中间结果?忘了。
面试官:django的默认缓存是啥 ?
我:memcache?忘了。
好像是cache?
网上:
抄自:https://blog.csdn.net/tianzongnihao/article/details/54924924
做缓存。做消息队列。通常在一个电商类型的数据处理过程之中,有关商品,热销,推荐排序的队列。
优点:
1.性能极高-100K+ 每秒的读写频率。
2.丰富的数据类型
3.原子 – Redis的所有操作都是原子性的
4.丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
5.持久化:对数据的更新采用Copy-on-write技术,可以异步地保存到磁盘上,主要有两种策略,一是根据时间,更新次数的快照(save 300 10 )二是AOF:append-only file,只追加文件,在Redis执行命令时,将执行的写命令复制到硬盘里面。(memcache一断电就没了)
缺点:
1.受限于物理内存,无法做海量数据的高性能读写。场景受限于较小数据量的高性能操作和运算上。
这个也很好:https://blog.csdn.net/tianzongnihao/article/details/54924924
抄自:https://docs.djangoproject.com/zh-hans/3.2/topics/cache/
动态网站的一个基本取舍是,它们是动态的。每当用户请求一个页面时,网络服务器都会进行各种计算 —— 从数据库查询到模板渲染再到业务逻辑 —— 以创建访客看到的页面。从处理花费的角度来看,这比标准的从文件系统中读取文件的服务器安排要昂贵得多。
Memcached¶
Memcached 是一个完全基于内存的缓存服务器,是 Django 原生支持的最快、最高效的缓存类型,最初被开发出来用于处理 LiveJournal.com 的高负载,随后由 Danga Interactive 开源。Facebook 和 Wikipedia 等网站使用它来减少数据库访问并显著提高网站性能。
18.有没有用过联合索引,创建3个联合索引有几种类型
我:没有
面试官:没有?怎么会没有?
我:什么事联合索引?
面试官:就是你查1个字段需要给字段加索引,然后一般都是查多个字段把,就比如查3个就都加上索引。
面试官:创建3个联合索引有几种类型?
我:1种把,我猜的。
面试官:不对,有三种。
我:怎么会有三种,那不就是三个单一索引,怎么叫联合索引?
19.有没有用过第三方接口、微信支付什么的
支付调用接口:(快看看)https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_0.shtml
20.python list、dict查询时哪个快
网上:
https://www.cnblogs.com/nxf-rabbit75/p/10006563.html
查找效率:set>dict>list
list | set | dict |
---|---|---|
O(n) | set做了去重,本质应该一颗红黑树(猜测,STL就是红黑树),复杂度O(logn); | dict类似对key进行了hash,然后再对hash生成一个红黑树进行查找,其查找复杂其实是O(logn),并不是所谓的O(1)。O(1)只是理想的实现,实际上很多hash的实现是进行了离散化的。dict比set多了一步hash的过程,so 它比set慢,不过差别不大。 |
那么为什么dict.keys()查询速度比另外dict,set慢很多呢?这就要对比list、dict、set三种的数据结构了。
[1]dict.keys()实际上是list(keys),是dict的所有key组成的list。查找一个元素是否在list中是以list的下标为索引遍历list.
[2]而查询是否在dict中,是将key以hash值的形式直接找到key对应的索引,根据索引可直接访问value。对量大的dict查询,自然是后者快很多。
[3]而set和dict的存储原理基本是一样的,唯一不同的是,set没有value,只有key。对查询key是否在dict或sset内,效果基本上是一样的。
由此,可以得出,如果存储的数据会被反复查询,且量大,那么,尽量不要用list,尽量用dict,如果元素不重复,用set更好。查询是否在dict内,也不要再用dict.keys()了。
关于dcit有几点需要特别注意:
dict的key或者set的值 都必须是可以hash的不可变对象都是可hash的,str,fronzenset,tuple,自己实现的类 hash
dict的内存花销大,但是查询速度快, 自定义的对象 或者python内部的对象都是用dict包装的
dict的存储顺序和元素添加顺序有关
添加数据有可能改变已有数据的顺序
21.pandas的数据类型,两种?
网上找:
https://www.pypandas.cn/docs/getting_started/dsintro.html#dataframe
Series
Series (opens new window)是带标签的一维数组,可存储整数、浮点数、字符串、Python 对象等类型的数据。轴标签统称为索引。调用 pd.Series 函数即可创建 Series:
>>> s = pd.Series(data, index=index)
DataFrame
DataFrame 是由多种类型的列构成的二维标签数据结构,类似于 Excel 、SQL 表,或 Series 对象构成的字典。DataFrame 是最常用的 Pandas 对象,与 Series 一样,DataFrame 支持多种类型的输入数据:
一维 ndarray、列表、字典、Series 字典
二维 numpy.ndarray
结构多维数组或记录多维数组(opens new window)
Series
DataFrame
技术一点没准备就去了,果然不行,感觉差的厉害,感觉得再学上一周,然后来和面试官交流,才好无阻。还是要技术的。
还有,怎么在面试官的角度识别我这种简历还可以,但水平不行的人。问那种用过全部框架才知道的功能,不是只是简单用了hello world。
地*线简单面试题
1.List, tuple, set, dict 是否有序, 可修改, 可重复
List 有序,可修改,可重复
tuple 有序,可修改里面的元素本身,可重复
set 无序,可修改,不可重复
dict 无序,可修改值,值可重复
2.给定一个字符串, 统计每个字母出现的次数, 例如"hello world", o出现了2次, l出现了3次
def count_str_rate(get_strs):
'''统计每个字母出现的次数'''
count_dict = {}
for get_str in get_strs:
num = 1
if get_str != ' ':
if count_dict.get(get_str) == None:
count_dict[get_str] = get_strs.count(get_str)
return count_dict
print(count_str_rate('hello world'))
3.写一个排序算法
def quicksort(list1):
'''递归用法的快排'''
left = []
right = []
if len(list1) <= 1:
return list1
quick = list1.pop()
for i in list1:
if i >= quick:
right.append(i)
else:
left.append(i)
return quicksort(left) + [quick] + quicksort(right)
quicksorted = quicksort([2, 4, 5, 7, 3, 11, 27, 12, 8, 9])
print(quicksorted)
4.简述装饰器
一个参数为函数的调用对象,函数执行前走装饰器函数做处理
5.什么是lambda函数?它有什么好处?
接受多个参数,返回表达式值的简写版函数; 比较简便,可用来过滤数据
6.Python里面如何实现tuple和list的转换?
将对应的list用tuple包一下、tuple包一下list
7.简述浅拷贝, 深拷贝
深拷贝和浅拷贝都拷贝了对象的数据,并开辟了一个新的内存空间,不同的是深拷贝给对象的可变数据也开辟了一片内存空间
8.简述python如何捕捉异常
try except 某个异常类型
9.给定一个整数, 输出各个位相加之和, 例如"120"就是1+2+0=3, "15"就是1+5=6'
def two_num_add(get_mum):
'''统计各个位相加之和'''
sum = 0
for i in str(get_mum):
sum += int(i)
return sum
print(two_num_add(120))