面试题锦集
1、讲讲你之前的工作经历,之前在公司负责什么?
了解 桌面的自我介绍文档
2、微信接口access_token怎么获取?
access_token简称token,是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。微信公众平台是运营者通过公众号为微信用户提供资讯和服务的平台,而公众平台开发接口则是提供服务的基础,开发者在公众平台网站中创建公众号、获取接口权限后,才可以进行业务开发.开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效.
一共三个参数.
参数1:grant_type是获取token的网址(https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET)
参数2:,appid是用户凭证(也就是刚刚appiD账号)
参数3:.secret是密码(也就是刚刚得到的appsecret密钥)
把账号密码填入网址中,如下示例:
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wx19b9959eaa9aceee&secret=93aa673f043bdfdcef7504f7cf571cd0
3、Django的orm的get方法会报哪两种错误?
get 只有一条记录返回的时候才正常,也就说明get的查询字段必须是主键或者唯一约束的字段。
第一种:
MultipleObjectsReturned异常,返回多条记录
第二种:
DoesNotExist异常,没有找到记录
4、Django的orm的filter出来的对象是什么类型以及ORM优化?
queryset集合
优化:
1.能用values的尽量不查询对象,然后对象.属性的操作
2.select_related 主动连表,针对一对一或者外键
3.perfetch_related 子查询 ,针对一对一或者外键或者多对多
4.only只查询指定字段数据 defer排除某些字段
5、flask的orm用的是哪个第三方库?
flask_sqlalchemy 弗拉斯克-涩口奥克米
Flask 是一个使用 Python 编写的轻量级 Web 应用框架,使用 BSD 授权。其 WSGI 工具箱采用 Werkzeug,模板引擎则使用 Jinja2。除了 Werkzeug 和 Jinja2 以外几乎不依赖任何外部库。因为 Flask 被称为轻量级框架。
Flask 的会话会话使用签名 cookie 来允许用户查看和修改会话内容。它会记录从一个请求到另一个请求的信息。但如果要修改会话,则必须有密钥 Flask.secret_key。
6、celery怎么应用在Django?
Celery是一个功能完备即插即用的异步任务队列系统。它适用于异步处理问题,当发送邮件、或者文件上传, 图像处理等等一些比较耗时的操作,我们可将其异步执行,这样用户不需要等待很久,提高用户体验。
Celery的特点是:
- 简单,易于使用和维护,有丰富的文档。
- 高效,单个celery进程每分钟可以处理数百万个任务。
- 灵活,celery中几乎每个部分都可以自定义扩展。
Celery的架构由三部分组成,消息队列(message broker),任务执行单元(worker)和任务执行结果存储(task result store)组成。
celery通过消息进行通信,通常使用一个叫Broker(中间人)来协助client(任务的发出者)和worker(任务的处理者). clients发出消息到队列中,broker将队列中的信息派发给worker来处理。
使用:
第一步:创建一个Celery实例,一般称之为celery应用
第二步:配置好main.py主文件和config.py配置文件
第三步:创建任务存放的目录,创建任务文件
第四步:与Django配合使用,在main.py主程序中对django的配置文件进行加载
第五步:就可以调用Celery来执行异步任务了
7、熟悉哪些数据库?
数据库分为关系型数据库和非关系型数据库
我所熟悉的关系型数据库:mysql、SQLserver、sqlite
我所熟悉的非关系型数据库:redis、MongoDB
8、docker怎么部署?
1.下载安装docker
2.编写dockerfile编写部署程序的脚本,大概流程是
-下载镜像
-环境部署操作,如安装python解释器,yum源配置,代码文件拷贝,启动程序等
3.编译dockerfile,生成镜像,启动容器,注意数据卷映射,端口映射
4.使用多个容器的话,考虑用容器编排,容器间通信
9、Nginx怎么部署?
vue+nginx+uwsgi+django+mysql+redis
主要是利用nginx的静态网站功能,展示vue页面
然后利用反向代理、负载均衡功能,请求分发给后端服务器
整个的过程都是修改nginx.conf来配置
优点:
轻量级
在应对高并发情况时,能保持低资源低消耗高性能
高度模块化的设计,配置简洁
官方测试nginx能够支撑5万并发量,并且cpu、内存等资源消耗却非常低,运行非常稳定has
10、Django项目部署之后怎么起动的?
看题意回答的话,大概是
1.编写好uwsgi.ini配置文件,配置如多进程,内存管理等参数,用于启动django
2.编写好supervisor配置文件,用于启动uwsgi,启动后台程序
3.启动nginx,配置好反向代理,请求发给uwsgi
4.访问nginx的入口,访问整个项目
11、简述一次完整的http请求流程
1、TCP建立连接
2、浏览器发送请求命令
3、浏览器发送请求头消息
4、服务器应答
5、服务器回应头信息
6、服务器发送数据
7、断开TCP连接
12、简述python的内存管理和垃圾回收机制
python采用的是引用计数机制为主,标记清除和分代收集(隔代回收)两种机制为辅的策略。
简单来说python的内存管理机制有三种
1)引用计数
2)垃圾回收
3)内存池
1,引用计数:
引用计数是一种非常高效的内存管理手段,当一个python对象被引用时其引用计数增加1,当其不再被引用时引用计数减1,当引用计数等于0的时候,对象就被删除了。
2,垃圾回收:
① 引用计数
② 标记清除
③ 分代回收
标记清除用来解决循环引用产生的问题,循环引用只有在容器对象才会产生,比如字典,元祖,列表等。首先为了追踪对象,需要每个容器对象维护两个额外的指针,用来将容器对象组成一个链表,指针分别指向前后两个容器对象,这样可以将对象的循环引用摘除,就可以得出两个对象的有效计数。
分代回收思想将对象分为三代(generation 0,1,2)
0代表幼年对象,
1代表青年对象,
2代表老年对象。
根据弱代假说(越年轻的对象越容易死掉,老的对象通常会存活更久。)
新生的对象被放入0代,如果该对象在第0代的一次gc垃圾回收中活了下来,那么它就被放到第1代里面(它就升级了)。如果第1代里面的对象在第1代的一次gc垃圾回收中活了下来,它就被放到第2代里面。
3,内存池:
Python的内存机制呈现金字塔形状,-1,-2层主要有操作系统进行操作
第0层是C中的malloc,free等内存分配和释放函数进行操作
第1层和第2层是内存池,有python接口函数,PyMem_Malloc函数实现,当对象小于256k的时由该层直接分配内存
第3层是最上层,也就是我们对python对象的直接操作
Python在运行期间会大量地执行malloc和free的操作,频繁地在用户态和核心态之间进行切换,这将严重影响Python的执行效率。为了加速Python的执行效 率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。
13、请写一个简单的装饰器
def wapper(func):
def inner(*args, **kwargs):
print("被装饰前")
func(*args, **kwargs)
print("被装饰后")
return inner
@wapper
def f():
print('this is a app')
f()
14.写一个冒泡排序,他的时间复杂度是多少?时间复杂度的定义是什么?
# 将乱序序列中的最大值找出,逐一移动到序列最后的位置
alist = [3, 8, 5, 7, 6]
def sort(alist):
# 找最大值的方式是通过对列表中的元素进行两两比较,值大的元素逐步向后移动
# 序列中有n个元素,两两比较的话,需要比较n-1次
for i in range(len(alist) - 1): # 循环n-1次,控制两两比较的次数
if alist[i] > alist[i + 1]: # 如果前面的元素大于后面的元素,交换两个元素的位置
alist[i], alist[i + 1] = alist[i + 1], alist[i]
else: # 如果后面的元素大于前面的元素,则不作任何操作
pass
return alist
print(sort(alist))
他的时间复杂度是:n + 1 + 1
定义:时间复杂度是度量算法执行的时间长短.
常见的时间复杂度高低排序:O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n2logn)<O(n3)
15.使用递归的方式实现斐波那契数列
def func(num):
"""
:param nums: int
:return:
"""
if num == 1 or num == 2:
return 1
return func(num - 1) + func(num - 2)
print(func(3))
16.写出SQL语句从数据库中随机取50条
mysql操作
从所有数据中随机取一条数据进行展示,需要使用rand()函数
select * from 表名 order by rand() limit 50;
Oracle操作,random()函数
SELECT * FROM (SELECT * FROM T_USER ORDER BY DBMS_RANDOM.RANDOM()) WHERE RONUM <= 50;
17.简述django rest framework框架的认证流程
前端发送请求-->Django的wsgi-->中间件-->路由系统_执行CBV的as_view(),就是执行内部的dispath方法-->在执行dispath之前,有版本分析 和 渲染器-->在dispath内,对request封装-->版本-->认证-->权限-->限流-->视图-->如果视图用到缓存( request.data or request.query_params )就用到了 解析器-->视图处理数据,用到了序列化(对数据进行序列化或验证) -->视图返回数据可以用到分页
17.1Django生命周期
前端发送请求-->Django的wsgi-->中间件-->路由系统-->视图-->ORM数据库操作-->模板-->返回数据给用户
18、Redis打的RDB和AOF持久化
RDB:快照方式,允许你每隔一段时间对内存数据做一次快照然后存储到硬盘中。该方式是Redis默认的持久化方式。
AOF:通过将发送到服务器的写操作命令记录下来,形成AOF文件,文件默认名称是appendonly.aof,可以通过appendfilename来指定文件名称
RDB快照过程:
1、Redis使用fork函数复制一份当前的父进程作为子进程
2、父进程继续处理用户的请求,子进程开始把内存中的数据持久化到磁盘上
3、当子进程把内存中的数据写入到临时文件完成之后,会把该临时文件替换掉旧的RDB文件。
AOF同步过程:
1、Redis 执行 fork() ,现在同时拥有父进程和子进程。
2、子进程开始将新 AOF 文件的内容写入到临时文件。
3、对于所有新执行的写入命令,父进程一边将它们累积到一个内存缓存中,一边将这些改动追加到现有 AOF 文件的末尾: 这样即使在重写的中途发生停机,现有的 AOF 文件也还是安全的。
4、当子进程完成重写工作时,它给父进程发送一个信号,父进程在接收到信号之后,将内存缓存中的所有数据追加到新 AOF 文件的末尾。
5、现在 Redis 原子地用新文件替换旧文件,之后所有命令都会直接追加到新 AOF 文件的末尾。
19.POP与OOP编程模式
POP与OOP编程模式对比
面向过程:(procedure oriented programming 即:POP)
代表:python
特点:
1.注重步骤与过程,不注重责任分工
2.如果需求复杂,代码会变得复杂
3.开发复杂项目,没有固定的套路,开发难度大.
面向对象:(object oriented programming 即:OOP)
面向对象是一种编程范式,满足面向对象编程的语言,一般会提供类、封装、继承等语法和概念来辅助我们进行面向对象编程。所谓的面向对象就是将我们的程序模块化,对象化,把具体事物的特性属性和通过这些属性来实现一些动作的具体方法放到一个类里面。
特点:
1.注重 对象和职责,不同的对象承担不同的职责
2.更适合因对复杂的需求变化,是专门应对复杂项目开发,提供的固定套路
3.需要在面向过程基础上,再学习一些面向对象的语法
20.python最大的递归层数
一般在1000左右,window10测试998,Mac测试997
可以通过sys.setrecursionlimit()进行设置,但是一般默认不会超过3925-3929这个范围
21、协程的意义
充分的利用线程,不让线程出现阻塞从而浪费硬件资源,同时耗费最少的时间去完成任务
22、MongoDB数据库
MongoDB是一个跨平台,面向文档的数据库,提供高性能,高可用性和易于扩展。MongoDB是工作在集合和文档上一种概念。
Mac开启MongoDB的指令:
sudo mongod --dbpath /usr/local/mongodb/data/db
23、asyncio和FastAPI框架
https://www.cnblogs.com/suguangti/p/12992098.html
参考pycharm的面试题
24、Rest特点
1.具象的:一般指表现层,表现得对象就是资源,例如客户端访问服务器的时候,获取的就是资源,比如文字,图片,音频等。
2.表现:资源的表现形式,txt形式,html形式,json形式,jpg形式,浏览器通过url确定资源的位置,但是http请求头中,用Accept和Content-Type来指定字段,这两个字段是对资源表现得描述。
3.状态转换:客户端和服务器的交互过程,在这个过程中,一定会有数据和状态的转化,这种转化叫做状态转化,其中GET表示获取资源,PUT更新资源,POST新建,DELETE表示删除资源,HTTP协议中最常见的四种协议。
-RESTful架构:
-每个url代表一种资源
-客户端和服务器之间,传递这种资源的某种表现层
-客户端通过四个常见的http动词,对服务器资源进行操作
4.重要特征: 统一接口,同一个资源,对外暴露的URL一致
无状态 可缓存 C/S模式 分层系统
5.状态码:1xx:相关信息
2xx:操作成功
3xx:重定向
4xx:客户端错误
5xx:服务器错误
25、进程的缺点
1.创建进程的代价非常大:操作系统要自己的每一个进程分配资源,并且对进程总数有一定限制。
2.进程间通讯成本很高
3.切换开销大:上下文切换的时候需要保存栈,cpu寄存器。
4.耗内存
26、理解一下python中的 多进程 多线程 协程:
-进程:
-一个运行的程序就是一个进程,没有运行的代码叫做程序,进程是系统资源分配的最小单位,进程拥有自己独立的内存空间,所以进程间的数据不共享,开销很大。
-线程:
-调度执行的最小单位,也叫做执行路径,不能独立存在,依赖进程存在一个进程至少还有一个线程,叫做主线程,而且多个线程共享内存(数据共享,共享全局变量),从而极大的提高了程序的运行效率
-协程
- 是一种用户态的轻量级线程,协程的调度完全由用户来控制,协程有自己的寄存器上下文和栈,协程调用切换时,将寄存上下文和栈保存在其他地方,在切回的时候,恢复之前保存的上下文和栈,直接操作栈则没有内核切换的开销,可以不加锁的访问全局变量,所以上下文切换非常快。
27、线程不安全
- 线程是非独立的,同一个进程里面的多个线程的数据是共享的,当各个线程访问数据资源的时候会产生竞争状态,数据几乎同步的被多个线程占用,造成数据混乱的问题,这就是所谓的线程不安全。
28、解决线程不安全:锁
好处:确保了关键代码(共享数据资源)只能由一个线程从头到尾的完成执行操作,解决了多线程资源竞争下的原子性操作问题
坏处:阻止了多线程的并发执行,包括锁的某段代码实际上只能单个线程执行,效率就大大降低了
29、锁的致命问题:死锁
若干个子线程在系统资源竞争的时候,都在等待这对方对某部分资源解除占用状态,结果就是谁都不愿意先解锁,互相干等,程序无法继续执行下去,这就是死锁。
30、GIL锁 全局解释器锁
作用:限制多线程的同时进行,保证同一时间只有一个线程进行执行,所以cpython中的多线程其实是伪多线程
所以在python中常常使用协程技术来代替多线程,协程是一种轻量级的线程,进程和线程的切换是由系统决定,而协程是由程序员自己决定,而模块gevent下切换是遇到了耗时任务才会切换。
31、docker
docker中的image镜像文件,更像是一个环境包,可以随意的移动到其他docker平台中使用
container更像是镜像文件的实例化,可以针对这个包进行N个实例
docker images--命令是用来查看所有的Docker image
docker ps -a 用来查看所有正在运行或者停止的container
docker ps -q 用来查看所有的正在运行的的container
32、守护进程、线程
1.对主进程来说,运行完毕指的是主进程代码运行完毕
2.对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕
33、使用elasticsearch搜索引擎实现对数据的全文关键字检索
Mac开启:elasticsearch
开源的 [Elasticsearch ](https://www.elastic.co/)是目前全文搜索引擎的首选。
它可以快速地储存、搜索和分析海量数据。维基百科、Stack Overflow[爆栈]、Github 都采用它。
Elasticsearch 的底层是开源库 [Lucene](https://lucene.apache.org/)。但是,你没法直接用 Lucene,必须自己写代码去调用它的接口。Elastic 是 Lucene 的封装,提供了 REST API 的操作接口,开箱即用。
Elasticsearch 是用Java实现的。所以还需要安装java环境。
第一步:docker安装Elasticsearch和ik分词器
第二步:使用haystack对接Elasticsearch,在django中可以通过使用haystack来调用Elasticsearch搜索引擎。而在drf框架中,也有一个对应的drf-haystack模块,是`django-haystack`进行封装处理的。
第三步:安装drf-haystack、django-haystack、elasticsearch模块
第四步:settings配置应用,配置haystack使用的后端搜索引擎
第五步:创建类索引
第六步:在templates目录中创建text字段使用的模板文件
第七步:手动生成初始索引
第八步:创建序列化器
第九步:创建视图
第十步:定义路由
34、TCP、UDP、HTTP协议的区别
TCP、UDP都是传输层协议,HTTP是基于TCP协议的应用层协议
TCP与UDP基本区别
1.基于连接与无连接
2.TCP要求系统资源较多,UDP较少;
3.UDP程序结构较简单
4.流模式(TCP)与数据报模式(UDP);
5.TCP保证数据正确性,UDP可能丢包
6.TCP保证数据顺序,UDP不保证
https://blog.csdn.net/li_ning_/article/details/52117463
HTTP协议是建立在请求/响应模型上的。首先由客户建立一条与服务器的TCP链接,并发送一个请求到服务器,请求中包含请求方法、URI、协议版本以及相关的MIME样式的消息。服务器响应一个状态行,包含消息的协议版本、一个成功和失败码以及相关的MIME式样的消息。
UDP一般用于多点通信和实时的数据业务,比如QQ、视频
链接:https://www.365jz.com/article/24575
35、装饰器的作用
装饰器: 装饰是在原有的基础上额外添加功能,(语法糖 @run_time )
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
36、驻留机制
驻留机制:节省内存,提高效率
* 小数据池的规则:数字、字符串、布尔值(在终端中可以实现)
* 数字:-5——256
* 字符串:
* 定义和相乘时不能出现中文和特殊符号
* py3.6乘法时总长度不能超过20
* py3.7乘法时总长度不能超过4096
* 代码块的规则:数字、字符串、布尔值(在pycharm中可以实现)
* 定义:一个py文件、一个模块、一个函数、一个类、交互模式即终端下的每一行
* 数字: -5——正无穷
* 字符串:
* 定义时,内容长度不限,内容相同就进行驻留
* 乘法时不能出现中文个特殊符号
* 乘法时总长度不能超过20
37、深浅拷贝
* 赋值:多个变量名指向同一个内存地址
* 浅拷贝:新开辟一个空间即内存地址不同,只拷贝第一层的元素内存地址,可变和不可变的数据都是共用的
* 深拷贝:对于不可变的数据,元素是共用的、对于可变的数据,需要开辟新的空间,不管嵌套多少层
* == :判断的是等号两边的值是否相同
* is :判断的是两边的值的内存地址是否相同
38、B/S和C/S架构
B/S 浏览器服务器模型
C/S 客户端服务器模型
B/S结构和C/S结构的区别:
1、硬件环境不同,C/S通常是建立在专用的网络上,小范围的网络环境。而B/S是建立在广域网上的,适应范围强,通常有操作系统和浏览器就行;
2、C/结构比B/S结构更安全,因为用户群相对固定,对信息的保护更强;
3、B/S结构维护升级比较简单,而C/S结构维护升级相对困难;
39、JWT分为哪三部分?
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
JWT就一段字符串,由三段信息构成的,将这三段信息文本用`.`链接一起就构成了Jwt字符串。
第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).
其原理就是:
第一步:定义一个JSON头部数据,将头部进行base64加密(该加密是可以对称解密的),构成了第一部分.
第二步:定义一个payload载荷,然后将其进行base64加密,得到JWT的第二部分。
第三步:需要base64加密后的header和base64加密后的payload使用`.`连接组成的字符串,然后通过header中声明的加密方式进行加盐`secret`组合加密,然后就构成了jwt的第三部分。
header
jwt的头部承载两部分信息:
- 声明类型,这里是jwt
- 声明加密的算法 通常直接使用 HMAC SHA256
将头部进行base64加密(该加密是可以对称解密的),构成了第一部分.
payload
载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分:
- 标准声明:
-iss:jwt签发者
- sub: jwt所面向的用户
- aud: 接收jwt的一方
- exp: jwt的过期时间,这个过期时间必须要大于签发时间
- nbf: 定义在什么时间之前,该jwt都是不可用的.
- iat: jwt的签发时间
- jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
- 公共声明:公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.
- 私有声明: 私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。
signature
JWT的第三部分是一个签证信息,这个签证信息的主要作用并非防止解密,而是为了防止别人恶意串改,由三部分组成:
- header (base64后的)
- payload (base64后的)
- secret密钥
**注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。**
40、FastDFS分布式文件系统
FastDFS 是用 c 语言编写的一款开源的分布式文件系统。FastDFS 为互联网量身定制, 充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用 FastDFS 很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。
原理:
FastDFS 架构包括 **Tracker server** 和 **Storage server**。客户端请求 Tracker server 文件上传、下载,通过 Tracker server 调度最终由 Storage server 完成文件上传和下载。
**Tracker server** 作用是负载均衡和存储调度,通过 Tracker server 在文件上传时可以根据一些 策略算法找到 Storage server 提供文件上传服务。可以将 tracker 称为**追踪服务器**或**调度服务器**。
**Storage server** 作用是文件存储,客户端上传的文件最终存储在 Storage 服务器上, Storage Serve利用操作系统 的文件系统来管理文件。可以将 storage 称为**存储服务器**。
服务端由两部分组成:
Tracker: 管理集群,tracker 也可以实现集群。每个 tracker 节点地位平等。收集 Storage 集群的状态。
Storage: 实际保存文件, Storage 分为多个组,每个组之间保存的文件是不同的。每 个组内部可以有多个成员,组成员内部保存的内容是一样的,组成员的地位是一致的,没有 主从的概念。
41、Docker与FastDFS配合使用
第一步:获取FastDFS镜像 sudo docker pull season/fastdfs
第二步:创建tracker调度服务器器的运行目录
第三步:创建容器开启tracker服务,默认端口22122
第四步:创建两个目录:存储服务器的运行目录和存储服务器保存文件目录
第五步:开启storage服务,可以通过docker container ls进行查看是否运行
第六步:配置storage.conf文件里面的ip,重新启动,就可以使用了。
与Django配合
第七步:创建FastDFS文件目录,配置好客户端文件,比如调度服务器ip和端口
第八步:配置自定义Django文件存储系统,具体实现呢需要调用`django.core.files.storage.Storage`类和`django.utils.deconstruct.deconstructible`装饰器,配置_open和_save等方法
第九步:配置好settings的文件存储设置
42、python下多线程的限制以及多进程中传递参数的方式
python多线程有个全局解释器锁(global interpreter lock),这个锁的意思是任一时间只能有一个线程使用解释器,跟单cpu跑多个程序一个意思,大家都是轮着用的,这叫“并发”,不是“并行”。
进程间传递参数,主要还是用队列啊,from multiprocessing import Queue来传递信息
多进程间共享数据,可以使用 multiprocessing.Value 和 multiprocessing.Array
43、用python编写一个线程安全的单例模式实现
from threading import Lock
class Single(object):
_instance = None
lock = Lock()
def __new__(cls, *args, **kwargs):
with cls.lock:
if not cls._instance:
cls._instance = object.__new__(cls)
return cls._instance
44、python中__new__
和__init__
的区别
__new__是在创建类对象时触发的方法,用于生成类对象,是python解释器调用的
__init__是在创建类对象之后,用于实例对象属性的方法
单例模式的应用场景:日志logger插入,计时器、权限校验、网站计数器,windows资源管理器,回收站,线程池,数据库连接池等资源池。
45、transaction事务有哪几个特性
事务的特性简称:ACID
所谓事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。(执行单个逻辑功能的一组指令或操作称为事务)
django中使用:
from django.db import transaction
with transaction.atomic()
# 读法:踹塞克神 饿套没课
1. Atomicity原子性
原子性是指事务是一个不可再分割的工作单元,事务中的操作要么都发生,要么都不发生。
2. Consistency一致性
一致性是指在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。这是说数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性。
3. Isolation隔离性
多个事务并发访问时,事务之间是隔离的,一个事务不应该影响其它事务运行效果。
在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。事务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到中间状态的数据。
事务最复杂问题都是由事务隔离性引起的。完全的隔离性是不现实的,完全的隔离性要求数据库同一时间只执行一条事务,这样会严重影响性能。
4. Durability持久性
这是最好理解的一个特性:持久性,意味着在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。(完成的事务是系统永久的部分,对系统的影响是永久性的,该修改即使出现致命的系统故障也将一直保持)
原文链接:https://blog.csdn.net/u012440687/article/details/52116108
46、MySQL的内连接和外连接的区别
内连接(inner join):取出两张表中匹配到的数据,匹配不到的不保留
外连接(outer join):取出连接表中匹配到的数据,匹配不到的也会保留,其值为NULL
47、如何随机打乱列表中元素,要求不引用额外的内存空间?
random 包中的 shuffle() 函数来实现
48、scapy的五大核心组件
scrapy一共有五大核心组件,分别为引擎、下载器、调度器、spider(爬虫文件)、管道。
调度器
用来接受引擎发过来的请求,由过滤器重复的url并将其压入队列中,在引擎再次请求的时候返回,可以想象成一个URL(抓取网页的网址或者说是链接)的优先队列,由他决定下一个要抓取的网址是什么,用户可以根据自己的需求定制调度器
下载器
下载器,是所有组件中负担最大的,它用于高速地下载网络上的资源,Scrapy的下载器代码不会太复杂,但效率高(原因:Scrapy下载器是建立在twisted这个高效的异步模型上的)
爬虫
爬虫是主要干活的,用户最关心的部分, 它可以生成url, 并从特定的url中提取自己需要的信息, 即所谓的实体(Item). 用户也可以从中提取出链接, 让Scrapy继续抓取下一个页面.
实体管道
负责处理爬虫从网页中抽取的实体, 主要的功能是持久化实体、验证实体的有效性、清除不需要的信息. 当页面被爬虫解析后, 将被发送到项目管道, 并经过几个特定的次序处理数据.
引擎
Scrapy引擎是整个框架的核心。它用来控制调试器、下载器、爬虫。实际上,引擎相当于计算机的CPU,它控制着整个流程。对整个系统的数据流进行处理, 触发事务(框架核心).
49.scrapy的步骤详解
1.spider中的url被封装成请求对象交给引擎(每一个对应一个请求对象)
2.引擎拿到请求对象之后,将全部交给调度器
3.调度器闹到所有请求对象后,通过内部的过滤器过滤掉重复的url,最后将去重后的所有url对应的请求对象压入到队列中,随后调度器调度出其中一个请求对象,并将其交给引擎
4.引擎将调度器调度出的请求对象交给下载器
5.下载器拿到该请求对象去互联网中下载数据
6.数据下载成功后会被封装到response中,随后response会被交给下载器
7.下载器将response交给引擎
8.引擎将response交给spiders
9.spiders拿到response后调用回调方法进行数据解析,解析成功后生成item,随后spiders将item交给引擎
10.引擎将item交给管道,管道拿到item后进行数据的持久化存储
50、git合并流程代码
1、进入要合并的分支(如开发分支合并到master,则进入master目录)
git checkout master
git pull
2、查看所有分支是否都pull下来了
git branch -a
3、使用merge合并开发分支
git merge 分支名
4、查看合并之后的状态
git status
5、有冲突的话,通过IDE解决冲突;
6、解决冲突之后,将冲突文件提交暂存区
git add 冲突文件
7、提交merge之后的结果
git commit
如果不是使用git commit -m "备注" ,那么git会自动将合并的结果作为备注,提交本地仓库;
8、本地仓库代码提交远程仓库
git push
50.1、git合并冲突的解决办法
1、git merge冲突了,根据提示找到冲突的文件,解决冲突
如果文件有冲突,那么会有类似的标记
2、修改完之后,执行git add 冲突文件名
3、git commit
注意:没有-m选项
进去类似于vim的操作界面,把conflict相关的行删除掉
4、直接push就可以了,因为刚刚已经执行过相关merge操作了
51、git日常命令
在当前目录新建一个Git代码库
git init
下载一个项目
git clone [url]
显示当前的Git配置
git config --list
设置提交代码时的用户信息
git config [--global] user.name "[name]"
git config [--global] user.email "[email address]"
添加指定目录到的所有文件暂存区
git add .
删除工作区文件,并且将这次删除放入暂存区
git rm [file文件] ...
提交暂存区到仓库区
git commit -m [提交时的名称]
列出所有本地分支
git branch
列出所有远程分支
git branch -r
新建一个分支,但依然停留在当前分支
git branch [分支名]
新建一个分支,并切换到该分支
git checkout -b [分支名]
合并指定分支到当前分支
git merge [分支名]
删除分支
git branch -d [分支名]
显示有变更的文件
git status
显示当前分支的版本历史
git log
提交到远程仓库
git push -v origin [分支名]
52、set集合的集合关系
| 并集
& 交集
- 差集
^ 补集
> 超集
< 子集
53、可变数据类型和不可变数据类型
可变数据类型:当该数据类型的对应变量的值发生了改变,其对应的内存地址不发生改变,这种数据类型就称可变数据类型
不可变数据类型:当该数据类型的对应变量的值发生了改变,其对应的内存地址也发生改变,这种数据就称不可变数据类型
可变数据类型:列表、集合、字典
不可变数据类型:整型、布尔值、字符串、元祖
54、re的()、[]、{}都是什么意思
{} 范围
{m}匹配前一个字符m次,{m,n}匹配前一个字符m至n次,若省略n,则匹配m至无限次
[] 字符集
字符集。对应的位置可以是字符集中任意字符。字符集中的字符可以逐个列出,也可以给出范围,如[abc]或[a-c]。[^abc]表示取反,即非abc。
所有特殊字符在字符集中都失去其原有的特殊含义。用\反斜杠转义恢复特殊字符的特殊含义。
() 分组
被括起来的表达式将作为分组,从表达式左边开始没遇到一个分组的左括号“(”,编号+1.分组表达式作为一个整体,可以后接数量词。表达式中的|仅在该组中有效。
55、classmethod和staticmethod
classmethod类方法,类方法是将类本身作为对象进行操作的方法
staticmethod静态方法,静态方法是类中的函数,不需要实例。静态方法主要是用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系,也就是说在静态方法中,不会涉及到类中的属性和方法的操作。可以理解为,静态方法是个独立的、单纯的函数,它仅仅托管于某个类的名称空间中,便于使用和维护
这两个方法的用法相似,主要区别就在于,classmethod增加了一个对实际调用类的引用,这带来了很多方便的地方:
方法可以判断出自己是通过基类被调用,还是通过某个子类被调用
通过子类调用时,方法可以返回子类的实例而非基类的实例
通过子类调用时,方法可以调用子类的其他classmethod
一般来说classmethod可以完全替代staticmethod,staticmethod唯一的好处是调用时它返回的是一个真正的函数,而且每次调用时返回同一个实例,staticmethod可以在子类上被重写为classmethod
# 应用场景:
classmethod可以设置修改类属性;也可以实例化对象;
staticmethod无法访问类或对象的数据,所以可把它当作一个辅助功能方法用,里面包含一些与该类有关的逻辑代码。比如validate(*args)
56、property特殊方法
1、将一个类的方法定义成属性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的
2、这种特性的使用方式**遵循了统一访问的原则**
属性一般具有三种访问方式,获取、修改、删除
• 我们可以根据这几个属性的访问特点,分别将三个方法定义为对同一个属性的
获取、修改、删除
• 只有在属性定义property后才能定义setter,deleter
57、反射
通过字符串的形式操作对象相关的属性或方法。
主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)
查询hasattr
获取getattr
设置setattr
删除delattr
58、Socket编程-简介
Socket本质是编程接口(API): Socket 是对 TCP/IP 协议的封装,Socket 只是个编程接口不是协议,通过 Socket 我们才能使用 TCP/IP 协议簇(程序员层面)
TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力
最重要的是,Socket是面向客户/服务器模型而设计的,针对客户和服务器程序提供不同的Socket系统调用
套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认
59、同步调用和异步调用
同步调用:确定调用的顺序
提交一个任务,自任务开始运行直到此任务结束,再提交下一个任务
异步调用:不确定顺序
一次提交多个任务,然后就直接执行下一行代码
同步意味着顺序、统一的时间轴:
– 场景1:是指完成事务的逻辑,先执行第一个事务,如果阻塞了,会一直等待,直到这个事务完成,再执行第二个事务,协同步调,按预定的先后次序进行运行
– 场景2:一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列
异步则意味着乱序、效率优先的时间轴:
– 处理调用这个事务的之后,不会等待这个事务的处理结果,直接处理第二个事务去了,通过状态、回调来通知调用者处理结果
– 对于I/O相关的程序来说,异步编程可以大幅度的提高系统的吞吐量,因为在某个I/O操作的读写过程中,系统可以先去处理其它的操作(通常是其它的I/O操作)
异步的实现:
1、无需等待线程执行
2、通过循环控制
3、通过回调机制
60、requests库(UA伪装、ip代理、请求参数)
import requests
# 请求头
headers = {
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'
}
# ip池 proxies读 po rua k sei zi
proxies={'https':'101.236.54.97:8866'}
# 请求参数
params = {
'query':’xiaohaoge‘
}
# 请求路由
url = 'https://www.sogou.com/web'
# get请求
response = requests.get(url=url, proxies=proxies, headers=headers, params=params)
# post请求
data = {
'cname': '',
'pid': '',
'keyword': '北京',
'pageIndex': str(1),
'pageSize': '10'
}
url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'
# data参数是post方法中处理参数动态化的参数
response = requests.post(url=url, headers=headers, data=data)
61、MVC框架、MTV框架和MVVM架构
MVC框架是什么呢:
M:model.py 就是和数据库打交道用的,创建表等操作
V:View 视图(视图函数,html文件)
C:controller 控制器(其实就是我百度云代码里面那个urls文件里面的内容,url(路径)分发与视图函数的逻辑处理)
Django叫做MTV框架
M:model.py 就是和数据库打交道用的,创建表等操作(和上面一样)
T:templates 存放HTML文件的
V:View 视图函数(逻辑处理)
其实你会发现MTV比MVC少一个url分发的部分
MVVM是Model-View-ViewModel的缩写,它是一种基于前端开发的架构模式
Model指代的是vue对象的data属性里面的数据。这里的数据要显示到页面中
View指代的是vue中数据要显示的HTML页面,在vue中,也称之为“视图模板”
ViewModel指的是vue.js中我们编写代码时的vm对象,它是vue.js的核心,负责连接View和Model,保证视图和数据的一致性。
https://www.cnblogs.com/clschao/articles/10391859.html
62、with关键字和自定义类
"""
with 语句实质是上下文管理。
1、上下文管理协议。包含方法__enter__() 和 __exit__(),支持该协议对象要实现这两个方法。
2、上下文管理器,定义执行with语句时要建立的运行时上下文,负责执行with语句块上下文中的进入与退出操作。
3、进入上下文的时候执行__enter__方法,如果设置as var语句,var变量接受__enter__()方法返回值。
4、如果运行时发生了异常,就退出上下文管理器。调用管理器__exit__方法。
"""
自定义类必须包含__enter__和__exit__方法才能正确使用with关键字。
使用场景:
1、文件操作。2、进程线程之间互斥对象。3、支持上下文其他对象
文件操作:
with open()as f:
Django的from django.db import transaction事务:
with transaction.atomic(): #开启事务
aiohttp多链接异步访问:
from aiohttp import ClientSession
async with ClientSession() as session:
async读 i 森 课
aiohttp读 i 由
https://www.jianshu.com/p/34a4f1bbfdf6
63、数据分析三剑客之numpy
NumPy(Numerical Python) 是 Python 语言中做科学计算的基础库。重在于数值计算,也是大部分Python科学计算库的基础,多用于在大型、多维数组上执行的数值运算。
import numpy as np
# 创建多维数组array()
data = np.array([[1,2,3],[4,5,6]])
# 返回元组,表示n行n列
data.shape
# 返回数据数据类型
data.dtype
# 返回是几维数组
data.ndim
# 转换数据类型
a = data.astype(float)
a.dtype
# 数组之间的计算
data + data
# 切片,先沿着行(axis=0)进行索引,再沿着列(axis=1)进行索引
data[:2,:2]
# 数组的逻辑表达处理:
np.where(data>3, 1, 0) # 大于3的标记为1,小于等于3的标记为0
# 沿着行(axis=0)进行索引,平均值
data.mean(axis=0)
# 求出全部元素的方差
data.std()
# 统计数组中元素大于3的个数
(data>3).sum()
# 数组中是否存在一个或多个True
data.any()
# 数组中是否全部数都是True
data.all()
# 沿着行(axis=0)进行索引,进行累加
data.cumsum(0)
# 沿着列(axis=1)进行索引,进行累乘
data.cumprod(1)
# 沿着行进行索引,并进行升序排序
data.sort(0)
# 降序操作
data[::-1]
# 矩阵相乘
np.dot(data, data)
# 矩阵转置
data.T
# 数据的保存
np.save('name', data)
# 数据的读取
np.load('name.npy')
# 变形reshape
data1 = data.reshape((12, )) # 将二维变成一维
data1.reshape((2, -1)) # 将一维变形成二维,-1自动计算
# 级联操作,将多个numpy数组进行横向或纵向的拼接,#维度不一致的数组不可以级联
np.concatenate((data, data), axis=1) # 纵向拼接
64、数据分析三剑客之pandas
numpy能够帮助我们处理的是数值型的数据,当然在数据分析中除了数值型的数据还有好多其他类型的数据(字符串,时间序列),那么pandas就可以帮我们很好的处理除了数值型的其他数据!
pandas的两个常用的类:Series和DataFrame
Series
Series是一种类似与一维数组的对象,由下面两个部分组成:
values:一组数据(ndarray类型)
index:相关的数据索引标签
Series的创建
由列表或numpy数组创建
由字典创建
from pandas import Series
import pandas as pd
import numpy as np
# 实例化Series
# '语文', '数学', '英语'索引是显示索引,不会覆盖原有的隐式索引0,1,2
s = Series(data=[1, 2, 3], index=['语文', '数学', '英语'])
#字典作为数据源
dic = {
'语文':100,
'数学':120,
'英语':120,
}
s = Series(data=dic) #字典的key作为Seres的显示索引
# 索引
s[0]
s['语文']
s.语文 # s.显示索引
s[['语文', '英语']] # 取多值
# 切片
s[0:3]
s['语文': '英语']
Series的常用属性:
s.shape
s.size
s.index
s.values
Series的常用方法:
head()# 查看前几个,默认是5个 tail()# 查看后几个
unique()# 去重 nunique()#返回去重后元素的个数
isnull()# 判断元素是否为空 notnull()# 判断元素是否为非空
add() sub() mul() div()
DataFrame
DataFrame是一个【表格型】的数据结构。DataFrame由按一定顺序排列的多列数据组成。设计初衷是将Series的使用场景从一维拓展到多维。DataFrame既有行索引,也有列索引。
行索引:index
列索引:columns
值:values
DataFrame的创建:
ndarray创建
字典创建
from pandas import DataFrame
df = DataFrame(data=[[1,2,3],[4,5,6]],index=['a','b'],columns=['A','B','C'])
# 字典方式
dic = {
'张三':[150,150,150,150],
'李四':[0,0,0,0]
}
df = DataFrame(data=dic,index=['语文','数学','英语','理综'])
DataFrame的属性:
values、columns、index、shape
65、数据分析三剑客之matplotlib
66、阻塞与非阻塞、同步与异步的概念
阻塞与非阻塞、同步与异步,得从一个分布式系统角度来回答。
1.同步与异步
同步和异步关注的是消息通信机制。所谓同步,就是在发出一个‘调用’时,在没有得到结果之前,该‘调用’就不返回,但是一旦调用返回,就得到返回值。简而言之就是由‘调用者’主动等待这个‘调用’结果。 异步则相反,‘调用’在发出之后,这个调用就直接返回了,所以没有返回结果。即当一个异步过程调用发出后,调用者不会立刻得到结果,而是在‘调用’发出后,‘被调用者’通过状态、通知来通知调用者,或通过回调函数处理这个调用。
2.阻塞与非阻塞
阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态。
阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
67、异步编程asyncio,与FastAPI
https://www.cnblogs.com/wupeiqi/p/12834355.html
68、selenium中的显示等待和隐式等待
Explicit Waits 显示等待
显示等待的代码定义了等待条件,只有该条件触发,才执行后续代码
Implicit Waits 隐式等待
隐式等待实在尝试发现某个元素的时候,如果没能立刻发现,就等待固定长度的时间。默认是0秒,一旦设置了隐式等待时间,他的作用就是Webdriver对象实例的整个生命周期
69、栈溢出
栈溢出是由于C语言系列没有内置检查机制来确保复制到缓冲区的数据不得大于缓冲区的大小,因此当这个数据足够大的时候,将会溢出缓冲区的范围。
在Python中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。
栈溢出就是缓冲区溢出的一种。 由于缓冲区溢出而使得有用的存储单元被改写,往往会引发不可预料的后果。程序在运行过程中,为了临时存取数据的需要,一般都要分配一些内存空间,通常称这些空间为缓冲区。如果向缓冲区中写入超过其本身长度的数据,以致于缓冲区无法容纳,就会造成缓冲区以外的存储单元被改写,这种现象就称为缓冲区溢出。缓冲区长度一般与用户自己定义的缓冲变量的类型有关
100、向面试官提问
1.未来半年内我需要承担的KPI主要是什么?
2.我将要加入的团队的架构是什么?
3.公司内部的培训机制和晋升通道是怎么样的?
4.我的直属上司是什么样的人,有什么背景和经验?
101、未来的事业规划
1-3年:初入职场,主要的工作就是夯实基础,此时基本处于完成上级交付的任务
3-5年:快速成长,作为技术工程师,需要达到一个小leader的层级,即带领一个小团队负责某一个模块或功能的开发。
5-8年:从程序员向架构师转型,现在需要横向发展,了解前端、后端、测试、运维等知识和技能,形成自己的方法论和架构哲学。
10年以上:领导创新阶段,此时达到研发总监或是更高的职位会是一个比较理想的状态