面试题及答案

1. 为什么学习Python?
自身觉得有个一技之长在手,心里踏实,现在了解到人工智能是以后的发展趋势,然后经过网上查询资料,以及自己朋友的推荐,说python在人工智能方面涉及到很多领域,且代码简洁,简单易学,生态圈强大,因此来学python。

3. Python和Java、PHP、C、C#、C++等其他语言的对比?
如果以解释型、编译型来分类的话。python(php)就属于解释型
(c/java/c#属于编译型),同时python也属于弱类型语言。
强类型定义语言:强制数据类型定义的语言。也就是说,一旦一个变量被指定了某个数据类型,如果不经过强制转换,那么它就永远是这个数据类型了。
弱类型定义语言:数据类型可以被忽略的语言。它与强类型定义语言相反, 一个变量可以赋不同数据类型的值。

4. 简述解释型和编译型编程语言?
#1. 编译型(需要编译器,相当于用谷歌翻译):如C,执行速度快,调试麻烦
#2. 解释型(需要解释器,相当于同声传译):如python,执行速度慢,调试方便

解释型语言:专门的解释器对源程序每一行解释成特定平台的机器码并立即执行的语言;
解释型语言不会对整体性的编译和链接处理,解释型语言相当于把编译语言中编译和解释过程混合到了一起同时完成。
优点:跨平台较容易,是以牺牲程序执行效率为代价。 缺点:效率较低,不能脱离解释器独立运行。

编译型的语言: 专门的编译器, 针对特定的平台(操作系统)“翻译”成机器码(包括机器指令和操作数),
并包装成该平台可执行程序的格式;如需要其他的代码,要进行链接。
优点: 可脱离开发环境,特定的平台上独立运行,运行效率较高。缺点:无法移植;需要移植,要源代码重新编译。

5. Python解释器种类以及特点?
CPython

  当从Python官方网站下载并安装好Python2.7后,就直接获得了一个官方版本的解释器:Cpython,这个解释器是用C语言开发的,所以叫CPython,在命名行下运行python,就是启动CPython解释器,CPython是使用最广的Python解释器。

  IPython

  IPython是基于CPython之上的一个交互式解释器,也就是说,IPython只是在交互方式上有所增强,但是执行Python代码的功能和CPython是完全一样的,好比很多国产浏览器虽然外观不同,但内核其实是调用了IE。

  PyPy

  PyPy是另一个Python解释器,它的目标是执行速度,PyPy采用JIT技术,对Python代码进行动态编译,所以可以显著提高Python代码的执行速度。

  Jython

扫描二维码关注公众号,回复: 4010907 查看本文章

  Jython是运行在Java平台上的Python解释器,可以直接把Python代码编译成Java字节码执行。

  IronPython

  IronPython和Jython类似,只不过IronPython是运行在微软.Net平台上的Python解释器,可以直接把Python代码编译成.Net的字节码。

  在Python的解释器中,使用广泛的是CPython,对于Python的编译,除了可以采用以上解释器进行编译外,技术高超的开发者还可以按照自己的需求自行编写Python解释器来执行Python代码,十分的方便!

6. 位和字节的关系?
最小的存储单位称为位(bit):
只能容纳两个值(0或1)之一,不能在一个位中存储更多的信息。位是计算机存储的基本单位。
字节(byte)是常用的计算机存储单位。
字节的标准定义:一个字节均为8位。由于上述所讲每个位或者是0或者是1,所以一个8位的字节包含256种可能的0,1组合
对于一种给定的计算机设计,字(word)是自然的存储单位。

一个英文字符和英文标点占用一个字节,一个中文字符和中文标点占用2个字节

7. b、B、KB、MB、GB 的关系?
1024b = 1B 1024B = 1KB 1024KB = 1MB 1024MB = GB

8. 请⾄少列举5个 PEP8 规范(越多越好)。
缩进。4个空格的缩进(编辑器都可以完成此功能),不使用Tap,更不能混合使用Tap和空格。
每行最大长度79,换行可以使用反斜杠,最好使用圆括号。换行点要在操作符的后边敲回车。
类和top-level函数定义之间空两行;类中的方法定义之间空一行;函数内逻辑无关段落之间空一行;其他地方尽量不要再空行。
各种右括号前不要加空格。
逗号、冒号、分号前不要加空格。
函数的左括号前不要加空格。如Func(1)。
序列的左括号前不要加空格。如list[2]。
操作符左右各加一个空格,不要为了对齐增加空格。
函数默认参数使用的赋值符左右省略空格。
不要将多句语句写在同一行,尽管使用‘;’允许。
if/for/while语句中,即使执行语句只有一句,也必须另起一行。
变量小写,多的话用下划线分割,等号中间不要用空格

9、通过代码实现如下转换:
二进制转换成十进制:v = “11 11 011” print(int('1111011',2))#123
十进制转换成二进制:v = 18 print(bin(18)) #10010
八进制转换成十进制:v = “011” print(int('011',8)) #9
十进制转换成八进制:v = 30 print(oct(30)) #36
十六进制转换成十进制:v = “0x12” print(int('0x12',16)) or print(int('12',16)) #18
十进制转换成十六进制:v = 87 print(hex(87)) #57

10、请编写一个函数实现将IP地址转换成一个整数。

如 10.3.9.12 转换规则为:
00001010
00000011
00001001
00001100
再将以上二进制拼接起来计算十进制结果:00001010 00000011 00001001 00001100 = ?

11、python递归的最大层数?
最大层数998层
12、求结果:
v1 = 1 or 3 #1
v2 = 1 and 3 # 3
v3 = 0 and 2 and 1 # 0 因为0是错误的,一个错误的跟一个正确的做比较,肯定是错误的
v4 = 0 and 2 or 1 #1
v5 = 0 and 2 or 1 or 4 #1
v6 = 0 or Flase and 1 #0
13、ascii、unicode、utf-8、gbk 区别?

编码 大小 支持语言
ASCII 1个字节 英文
Unicode 2个字节(生僻字4个) 所有语言
UTF-8 1-6个字节,英文字母1个字节,汉字3个字节,生僻字4-6个字节 所有语言

ascii用1个字节(8位二进制)代表一个字符
unicode常用2个字节(16位二进制)代表一个字符,生僻字需要用4个字节
GBK是中国标准,只在中国使用,并没有表示大多数其它国家的编码;而各国又陆续推出各自的编码标准,互不兼容,非常不利于全球化发展。于是后来国际组织发行了一个全球统一编码表,把全球各国文字都统一在一个编码标准里,名为Unicode。
unicode----->encode-------->utf-8
utf-8-------->decode---------->unicode
ps:
浏览网页的时候,服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器
如果服务端encode的编码格式是utf-8, 客户端内存中收到的也是utf-8编码的结果。

gbk-->decode-->unicode
GBK编码,一个汉字占两个字节。
GBK包含全部中文字符;UTF-8则包含全世界所有国家需要用到的字符。

python2中的str类型就是python3的bytes类型


14、字节码和机器码的区别?
字节码(Bytecode):是一种包含执行程序、由一序列 op 代码/数据对 组成的二进制文件。字节码是一种中间码,它比机器码更抽象,需要直译器转译后才能成为机器码的中间代码。

机器码:机器码是电脑CPU 直接读取运行的机器指令,运行速度最快,但是非常晦涩难懂,也比较难编写,一般从业人员接触不到。



15、三元运算规则以及应用场景?
规则:为真结果 if 判断条件 else 为假结果(且间隔之间没有冒号)

场景:主要用于简单的if else 判断语句
16. 列举 Python2和Python3的区别?
说这个的时候,最好讲故事,(讲一些之前的经历或者故事,),然后在可以说我记得大概是这样,python2中字符串是字节,源码中bytes=str;python3中字符串数Unicode

py2和py3:
1. 文件操作: xreadlines
--文件操作:xreadlines,这是python2中的,python3中就没有了,python3中返回的是range的一个对象

f = open('x.log','rb')

for line in f.xreadlines():
print(line)

f.close()

2. 字符串:
py2:
str: 字符串 -> 字节
-在python2中字符串其实是字节(字节串------在python2中字符串其实是字节(字节串------>这是python3中的字节) #这个特点一定要说
-unicode=u'xxxxxx'------>这python3中的字符串
py3: #python3中字符串就是Unicode
bytes:
str:

3. 默认解释器编码
py2: ascii;#py2中在py文件顶层需要加上-*-code.....补全# -*- coding: utf-8 -*-
py3: utf-8

5.
py2: range/xrange
py3: range

6.
py2: int / long
py3: int
long整数类型被Python3废弃,统一使用int
xrange函数被Python3废弃,统一使用range,Python3中range的机制也进行修改并提高了大数据集生成效率

7. input/raw_input

8.
py2: yield
py3: yield/yield from

9.
py2: 新式类和经典类
py3: 新式类
在Python 3.x中取消了经典类,默认都是新式类,并且不必显式的继承object,也就是说:
class Person(object):pass
class Person():pass
class Person:pass
三种写法并无区别,推荐第一种
在Python2.x中,默认都是经典类,只有显式继承了object才是新式类,即:
class Person(object):pass 新式类写法
class Person():pass 经典类写法
class Person:pass 经典类写法


python2中print #被视为一个语句
python3中是print() #视为一个函数


17、用一行代码实现数值交换:
a = 1
b = 2
答案:a,b=b,a
18、Python3和Python2中 int 和 long的区别?
python3去除了long类型,现在只有一种整型——int,但它的行为就像python2版本的long
python3 彻底废弃了 long+int 双整数实现的方法, 统一为 int , 支持高精度整数运算.
int() (符号整数):通常被称为是整数或整数,没有小数点的正或负整数。
long() (长整数):或渴望,无限大小的整数,这样写整数和一个大写或小写的L。

19、xrange和range的区别?
python2中:range返回的是一个列表 xrange返回的是一个迭代器
python3中:取消了xrange 用range代替 返回的是一个 range对象
20、文件操作时:xreadlines和readlines的区别?
python2中:xreadlines 则直接返回一个iter(file)迭代器,这个一个个循环
python3中:取消了xreadlines 用readlines代替 返回的是一个list对象(或者说是一个for对象)
21、列举布尔值为False的常见值?
0、 Flase、 负数 、 None 等
22、字符串、列表、元组、字典每个常用的5个方法?
字符串方法:len/index/replace/split/find
列表方法:extend、append、insert、pop、remove
元祖方法:len、max、min、clear、index
字典方法:.get、.update、.pop、.items、.values

23、lambda表达式格式以及应用场景?
# val = (lambda x:x+i for i in range(10))
# print(val,type(val))
python 使用 lambda 表达式来创建匿名函数

24、pass的作用?
pass是空语句,为了保持程序结构的完整性,它不做任何事情,可当占位语句来用

25、*arg和**kwarg作用
*arg和**kwarg 可以帮助我们在调用函数的时候传入多个实参
*arg会把多出来的位置参数转化为tuple
**kwarg会把关键字参数转化为dict

26、is和==的区别
在python中,is检查两个对象是否是同一个对象,而==检查他们是否相等.
简述Python的深浅拷贝以及应用场景?
copy和deepcopy
浅拷贝就是对引用的拷贝(只拷贝父对象,不会拷贝数据中的子对象切片拷贝,)
深拷贝就是对对象的资源的拷贝

浅拷贝与原对象的内层数据地址相同;
深拷贝完全独立开来,与原对象没有任何联系。
Python垃圾回收机制?
Python中的垃圾回收是以引用计数为主,分代收集为辅。引用计数的缺陷是循环引用的问题。
在Python中,如果一个对象的引用数为0,Python虚拟机就会回收这个对象的内存。
Python的可变类型和不可变类型?
数字、字符串、元组是不可变的,
列表、字典是可变的。
求结果:
v = dict.fromkeys(['k1','k2'],[])
v[‘k1’].append(666)
print(v)
v[‘k1’] = 777
print(v)

#{'k1': [666], 'k2': [666]}
#{'k1': 777, 'k2': [666]}
求结果:
def num():
return [lambda x:i*x for i in range(4)]
#这个range4,其实是4个函数,但是0 1 2都没执行,最后只剩下3了,所以每次传进来的参数,执行结果都是2*3=6
print([m(2)for m in num()])
#结果是[6, 6, 6, 6]
列举常见的内置函数?
len()长度
count()计数
str()字符串
int() 数字
filter 过滤 构造一个列表返回所有值为True的元素
instance 判断是否是class的实例
type 返回该object的类型
dir 不带参数时,返回当前范围内的变量、方法和定义的类型列表;
filter、map、reduce的作用?
一行代码实现9*9乘法表
print('\n'.join([' '.join(['%s*%s=%-2s' % (j, i, i * j) for j in range(1, i + 1)]) for i in range(1, 10)]))
如何安装第三方模块?以及用过哪些第三方模块?
pip3 install xxx # 在线安装制定版本
pip install xxx==版本 # 通过whl文件离线安装扩展库
第三方模块:requests,DbUtils,SQLAlchemy等
至少列举8个常用模块都有那些?
- time/random/re/json/pickle/logging/os/sys/hashlib
- requests/beautifulsoup4
re的match和search区别?
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;
re.search匹配整个字符串,直到找到一个匹配。
什么是正则的贪婪匹配?
在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配
eg:
string pattern1 = @"a.*c"; // greedy match
Regex regex = new Regex(pattern1);
regex.Match("abcabc"); // return "abcabc"
求结果:
a. [ i % 2 for i in range(10) ] #[0, 1, 0, 1, 0, 1, 0, 1, 0, 1] 为列表生成式
b. ( i % 2 for i in range(10) ) #<generator object <genexpr> at 0x00000000005DB780> 为生成式
求结果:
a. 1 or 2 #1 整个式子 不断去向右查看,直到能确定为真就停下来
b. 1 and 2 #2 整个式子 不断去向右查看,直到能确定为真就停下来
c. 1 < (2==2) #False 因为布尔值是一种特殊的int,所示1<ture,因此是F
d. 1 < 2 == 2 #True
def func(a,b=[]) 这种写法有什么坑?
这里b=[]参数有坑,eg:第一次传个字符串,能正常使用;第二次若传个列表,那么会覆盖第一次传的字符串。
如何实现 “1,2,3” 变成 [‘1’,’2’,’3’] ?
v = “1,2,3”

print(list(v.split(',')))
如何实现[‘1’,’2’,’3’]变成[1,2,3] ?
[int(x) for x in ['1','2','3']]
比较: a = [1,2,3] 和 b = [(1),(2),(3) ] 以及 b = [(1,),(2,),(3,) ] 的区别?
首先它们都是一个列表 只是列表元素种类不同 a和b的元素都是int类型 c的元素是元祖
如何用一行代码生成[1,4,9,16,25,36,49,64,81,100] ?
a=[i*i for i in range(1,11)]
print(a)
一行代码实现删除列表中重复的值 ?
如何在函数中设置一个全局变量 ?
logging模块的作用?以及应用场景?

通过log的分析,可以方便用户了解系统或软件、应用的运行情况;如果你的应用log足够丰富,也可以分析以往用户的操作行为、类型喜好、地域分布或其他更多信息;如果一个应用的log同时也分了多个级别,那么可以很轻易地分析得到该应用的健康状况,及时发现问题并快速定位、解决问题,补救损失。

应用场景,数据库每操作一次,生成一条日志记录。
请用代码简答实现stack 。
常用字符串格式化哪几种?
字符串格式化有两种方式:百分号方式、format方式。

格式:%[(name)][flags][width].[precision]typecode

i1 = "i am {},age {} ,{}".format('cairui',18,'kk')
print(i1)
i am cairui,age 18 ,kk
简述 生成器、迭代器、可迭代对象 以及应用场景?
生成器是什么?在哪里用过?
一个函数内部存在yield关键字;v = 函数()。那么函数名()的到的结果就是生成器,并且不会执行函数内部代码
本质:就是一个迭代器
应用场景:
- range/xrange
- py2: range(100000000),立即创建;xrange(100000000)生成器;
- py3: range(100000000)生成器;
- stark组件
xx.html:
{% for item in data %}
<p>{{item.k1}} {{item.name}}</p>
{%endfor%}
views.py
def index(request):
data = [
{'k1':1,'name':'alex'},
{'k1':2,'name':'老男孩'},
{'k1':3,'name':'小男孩'},
]

new_data = []
for item in data:
item['email'] = "[email protected]"
new_data.append(item)

return render(request,'xx.html',{'data':new_data})

迭代器是什么?在哪里用过?
迭代器即迭代的工具,那什么是迭代呢?
迭代是一个重复的过程,每次重复即一次迭代,并且每次迭代的结果都是下一次迭代的初始值,内部内部实现__next__方法,帮助我们向后一个一个取值。

什么叫迭代?:一个一个取值,就像for循环一样取值。
迭代器协议:内部实现了__iter__,__next__方法

-什么是可迭代对象?
- 可迭代对象,一个类内部实现__iter__方法且返回一个迭代器。即obj.__iter__

class Foo(object):
def __iter__(self):
return iter([11,22,33])
obj = Foo()

应用场景:
- wtforms中对form对象进行循环时候,显示form中包含的所有字段。
class LoginForm(Form):
name = simple.StringField(
label='用户名',
validators=[
validators.DataRequired(message='用户名不能为空.'),
validators.Length(min=6, max=18, message='用户名长度必须大于%(min)d且小于%(max)d')
],
widget=widgets.TextInput(),
render_kw={'class': 'form-control'}
)
pwd = simple.PasswordField(
label='密码',
validators=[
validators.DataRequired(message='密码不能为空.'),
validators.Length(min=8, message='用户名长度必须大于%(min)d'),
validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,}",
message='密码至少8个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符')

],
widget=widgets.PasswordInput(),
render_kw={'class': 'form-control'}
)


form = LoginForm()
for item in form:
print(item)

- 列表、字典、元组

总结:如果想要让一个对象可以被for循环,那么就需要在当前类中定义__iter__
用Python实现一个二分查找的函数。
https://www.cnblogs.com/wgDream/p/7533605.html
百度查询下什么是二分查找
谈谈你对闭包的理解?
闭包函数,其实就是一个装饰器,是内部函数包含对外部作用域中变量的引用
闭包:
1.闭 :内部的函数
   2.包 :包含了对外部函数作用域中变量的引用
# 闭包的常用形式:
def hei():
  x=20
  def inner():
    '''闭包函数'''
    print(x)
return inner()
判断闭包函数的方法:__closure__
#输出的__closure__有cell元素 :是闭包函数
def func():
name = 'eva'
def inner():
print(name)
print(inner.__closure__)
return inner

f = func()
f()


#输出的__closure__为None :不是闭包函数
name = 'egon'
def func2():
def inner():
print(name)
print(inner.__closure__)
return inner

f2 = func2()
f2()
os和sys模块的作用?
总结:
就是,os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口;
sys模块负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境。
--os模块是与操作系统交互的一个接口,这个模块提供了一种方便的使用操作系统函数的方法。
'''
os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd
os.curdir 返回当前目录: ('.')
os.pardir 获取当前目录的父目录字符串名:('..')
os.makedirs('dirname1/dirname2') 可生成多层递归目录
os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove() 删除一个文件
os.rename("oldname","newname") 重命名文件/目录
os.stat('path/filename') 获取文件/目录信息
os.sep 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
os.linesep 输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
os.pathsep 输出用于分割文件路径的字符串 win下为;,Linux下为:
os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
os.system("bash command") 运行shell命令,直接显示
os.environ 获取系统环境变量
os.path.abspath(path) 返回path规范化的绝对路径
os.path.split(path) 将path分割成目录和文件名二元组返回
os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素
os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path) 如果path是绝对路径,返回True
os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime(path) 返回path所指向的文件或者目录的最后访问时间
os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间
os.path.getsize(path) 返回path的大小
'''
--sys这个模块可供访问由解释器使用或维护的变量和与解释器进行交互的函数。
sys.argv 命令行参数List,第一个元素是程序本身路径
sys.exit(n) 退出程序,正常退出时exit(0)
sys.version 获取Python解释程序的版本信息
sys.maxint 最大的Int值
sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform 返回操作系统平台名称
如何生成一个随机数?
import random
a = random.randint(1,100)
print(a)
print(random.random()) # 用于生成一个0到1的随机符点数: 0 <= n < 1.0
print(random.randint(1,10)) # 用于生成一个指定范围内的整数
print(random.randrange(1,10)) # 用于生成一个指定范围内的整数
如何使用python删除一个文件?
import os
file = r'F:\test.txt'
if os.path.exists(file):
os.remove(file)
print('delete success')
else:
print('no such file:%s' % file)
谈谈你对面向对象的理解?

面向对象:
从三大特性说起:继承、封装、多态

封装:
起始就是将很多数据封装到一个对象中,类似于把很多东西放到一个箱子中,
如:一个函数如果好多参数,起始就可以把参数封装到一个对象再传递。

在哪里用过:
- django rest framework中的request对象。
- flask中:请求上下文对象中ctx_context/app_context对象
继承:
如果多个类中都有共同的方法,那么为了避免反复编写,就可以将方法提取到基类中实现,
让所有派生类去继承即可。

在哪里用过?
- 视图
- 版本、认证、分页
多态:
python本身就是多态的,崇尚鸭子模型,只要会呱呱叫的就是鸭子。
def func(arg):
arg.send()
Python面向对象中的继承有什么特点?
面向对象继承中的一些特点:
1:在继承中基类的构造(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。有别于C#
2:在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数
3:总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。
(先在本类中查找调用的方法,找不到才去基类中找)。

ps:什么是派生
派生就是子类在继承父类的基础上衍生出新的属性。子类中独有的,父类中没有的;或子类定义与父类重名的东西。子类也叫派生类。
面向对象深度优先和广度优先是什么?
Python的类可以继承多个类,Python的类如果继承了多个类,那么其寻找方法的方式有两种
当类是经典类时,多继承情况下,会按照深度优先方式查找
当类是新式类时,多继承情况下,会按照广度优先方式查找
简单点说就是:经典类是纵向查找,新式类是横向查找
典类和新式类的区别就是,在声明类的时候,新式类需要加上object关键字。在python3中默认全是新式类
面向对象中super的作用?
调用父类中的方法

在python中,每个类都有一个mro的类方法。 mro方法返回的是类的继承顺序的列表 并且所继承的类只出现一次
这也是super在父类中查找成员的顺序, 这解决了多继承的问题。
super在继承体系中向上的查找过程,变成了在mro中向右的线性查找过程,任何类都只会被处理一次。
通过这个方法,python解决了多继承中的2大难题:
1. 查找顺序问题。
2. 钻石继承的多次初始化问题。事实上任何类都只会在mro list中出现一次。这就确保了super向上调用的过程中,
任何祖先类的方法都只会被执行一次。
是否使用过functools中的函数?其作用是什么?
@functools.wraps() 用于修复装饰器对原函数名的更改

import functools #导入模块

def wapper(func):
@functools.wraps(func) #函数被装饰器装饰后会改变函数的函数名 此方法可以保留原函数名(将原函数的原信息重新赋值给函数)
def inner(*args,**kwargs):
return func(*args,**kwargs)
return inner
"""
1. 执行wapper函数,并将被装饰的函数当做参数。 wapper(index)
2. 将第一步的返回值,重新赋值给 新index = wapper(老index)
"""
@wapper
def index(a1):
return a1 + 1000

@wapper
def order(a1):
return a1 + 1000
列举面向对象中带双下划线的特殊方法,如:__new__、__init__
_iter__ 循环对象是,自定义__iter__
        wtforms中BaseForm中循环所有字段时定义了__iter__
__call__、__dir__、__eq__等__xx__方法
在flask的上下文管理中,LocalProxy里面用到过,顺便说一句上下文管理还挺有意思的。
__call__ 对象名(),触发执行。
__new__ 类名()会执行__new__ 然后在执行__init__ 方法
__init__ 类名()执行__init__ 方法
__doc__ 返回类的描述信息(注释)
__class__ 表示当前操作的对象的类是什么
__del__ 析构方法,当对象在内存中被释放时,自动触发执行。
__dict__ 以字典的形式返回类的所有属性
__str__ 改变对象的字符串显示
如何判断是函数还是方法?

函数和方法的区别?
from types import MethodType(方法),FunctionType(函数)
def func():
pass
print(isinstance(func,FunctionType)) # True


class A():
def aaa(self):
pass
print(isinstance(aaa,FunctionType)) # True
a=A()
print(isinstance(a.aaa,MethodType)) # True要有实例化出来的对象才可以,如果只是用类名去调用的话还是function,只有用实例化出来的对象去调用才可以得到method

我们的函数只有跟我们的实例化出来的对象有绑定关系才能称之为方法,否则都是函数,即便它是写到类里面的方法,没有跟我们的类实例化出来的对象进行绑定,它依然是函数,而不是类里面的方法.
静态方法和类方法区别?
尽管 classmethod 和 staticmethod 非常相似,但在用法上依然有一些明显的区别。
classmethod 必须有一个指向类对象的引用作为第一个参数,而 staticmethod 可以没有任何参数。
列举面向对象中的特殊成员以及应用场景
在flask的上下文管理中,LocalProxy里面用到过
__call__ 对象名(),触发执行。

__new__ 类名()会执行__new__ 然后在执行__init__ 方法

__init__ 类名()执行__init__ 方法

__doc__ 返回类的描述信息(注释)

__class__ 表示当前操作的对象的类是什么

__del__ 析构方法,当对象在内存中被释放时,自动触发执行。

__dict__ 以字典的形式返回类的所有属性

__str__ 改变对象的字符串显示
1、2、3、4、5 能组成多少个互不相同且无重复的三位数
60个
import itertools
print(len(list(itertools.permutations('12345', 3)))) # 60

题意理解:组成后的数值不相同,且组合的三个位数之间数字不重复。
使用python内置的排列组合函数(不放回抽样排列)
product 笛卡尔积  (有放回抽样排列)
permutations 排列  (不放回抽样排列)
combinations 组合,没有重复  (不放回抽样组合)
combinations_with_replacement 组合,有重复  (有放回抽样组合)
什么是反射?以及应用场景?
python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
反射的核心本质就是以字符串的形式去导入个模块,利用字符串的形式去执行函数。
Django中的 CBV就是基于反射实现的。
metaclass作用?以及应用场景?
metaclass用来指定类是由谁创建的。 可以在创建类的前后做一些定制操作
类的metaclass 默认是type。我们也可以指定类的metaclass值。在python3中:
class MyType(type):
def __init__(self,*args,**kwargs):
print('创建类之前')
super(MyType,self).__init__(*args,**kwargs)
print('创建类之后')
class Foo(object,metaclass=MyType): # 当前类,由type类创建。
CITY = "bj"
def func(self, x):
return x + 1
用尽量多的方法实现单例模式。 什么是单例模式????
# 1. 基于__new__方法
class Singleton:
_INSTANCE = None

def __new__(cls, *args, **kwargs):
if not cls._INSTANCE:
cls._INSTANCE = super().__new__(cls, *args, **kwargs)
return cls._INSTANCE

# a = Singleton()
# b = Singleton()
# print(a is b)

# 2. 基于装饰器
def singleton(cls):
_instance = None
def inner(*args, **kwargs):
nonlocal _instance
if not _instance:
_instance = cls(*args, **kwargs)
return _instance
return inner


@singleton
class Foo:
x = 5


a = Foo()
b = Foo()
print(a is b)
print(type(a), type(b))
装饰器的写法以及应用场景。
什么是装饰器?
装饰器,是一个函数,能作为对象被调用,能作为返回值被返回,能做闭包函数;
在不修改被装饰对象源代码以及调用方式的前提下为其添加新功能;
请手写装饰器?
import functools

def wapper(func):
@functools.wraps(func)
def inner(*args,**kwargs):
return func(*args,**kwargs)
return inner

问题:装饰器都在哪里用过?或者说应用场景在哪里?
   - 应用:
   - flask:路由、before_request
   - django: csrf、缓存、用户登录
异常处理写法以及如何主动跑出异常(应用场景)
try:

try块的语句...

except exceptiontype1 as var:#使用as语句获得本次捕获到的异常的实例var

   except块语句...

raise主动抛出一个异常
什么是面向对象的mro
类的mro方法 会返回一个列表 里面是按顺序排列的类所继承的所有的父类 且不会重复
isinstance作用以及应用场景?
isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()。
isinstance() 与 type() 区别:
type() 不会认为子类是一种父类类型,不考虑继承关系。
isinstance() 会认为子类是一种父类类型,考虑继承关系。
如果要判断两个类型是否相同推荐使用 isinstance()。

isinstance用得少。只有在用某些面向对象的生产模式的时候才会用到。通常是判断类的继承关系。
>>> class a:
... v1=1
>>> class b:
... v2=2
>>> class c(a):
... v1=3
>>> x=c()
>>> isinstance(x,a)
True
>>> isinstance(x,c)
True
>>> isinstance(x,b)
False
写代码并实现: 参考博客# https://blog.csdn.net/qq_28119401/article/details/52972461
Given an array of integers, return indices of the two numbers such that they add up to a specific target.You may assume that each input would
have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1]
json序列化时,可以处理的数据类型有哪些?如何定制支持datetime类型?
1、数字(整型、浮点数、定点数);
2、字符和字符串;
3、布尔类型。
还有其他数据类型:
一、对象;
二、null;
三、数组。
注意,复合数据类型对象的数据结构可以被解构为原始数据类型。
datetime类型:
import json
from json import JSONEncoder
from datetime import datetime
class ComplexEncoder(JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.strftime('%Y-%m-%d %H:%M:%S')
else:
return super(ComplexEncoder,self).default(obj)
d = { 'name':'alex','data':datetime.now()}
print(d)
print(json.dumps(d,cls=ComplexEncoder))
json序列化时,默认遇到中文会转换成unicode,如果想要保留中文怎么办?
json.dumps(json.loads(result),ensure_ascii=False) #ensure_ascii=False用这个
什么是断言?应用场景?
断言是面向对象中的,as
python assert断言是声明其布尔值必须为真的判定,如果发生异常就说明表达示为假
比如我想测试 a==1。就可以用断言。如果我的猜想错误就会抛出异常,可以用于测试一段表达式是否成立。

a = 1
assert a == 1
assert a == 2
应用场景:
from rest_framework.generics import GenericAPIView 这里面有assert,如果不是queryset= 类型,则报错
有用过with statement吗?它的好处是什么?
要使用 with 语句,首先要明白上下文管理器这一概念。有了上下文管理器,with 语句才能工作。
下面是一组与上下文管理器和with 语句有关的概念。with 语句支持运行时上下文这一概念。
上下文管理器(Context Manager):支持上下文管理协议的对象,这种对象实现了
__enter__() 和 __exit__() 方法。 __enter__() 和__exit__() 方法负责执行 with 语句块上下文中的进入与退出操作。
语句体(with-body):with 语句包裹起来的代码块,在执行语句体之前会调用上下文管
理器的 __enter__() 方法,执行完语句体之后会执行 __exit__() 方法。 当我们操作文件结束时 它能帮我们自动关闭文件。
使用代码实现查看列举目录下的所有文件。
import os
for filename in os.listdir(r'c:\windows'):
print(filename)
简述 yield和yield from关键字。

函数中使用yield,可以使函数变成生成器。一个函数如果是生成一个数组,就必须把数据存储在内存中,
如果使用生成器,则在调用的时候才生成数据,可以节省内存。
为了让生成器(带yield函数),能简易的在其他函数中直接调用,就产生了yield from。
yield from 可以直接调用生成器(带yield函数)。

第二部分 网络编程和并发(34题)
简述osi七层协议
应用层 #桌面上所见的应用(.exe文件),以及能看到的应用程序
-表示层
-会话层#OSI是理论模型,其他协议里一般抽象成一个应用层,由程序的开发者控制。
传输层 #可靠性传输,校验,纠错,重传,重排序等。
网络层 # IP协议和路由协议。IP包的组包,解包和发送。
数据链路层 # arp协议;有一定的纠错,如重传可以解决短时间的链路质量波动。单还是要靠TCP保证传输可靠性。
物理层 # 把数据转化成高低电平传送出去
什么是C/S和B/S架构?
client和server端
Broswer端(网页端)与server端
简述三次握手、四次挥手的流程
建立连接需要三次握手:
三次握手,客户端先发给服务端说我要跟你建立连接,可以吗?;然后服务端发给客户端,我也要和你建立连接可以吗?;客户端再发给服务端说可以,这就表示建立连接成功
断开连接需要四次挥手:
客户端告诉服务端,要准备断开连接,服务端第一次告诉客户端,说同意断开连接;第二次再告诉客户端要进行断开连接了。然后客户端再发给服务端表示也断开连接了。
什么是arp协议?
ARP是英文Address Resolution Protocol的简称,中文名叫做:地址解析协议,是一个位于TCP/IP协议栈中的底层协议,对应于数据链路层,负责将某个IP地址解析成对应的MAC地址。

ARP协议的基本功能就是通过目标设备的IP地址,查询目标设备的MAC地址,以保证通信的进行。从IP地址到物理地址的映射有两种方式:表格方式和非表格方式。ARP具体说来就是将网络层(IP层,也就是相当于OSI的第三层)地址解析为数据链路层(MAC层,也就是相当于OSI的第二层)的MAC地址。

对于普通用户来说,以上的解释可能很难理解,下面用通俗易懂的语音为大家说明一下。我们的电脑、手机等设备要上互联网需要一块网卡,这个网卡有一个物理地址,又叫做MAC地址,MAC地址具有全球唯一性;同时我们上网的时候还需要一个IP地址。ARP的作用就是把IP地址和MAC地址对应起来,建立一张对应的表格,根据ARP映射表,就可以根据IP地址找到目标设备,实现通信。
TCP和UDP的区别?
PS:什么是TCP和UDP?
TCP和UDP是OSI模型中的运输层中的协议。TCP提供可靠的通信传输,而UDP则常被用于让广播和细节控制交给应用的通信传输。
TCP协议操作:
服务器端: 客户端
创建套接字 创建套接字
绑定ip和端口 绑定ip和端口
监听 连接服务器
accept等待连接 通信(收recv,发send)
通信(收recv,发send)

面向连接:
通信之前先要三次握手
断开之前先要四次挥手
安全、可靠、面向连接(不会丢包)

UDP:传输速度快
不面向连接,不能保证数据的完整性

服务器端: 客户端:
创建套接字 绑定套接字
绑定ip和端口 通信(收recvfrom,发sendto)
通信(收recvfrom,发sendto)
什么是局域网和广域网?
局域网和广域网是按规模大小而划分的两种计算机网络。范围在几千米以内的计算机网络统称为局域网;而连接的范围超过10千米的,则称为广域网,因特网(Intenet)就是目前最大的广域网。
为何基于TCP协议的通信比基于udp的协议通信更可靠?
TCP协议操作:
面向连接:
通信之前先要三次握手
断开之前先要四次挥手
安全、可靠、面向连接(不会丢包)

UDP:传输速度快
不面向连接,不能保证数据的完整性
什么是socket?简述基于tcp协议的套接字通信流程。
Socket是连接运行在网络上的两个程序间的双向通讯的端点。
服务器端程序将一个套接字绑定到一个特定的端口,并通过此套接字等待和监听客户的连接请求。
客户端程序根据服务器程序所在的主机名和端口号发出连接请求。
什么是粘包? socket 中造成粘包的原因是什么? 哪些情况会发生粘包现象?
粘包问题的本质就是数据读取边界错误所致。
原因:所谓粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的。
两种情况下会发生粘包。

发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包)
IO多路复用的作用?
IO多路复用的作用?
目标:用于监听多个socket对象是否发生变化。
- select,内部循环检测socket是否发生变化;1024个socket
- poll,内部循环检测socket是否发生变化;
- epoll,回调的方式

代码实例:

import select

while True:
# 让select模块帮助我们去检测sk1/sk2两个socket对象是否已经发生“变化”
# r=[]
# 如果r中有值
# r=[sk1,] 表示:sk1这个socket已经获取到响应的内容
# r=[sk1,sk2] 表示:sk1,sk2两个socket已经获取到响应的内容
# w=[],如果w中有值
# w=[sk1,], 表示:sk1这个socket已经连接成功;
# w=[sk1,sk2],表示:sk1/sk2两个socket已经连接成功;

r,w,e = select.select([sk1,sk2],[sk1,sk2],[],0.5)

for client in w:
content = "GET /wupeiqi HTTP/1.1\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36\r\n\r\n"
client.sendall(content.encode('utf-8'))

for cli in r:
response = cli.recv(8096)
print(response)
cli.close()
什么是防火墙以及作用?

防火墙它是一种位于内部网络与外部网络之间的网络安全系统。一项信息安全的防护系统,依照特定的规则,允许或是限制传输的数据通过。 它可通过监测、限制、更改跨越防火墙的数据流,尽可能地对外部屏蔽网络内部的信息、结构和运行状况, 以此来实现网络的安全保护。
作用:
它可通过监测、限制、更改跨越防火墙的数据流,尽可能地对外部屏蔽网络内部的信息、结构和运行状况, 以此来实现网络的安全保护。
select、poll、epoll 模型的区别?
- select,内部循环检测socket是否发生变化;1024个socket
- poll,内部循环检测socket是否发生变化;
- epoll,回调的方式
简述 进程、线程、协程的区别 以及应用场景?
进程:
正在执行的一个程序或者一个任务,而执行任务的是cpu。
每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,相比线程数据相对比较稳定安全。

进程:
是一种状态,运行过程中的才叫进程
进程:
是最小的资源管理单元


切换:
是程序的保存
切换的操作者:操作系统
##########
线程:
线程是进程的一个实体,是CPU调度和分派的基本单位
  线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。
--线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程中的最小单元,由线程ID、程序计数器、寄存器集合和堆栈共同组成。 线程是最小的执行单位
--线程开销要远远小于进程开销。

线程:最小的执行单位

------>
进程和线程两者关系:
线程一定要在进程里面的
(1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
(2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。
(3)CPU分给线程,即真正在CPU上运行的是线程。
------>

进程/线程切换的原则:
1、时间片 就是切换时候所需的时间,有时候觉得很短,我们察觉不到,其实也是有的
2、遇到IO操作切换 io阻塞,是等待期间,不占cpu,io就类似炒菜期间,没有盐了,就需要去买盐一样。
3、优先级切换,一定要按照优先级来执行(类似手机来电话似得,在玩游戏时候,来电话了也会有显示)
##########


原理:
1. 什么是协程?
- 是“微线程”,不存在;是由程序员人为创造出来并控制程序:先执行某段代码、再跳到某处执行某段代码。

- 如果遇到非IO请求来回切换:性能更低。
- 如果遇到IO(耗时)请求来回切换:性能高、实现并发(本质上利用IO等待的过程,再去干一些其他的事)


  优点:
    1. 协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级
    2. 单线程内就可以实现并发的效果,最大限度地利用cpu
  缺点:
    1、遇到非IO请求来回切换:性能更低。
    2、无法利用多核

1、进程与线程比较
  1) 地址空间:线程是进程内的一个执行单元,进程内至少有一个线程,它们共享进程的地址空间,而进程有自己独立的地址空间
  2) 资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
  3) 线程是处理器调度的基本单位,但进程不是
  4) 二者均可并发执行
  5) 每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
2、协程与线程进行比较
  1) 一个线程可以多个协程,一个进程也可以单独拥有多个协程,这样python中则能使用多核CPU。
  2) 线程进程都是同步机制,而协程则是异步
  3) 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态
GIL锁是什么鬼?
GIL互斥锁,将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全。
简单说,就是锁住其他进程,只能运行一个进程
Python中如何使用线程池和进程池?
进程池
就是在一个进程内控制一定个数的线程,
进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。

进程池中有两个方法:

apply
apply_async

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from multiprocessing import Process,Pool
import time

def Foo(i):
time.sleep(2)
return i+100

def Bar(arg):
print arg

pool = Pool(5)
#print pool.apply(Foo,(1,))
#print pool.apply_async(func =Foo, args=(1,)).get()

for i in range(10):
pool.apply_async(func=Foo, args=(i,),callback=Bar)

print 'end'
pool.close()
pool.join()#进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。
threading.local的作用?

为线程之间创建相互隔离的存储
或者说:为每个线程开辟一块空间进行数据存储。
进程之间如何进行通信?
1. 管道pipe:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
2. 命名管道FIFO:有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
4. 消息队列MessageQueue:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
5. 共享存储SharedMemory:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
6. 信号量Semaphore:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
7. 套接字Socket:套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。
8. 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
什么是并发和并行?
并发和并行从宏观上来讲都是同时处理多路请求的概念。
但并发和并行又有区别,并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔内发生。
19进程锁和线程锁的作用?
线程锁是锁线程的,锁住禁用,如果4线程的CPU锁一个线程剩余三个(如果可以锁的话),就像四车道封锁一条车道还剩3个车道可以跑车;
进程锁是锁进程的,进程就是正在运行的程序,锁住进程就是锁住程序禁止程序的任何操作,就像锁住汽车不能开车一样。

说了这么多,再补充一点,线程锁,进程锁,分布式锁的作用都是一样的,只是作用的范围大小不同。范围大小:分布式锁>进程锁>线程锁。能用线程锁,进程锁情况下使用分布式锁也是可以的,能用线程锁的情况下使用进程锁也是可以的。只是范围越大技术复杂度就越大。
解释什么是异步非阻塞?
什么是异步非阻塞?
- 非阻塞
- 不等待(报错,捕捉异常)
- 代码:
sk = socket.socket()
sk.setblocking(False)
- 异步:
- 回调,当达到某个指定的状态之后,自动调用特定函数。

示例:nb_async.py 实现异步非阻塞的模块。

自定义异步非阻塞模块
路由器和交换机的区别? #http://www.cnblogs.com/hanfei-1005/p/5685938.html
 --路由器可以给你的局域网自动分配IP,虚拟拨号,就像一个交通警察,指挥着你的电脑该往哪走,你自己不用操心那么多了。交换机只是用来分配网络数据的。
 路由器在网络层,路由器根据IP地址寻址,路由器可以处理TCP/IP协议,交换机不可以。

交换机在中继层,交换机根据MAC地址寻址。

--路由器可以把一个IP分配给很多个主机使用,这些主机对外只表现出一个IP。
交换机可以把很多主机连起来,这些主机对外各有各的IP。
--路由器提供防火墙的服务,交换机不能提供该功能。集线器、交换机都是做端口扩展的,就是扩大局域网(通常都是以太网)的接入点,也就是能让局域网可以连进来更多的电脑。 路由器是用来做网间连接,也就是用来连接不同的网络。
什么是域名解析?
域名解析是把域名指向网站空间IP,让人们通过注册的域名可以方便地访问到网站的一种服务。I
如何修改本地hosts文件?
Hosts是一个没有扩展名的系统文件,可以用记事本等工具打开,其作用就是将一些常用的网址域名与其对应的IP地址建立一个关联“数据库”,
当用户在浏览器中输入一个需要登录的网址时,系统会首先自动从Hosts文件中寻找对应的IP地址,一旦找到,系统会立即打开对应网页,
如果没有找到,则系统会再将网址提交DNS域名解析服务器进行IP地址的解析。
浏览器访问网站,要首先通过DNS服务器把要访问的网站域名解析成一个唯一的IP地址,之后,浏览器才能对此网站进行定位并且访问其数据。
操作系统规定,在进行DNS请求以前,先检查系自己的Hosts文件中是否有这个域名和IP的映射关系。如果有,则直接访问这个IP地址指定的网络位置,
如果没有,再向已知的DNS服务器提出域名解析请求。也就是说Hosts的IP解析优先级比DNS要高。
修改方式:ip 域名 127.0.0.1 www.163.com
生产者消费者模型应用场景及优势?
生产者------>缓冲区------>消费者
有流程图我们可以知道,生产者不关心数据什么时候被处理,消费者不关心数据什么时候产生,实现了解耦,也解决了阻塞。
还有一个比较典型的例子便是日志的记录,多线程产生日志,但写日志由于文件独占,不能多线程来写,于是我们就可以把线程压入队列,由日志线程来读取队列数据,完成写日志的操作。

为什么要使用生产者和消费者模式
在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,
如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,
才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。
为了解决这个问题于是引入了生产者和消费者模式。
什么是生产者消费者模式
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,
而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,
消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。
在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。
什么是cdn?
CDN的全称是Content Delivery Network,即内容分发网络。其目的是通过在现有的Internet中增加一层新的网络架构,
将网站的内容发布到最接近用户的网络"边缘",使用户可以就近取得所需的内容,解决Internet网络拥挤的状况,提高用户访问网站的响应速度。
从技术上全面解决由于网络带宽小、用户访问量大、网点分布不均等原因所造成的用户访问网站响应速度慢的问题。
LVS是什么及作用?
LVS 是 Linux Virtual Server ,Linux 虚拟服务器;是一个虚拟的服务器集群【多台机器 LB IP】是一个虚拟的四层交换器集群系统,
根据目标地址和目标端口实现用户请求转发,本身不产生流量,只做用户请求转发,目前是负载均衡性能最好的集群系统。

LVS主 要用于多服务器的负载均衡。它工作在网络层,可以实现高性能,高可用的服务器集群技术。它廉价,可把许多低性能的服务器组合在一起形成一个超级服务器。它 易用,配置非常简单,且有多种负载均衡的方法。它稳定可靠,即使在集群的服务器中某台服务器无法正常工作,也不影响整体效果。另外可扩展性也非常好。
Nginx是什么及作用?
--静态HTTP服务器
首先,Nginx是一个HTTP服务器,可以将服务器上的静态文件(如HTML、图片)通过HTTP协议展现给客户端。
--反向代理服务器
客户端本来可以直接通过HTTP协议访问某网站应用服务器,网站管理员可以在中间加上一个Nginx,客户端请求Nginx,Nginx请求应用服务器,然后将结果返回给客户端,此时Nginx就是反向代理服务器。
--负载均衡 当网站访问量非常大,网站站长开心赚钱的同时,也摊上事儿了。因为网站越来越慢,一台服务器已经不够用了。于是将同一个应用部署在多台服务器上,将大量用户的请求分配给多台机器处理。同时带来的好处是,其中一台服务器万一挂了,只要还有其他服务器正常运行,就不会影响用户使用。

Nginx可以通过反向代理来实现负载均衡。
keepalived是什么及作用? #https://blog.csdn.net/cooling88/article/details/52504854
keepalived是基于VRRP协议实现的保证集群高可用的一个服务软件,主要功能是实现真机的故障隔离和负载均衡器间的失败切换,防止单点故障。
haproxy是什么以及作用?#https://blog.csdn.net/qq_26562641/article/details/52511690
haproxy是一款功能强大、灵活好用反向代理软件,提供了高可用、负载均衡、后端服务器代理的功能,它在7层负载均衡方面的功能很强大(支持cookie track, header rewrite等等),支持双机热备,支持虚拟主机,拥有非常不错的服务器健康检查功能,当其代理的后端服务器出现故障, HAProxy会自动将该服务器摘除,故障恢复后再自动将该服务器加入;同时还提供直观的监控页面,可以清晰实时的监控服务集群的运行状况。
什么是负载均衡? 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。
什么是rpc及应用场景?
RPC 的主要功能目标是让构建分布式计算(应用)更容易,在提供强大的远程调用能力时不损失本地调用的语义简洁性。为实现该目标,RPC 框架需提供一种透明调用机制让使用者不必显式的区分本地调用和远程调用,在前文《浅出篇》中给出了一种实现结构,基于 stub 的结构来实现。下面我们将具体细化 stub 结构的实现。
简述 asynio模块的作用和应用场景。
实现高并发的一个模块

异步网络操作
并发
协程
当然到目前为止实现协程的不仅仅只有asyncio,tornado和gevent都实现了类似功能
简述 gevent模块的作用和应用场景。
gevent是python的一个并发框架,以微线程greenlet为核心,使用了epoll事件监听机制以及诸多其他优化而变得高效.而且其中有个monkey类,

将现有基于Python线程直接转化为greenlet(类似于打patch)
1.游戏服务器,基本是gevent ,tornado,twisted三选一,如游戏服务器框架gfirefly2.爬虫,gevent的pool是个大杀器3.使用gevent加速web应用,如flask搭配gevent,还可以实现长连接(ajax方式),websocketgevent一般高并发用的比较多,goagent也使用了gevent,openstack使用了eventlet,这是gevent的胞弟
twisted框架的使用和应用?
http://www.cnblogs.com/zhiyong-ITNote/p/7360442.html

第三部分 数据库和缓存(46题)
列举常见的关系型数据库和非关系型都有那些?
什么是关系型数据库?
关系型数据库是依据关系模型来创建的数据库。
所谓关系模型就是“一对一、一对多、多对多”等关系模型,关系模型就是指二维表格模型,因而一个关系型数据库就是由二维表及其之间的联系组成的一个数据组织。
关系型数据可以很好地存储一些关系模型的数据,比如一个老师对应多个学生的数据(“多对多”),一本书对应多个作者(“一对多”),一本书对应一个出版日期(“一对一”)
关系模型是我们生活中能经常遇见的模型,存储这类数据一般用关系型数据库
关系模型包括数据结构(数据存储的问题,二维表)、操作指令集合(SQL语句)、完整性约束(表内数据约束、表与表之间的约束)。

常见的关系型数据库:
Oracle、DB2、PostgreSQL、Microsoft SQL Server、Microsoft Access、MySQL
关系型数据库的特点:
安全(因为存储在磁盘中,不会说突然断电数据就没有了)、
容易理解(建立在关系模型上)、
但不节省空间(因为建立在关系模型上,就要遵循某些规则,好比数据中某字段值即使为空仍要分配空间)
什么是非关系型数据库?
非关系型数据库主要是基于“非关系模型”的数据库(由于关系型太大,所以一般用“非关系型”来表示其他类型的数据库)
非关系型模型比如有:
列模型:存储的数据是一列列的。关系型数据库以一行作为一个记录,列模型数据库以一列为一个记录。(这种模型,数据即索引,IO很快,主要是一些分布式数据库)
键值对模型:存储的数据是一个个“键值对”,比如name:liming,那么name这个键里面存的值就是limingimage
文档类模型:以一个个文档来存储数据,有点类似“键值对”。

常见非关系模型数据库:
列模型:Hbase
键值对模型:redis,MemcacheDB
文档类模型:mongoDB

非关系型数据库的特点:
效率高(因为存储在内存中)、
但不安全(断电丢失数据,但其中redis可以同步数据到磁盘中),现在很多非关系型数据库都开始支持转存到磁盘中。
MySQL常见数据库引擎及比较?
MyISAM 适合于一些需要大量查询的应用,但其对于有大量写操作并不是很好。甚至你只是需要update一个字段,整个表都会被锁起来,因此可以说它支持表锁(- select * from tb for update; 使用这种方式来实现表锁),而别的进程,就算是读进程都无法操作直到读操作完成。另外,MyISAM 对于 SELECT COUNT(*) 这类的计算是超快无比的。支持全文索引,且能快速查询

InnoDB 的趋势会是一个非常复杂的存储引擎,对于一些小的应用,它会比 MyISAM 还慢。他是它支持“行锁” ,于是在写操作比较多的时候,会更优秀。并且,他还支持更多的高级应用,比如:事务。
- 表锁:
select * from tb for update; #使用这种方式来实现表锁
- 行锁:
select id,name from tb where id=2 for update ; #使用这种方式来实现行锁


mysql 数据库引擎: http://www.cnblogs.com/0201zcr/p/5296843.html
MySQL存储引擎--MyISAM与InnoDB区别: https://segmentfault.com/a/1190000008227211
简述数据三大范式?
第一范式:确保每列的原子性.
如果每列(或者每个属性)都是不可再分的最小数据单元(也称为最小的原子单元),则满足第一范式.
例如:顾客表(姓名、编号、地址、……)其中"地址"列还可以细分为国家、省、市、区等。
第二范式:在第一范式的基础上更进一层,目标是确保表中的每列都和主键相关.
如果一个关系满足第一范式,并且除了主键以外的其它列,都依赖于该主键,则满足第二范式.
例如:订单表(订单编号、产品编号、定购日期、价格、……),"订单编号"为主键,"产品编号"和主键列没有直接的关系,即"产品编号"列不依赖于主键列,应删除该列。
第三范式:在第二范式的基础上更进一层,目标是确保每列都和主键列直接相关,而不是间接相关.
如果一个关系满足第二范式,并且除了主键以外的其它列都不依赖于主键列,则满足第三范式.
为了理解第三范式,需要根据Armstrong公里之一定义传递依赖。假设A、B和C是关系R的三个属性,如果A-〉B且B-〉C,则从这些函数依赖中,可以得出A-〉C,如上所述,依赖A-〉C是传递依赖。
例如:订单表(订单编号,定购日期,顾客编号,顾客姓名,……),初看该表没有问题,满足第二范式,每列都和主键列"订单编号"相关,再细看你会发现"顾客姓名"和"顾客编号"相关,"顾客编号"和"订单编号"又相关,最后经过传递依赖,"顾客姓名"也和"订单编号"相关。为了满足第三范式,应去掉"顾客姓名"列,放入客户表中。
什么是事务?MySQL如何支持事务?
数据库事务,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。
彻底理解数据库事务: http://www.hollischuang.com/archives/898
start transaction; -- 开始事务
update biao1 set money = money - 500 where id = '1';
update biao1 set money = money + 500 where id = '2';
commit; -- 提交事务
简述数据库设计中一对多和多对多的应用场景?

一对多 : 一个班级有多个学生.
多对多 : 一个老师可以带多个班级,一个班级有多个老师
如何基于数据库实现商城商品计数器?
常见SQL(必备) #练习题
详见武沛齐博客:https://www.cnblogs.com/wupeiqi/articles/5729934.html
简述触发器、函数、视图、存储过程?
--触发器,
触发器是什么------>在数据库某个表进行‘增删改’前后定义一些操作。
#http://www.cnblogs.com/wupeiqi/articles/5713323.html 参考网址看
--函数
在SQL语句中使用函数。
- select sleep(5)
- select date_format(ctime,'%m') from tb;
- 聚合:max/sum/min/avg
- 时间格式化 date_format
- 字符串拼接 concat
--存储过程------>在数据库中定义一些操作SQL语句,以后在代码中通过名称即可调用。
-将SQL语句保存到数据库中,并命名;以后再代码中调用时,直接发送名称。
存储过程的参数:
-in 放入进去
-out 返回回来
-inout 既可以传也可以拿结果

通过代码调用存储过程:
p1是存储过程的名称,后面args里面是参数
这是返回值,固定搭配,必须这么写,@后面的p1是名称,后面的0是下标
import pymysql

conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
# 执行存储过程
cursor.callproc('p1', args=(1, 22, 3, 4))
# 获取执行完存储的参数
cursor.execute("select @_p1_0,@_p1_1,@_p1_2,@_p1_3")
result = cursor.fetchall()
conn.commit()
cursor.close()
conn.close()
print(result)
MySQL索引种类
索引(分5种): B+/哈希索引 =》 查找速度快;更新速度慢
单列:
- 普通索引:加速查找
- 唯一索引: 加速查找 + 约束:不能重复
- 主键索引: 加速查找 + 约束:不能重复 + 不能为空
多列:
- 联合索引
- 联合唯一索引
PS:遵循最左前缀的规则
其他词语:
- 索引合并,利用多个单例索引查询;
- 覆盖索引,在索引表中就能将想要的数据查询到;
索引在什么情况下遵循最左前缀的规则?
#https://www.cnblogs.com/usa007lhy/p/6442570.html

.最左前缀:顾名思义,就是最左优先,上例中我们创建了lname_fname_age多列索引,相当于创建了(lname)单列索引,(lname,fname)组合索引以及(lname,fname,age)组合索引。

- 组合索引最左前缀
如果组合索引为:(name,email)
name and email -- 使用索引
主键和外键的区别?
主键 : 该表中此列唯一,非空 用于加快查询速度
外键 : 该列中的值必须是关联表中关联的数据 用于跨表查询
MySQL常见的函数?
#https://blog.csdn.net/sugang_ximi/article/details/6664748

数字函数,字符串函数,聚合函数
now() -- 返回当前时间
data_format(date,format) # 时间格式化
format(x,y) -- 将数字用千分符分开,并保留y位小数
聚合函数
列举 创建索引但是无法命中索引的8种情况。
创建了索引,应该如何命中索引? 那种情况下,创建了无法命中索引?
- like '%xx'
select * from tb1 where name like '%cn';
- 使用函数
select * from tb1 where reverse(name) = 'wupeiqi';
- or
select * from tb1 where nid = 1 or email = '[email protected]';
特别的:当or条件中有未建立索引的列才失效,以下会走索引
select * from tb1 where nid = 1 or name = 'seven';
select * from tb1 where nid = 1 or email = '[email protected]' and name = 'alex'
- 类型不一致
如果列是字符串类型,传入条件是必须用引号引起来,不然...
select * from tb1 where name = 999;
- !=
select * from tb1 where name != 'alex'
特别的:如果是主键,则还是会走索引
select * from tb1 where nid != 123
- >
select * from tb1 where name > 'alex'
特别的:如果是主键或索引是整数类型,则还是会走索引
select * from tb1 where nid > 123
select * from tb1 where num > 123
- order by
select email from tb1 order by name desc;
当根据索引排序时候,选择的映射如果不是索引,则不走索引
特别的:如果对主键排序,则还是走索引:
select * from tb1 order by nid desc;
- 组合索引最左前缀(要想命中得最左前缀才行)
如果组合索引为:(name,email)
name and email -- 使用索引
name -- 使用索引
email -- 不使用索引
如何开启慢日志查询?
#https://www.jianshu.com/p/9f9c9326f8f4
有2种方式,一是修改mysql的配置文件,二是通过set global语句来实现。
low_query_log = ON 是否开启慢日志记录
long_query_time = 2 时间限制,超过此时间,则记录
slow_query_log_file = /usr/slow.log 日志文件
log_queries_not_using_indexes = ON 为使用索引的搜索是否记录

查看当前配置信息:

   show variables like '%query%'
修改当前配置:
    set global 变量名 = 值
数据库导入导出命令(结构+数据)? #https://blog.csdn.net/dm1314oooooooo/article/details/72818559
- 导出现有数据库数据:
mysqldump -u用户名 -p密码 数据库名称 >导出文件路径 # 结构+数据
mysqldump -u用户名 -p密码 -d 数据库名称 >导出文件路径 # 结构
- 导入现有数据库数据:
mysqldump -uroot -p密码 数据库名称 < 文件路径


#https://blog.csdn.net/dm1314oooooooo/article/details/72818559
1.导出整个数据库

  mysqldump -u用户名 -p密码 数据库名 > 导出的文件名
  C:\Users\jack> mysqldump -uroot -pmysql sva_rec > e:\sva_rec.sql

  2.导出一个表,包括表结构和数据

  mysqldump -u用户名 -p 密码 数据库名 表名> 导出的文件名
  C:\Users\jack> mysqldump -uroot -pmysql sva_rec date_rec_drv> e:\date_rec_drv.sql

  3.导出一个数据库结构
  C:\Users\jack> mysqldump -uroot -pmysql -d sva_rec > e:\sva_rec.sql

4.导出一个表,只有表结构

  mysqldump -u用户名 -p 密码 -d数据库名 表名> 导出的文件名
  C:\Users\jack> mysqldump -uroot -pmysql -d sva_rec date_rec_drv> e:\date_rec_drv.sql

  5.导入数据库

  常用source 命令
  进入mysql数据库控制台,
  如mysql -u root -p
  mysql>use 数据库
  然后使用source命令,后面参数为脚本文件(如这里用到的.sql)
  mysql>source d:wcnc_db.sql
数据库优化方案?
1- 优化
- 不用 select *
- 固定长度字段列,往前放
- char和varchar
- 固定数据放入内存:choice
- 读写分离,利用数据库的主从进行分离:主,用于删除、修改更新;从,查。
- 分库,当数据库中表太多,将表分到不同的数据库;例如:1w张表
- 分表,
- 水平分表,将某些列拆分到另外一张表;例如:博客+博客详细
- 垂直分表,将历史信息分到另外一张表中;例如:账单
- 缓存:利用redis、memcache


还有其他优化方案,就不是开发级别的了
-读写分离
-主从分离,读的时候去从的地方读;写的时候,去主的时候写。
且读写互不影响
主:增删改
从:查
char和varchar的区别?
char:定长,效率高,一般用于固定长度的表单提交数据存储 ;例如:身份证号,手机号,电话,密码等
varchar:不定长,效率偏低

区别一,定长和变长
char 表示定长,长度固定,varchar表示变长,即长度可变。当所插入的字符串超出它们的长度时,视情况来处理,如果是严格模式,则会拒绝插入并提示错误信息,如果是宽松模式,则会截取然后插入。如果插入的字符串长度小于定义长度时,则会以不同的方式来处理,如char(10),表示存储的是10个字符,无论你插入的是多少,都是10个,如果少于10个,则用空格填满。而varchar(10),小于10个的话,则插入多少个字符就存多少个。
varchar怎么知道所存储字符串的长度呢?实际上,对于varchar字段来说,需要使用一个(如果字符串长度小于255)或两个字节(长度大于255)来存储字符串的长度。但是因为他需要有一个prefix来表示他具体bytes数是多少(因为varchar是变长的,没有这个长度值他不知道如何读取数据)。

区别之二,存储的容量不同
对 char 来说,最多能存放的字符个数 255,和编码无关。
而 varchar 呢,最多能存放 65532 个字符。VARCHAR 的最大有效长度由最大行大小和使用的字符集确定。整体最大长度是 65,532字节
简述MySQL的执行计划?
执行计划
目的:用来校验执行效率的;
explain select * from tb;
EXPLAIN命令是查看优化器如何决定执行查询的主要方法。可以帮助我们深入了解MySQL的基于开销的优化器,还可以获得很多可能被优化器考虑到的访问策略的细节,以及当运行SQL语句时哪种策略预计会被优化器采用。
http://www.cnblogs.com/clsn/p/8087501.html#auto_id_20
在对name做了唯一索引前提下,简述以下区别:
select * from tb where name = ‘Oldboy-Wupeiqi’ #这个是把表全部查询一遍 即使找到了也还是会把表查询一遍
select * from tb where name = ‘Oldboy-Wupeiqi’ limit 1 #这个是查询到一条后就不在查询了
1000w条数据,使用limit offset 分页时,为什么越往后翻越慢?如何解决?
因为越查数据越多,这属于全程扫描,所以会越来越慢。
如何解决------>答案一:
先查主键,在分页。
select * from tb where id in (
select id from tb where limit 10 offset 30
)
答案二:
按照也无需求是否可以设置只让用户看200页

答案三:
记录当前页 数据ID最大值和最小值
在翻页时,根据条件先进行筛选;筛选完毕之后,再根据limit offset 查询,避免全程扫描

select * from (select * from tb where id > 22222222) as B limit 10 offset 0

如果用户自己修改页码,也可能导致慢;此时对url种的页码进行加密(rest framework )。
什么是索引合并?
索引合并,就是利用多个单例索引查询
1、索引合并是把几个索引的范围扫描合并成一个索引。
2、索引合并的时候,会对索引进行并集,交集或者先交集再并集操作,以便合并成一个索引。
3、这些需要合并的索引只能是一个表的。不能对多表进行索引合并。

简单的说,索引合并,让一条sql可以使用多个索引。对这些索引取交集,并集,或者先取交集再取并集。从而减少从数据表中取数据的次数,提高查询效率。
什么是覆盖索引?
覆盖索引,在索引表中就能将想要的数据查询到;
简述数据库读写分离?
利用数据库的主从进行分离:主,用于删除、修改更新;从,查。
读写分离,基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。
简述数据库分库分表?(水平、垂直)
分库,当数据库中表太多,将表分到不同的数据库;例如:1w张表; 为了减轻数据库压力可以进行分库, 代价是进行链表操作时可能需要跨库操作
- 分表,
- 水平分表,将某些列拆分到另外一张表;例如:博客+博客详细;表的字段过多可以拆分成两个表
- 垂直分表,将历史信息分到另外一张表中;例如:账单 ;表的历史数据过多
redis和memcached比较?
使用redis有哪些好处? 
(1) 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)
(2) 支持丰富数据类型,支持string,list,set,sorted set,hash
(3) 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
(4) 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除

redis相比memcached有哪些优势?   
(1) memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型
(2) redis的速度比memcached快很多 (3) redis可以持久化其数据

Memcache与Redis的区别都有哪些?
1)、存储方式 Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。 Redis有部份存在硬盘上,这样能保证数据的持久性。
2)、数据支持类型 Memcache对数据类型支持相对简单。 Redis有复杂的数据类型。
3)、使用底层模型不同 它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。 Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。

redis与 memcached相比,redis支持key-value数据类型,同时支持list、set、hash等数据结构的存储。
redis支持数据的备份,即master-slave模式的数据备份。
redis支持数据的持久化。
redis在很多方面支持数据库的特性,可以这样说他就是一个数据库系统,而memcached只是简单地K/V缓存。
它们在性能方面差别不是很大,读取方面尤其是针对批量读取性能方面memcached占据优势。当然redis也有他的优点,如持久性、支持更多的数据结构。
所以在选择方面如果有持久方面的需求或对数据类型和处理有要求的应该选择redis。
如果简单的key/value 存储应该选择memcached。
redis中数据库默认是多少个db 及作用?
Redis默认支持16个数据库(可以通过配置文件支持更多,无上限),可以通过配置databases来修改这一数字。客户端与Redis建立连接后会自动选择0号数据库,不过可以随时使用SELECT命令更换数据库
Redis支持多个数据库,并且每个数据库的数据是隔离的不能共享,并且基于单机才有,如果是集群就没有数据库的概念。
python操作redis的模块?
https://www.cnblogs.com/Eva-J/p/5152841.html
如果redis中的某个列表中的数据量非常大,如果实现循环显示每一个值?
通过scan_iter分片取,减少内存压力
scan_iter(match=None, count=None)增量式迭代获取redis里匹配的的值
# match,匹配指定key
# count,每次分片最少获取个数
r = redis.Redis(connection_pool=pool)
for key in r.scan_iter(match='PREFIX_*', count=100000):
print(key)
redis如何实现主从复制?以及数据同步机制?
- 主从复制
优势:
- 高可用
- 分担主压力
注意:
- slave设置只读


从的配置文件添加以下记录(就加下面一条就行),即可:
slaveof 1.1.1.1 3306
redis中的sentinel的作用?
帮助我们自动在主从之间进行切换
检测主从中 主是否挂掉,且超过一半的sentinel检测到挂了之后才进行进行切换,会把从机变成主机。
如果主修复好了,再次启动时候,会变成从。
如何实现redis集群?
redis的cluster是什么?
集群方案(下面三种,且这些都是运维来做的):
- redis cluster 官方提供的集群方案。
- codis,豌豆荚技术团队。
- tweproxy,Twiter技术团队。
ps:还有一种,是我们程序员自己来做的。
redis cluster的原理?
- 基于分片来完成。
- redis将所有能放置数据的地方创建了 16384 个哈希槽。
- 如果设置集群的话,就可以为每个实例分配哈希槽:
- 192.168.1.20【0-5000】
- 192.168.1.21【5001-10000】
- 192.168.1.22【10001-16384】
- 以后想要在redis中写值时,
set k1 123
将k1通过crc16的算法,将k1转换成一个数字。然后再将该数字和16384求余,如果得到的余数 3000,那么就将该值写入到 192.168.1.20 实例中。
———————————————————————下面是刘师爷的———————————————————————
安装集群软件:

复制代码
# EPEL源安装ruby支持
yum install ruby rubygems -y
# 使用国内源
gem sources -a http://mirrors.aliyun.com/rubygems/
gem sources --remove http://rubygems.org/
gem sources -l
gem install redis -v 3.3.3
复制代码
redis配置文件:

复制代码
port 7000
daemonize yes
pidfile /data/7000/redis.pid
logfile "/var/log/redis7000.log"
dbfilename dump.rdb
dir /data/7000
cluster-enabled yes # 开实例的集群模式
cluster-config-file nodes.conf # 保存节点配置文件的路径
cluster-node-timeout 5000
appendonly yes
复制代码
启动6个节点(要让集群正常运作至少需要三个主节点,另外三个做为从节点)

/application/redis/src/redis-server /data/7000/redis.conf
/application/redis/src/redis-server /data/7001/redis.conf
/application/redis/src/redis-server /data/7002/redis.conf
/application/redis/src/redis-server /data/7003/redis.conf
/application/redis/src/redis-server /data/7004/redis.conf
/application/redis/src/redis-server /data/7005/redis.conf
 ps -ef |grep 700

创建集群

/application/redis/src/redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 \

127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
# 选项–replicas 1 表示我们希望为集群中的每个主节点创建一个从节点
# 之后跟着的其他参数则是这个集群实例的地址列表,3个master3个slave redis-trib 会打印出一份预想中的配
# 置给你看, 如果你觉得没问题的话, 就可以输入 yes
——————————————————————————————————————————————
redis中默认有多少个哈希槽?
默认有16384 个哈希槽
简述redis的有哪几种持久化策略及比较?

-持久化的两种方式:RDB/AOF
RDB:每隔一段时间对redis进行一次持久化。
- 缺点:数据不完整
- 优点:速度快
AOF:把所有命令保存起来,如果想到重新生成到redis,那么就要把命令重新执行一次。
- 缺点:速度慢,文件比较大
- 优点:数据完整
列举redis支持的过期策略。
redis的过期策略。#这个不用我们写,只要加配置就行了
voltile-lru: 从已设置过期时间的数据集(server.db[i].expires)中挑选最近频率最少数据淘汰
volatile-ttl: 从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰


allkeys-lru: 从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
allkeys-random: 从数据集(server.db[i].dict)中任意选择数据淘汰
no-enviction(驱逐):禁止驱逐数据
MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 redis 中都是热点数据?
redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略(回收策略),从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰。redis 提供 6种数据淘汰策略,就是上面的过期策略。
写代码,基于redis的列表实现 先进先出、后进先出队列、优先级队列。
class stack: #先进后出
def __init__(self,conn):
self.conn = connc
def push(self,val):
self.conn.rpush('aaa',val)
def pop(self):
return self.conn.rpop('aaa')

class stack: #先进先出
def __init__(self,conn):
self.conn = conn
def push(self,val):
self.conn.rpush('bbb',val)
def get(self):
return self.conn.lpop('bbb')

class stack: #优先级列队
def __init__(self,conn):
self.conn = conn
def push(self,val,count):
self.conn.zadd('ccc',val,count)
def get(self):
a = self.conn.zrange('ccc', 0, 0)[0]
self.conn.zrem('ccc', a)
return a
如何基于redis实现消息队列?
将列表维护成一个栈,设置获取数据的超时时间
ps:
不要使用redis去做消息队列,这不是redis的设计目标。
但实在太多人使用redis去做去消息队列,redis的作者看不下去,另外基于redis的核心代码,另外实现了一个消息队列disque:https://github.com/antirez/disque
如何基于redis实现发布和订阅?以及发布订阅和消息队列的区别?
发布者:
import redis

conn = redis.Redis(host='127.0.0.1',port=6379)
conn.publish('104.9MH', "hahaha")
订阅者:
import redis

conn = redis.Redis(host='127.0.0.1',port=6379)
pub = conn.pubsub()
pub.subscribe('104.9MH')

while True:
msg= pub.parse_response()
print(msg)
ps:
发送消息 : conn.publish(名称,消息)
接收消息 : conn.sunscribe(名称)
区别 : 消息队列,收到消息只会有一个处理者;发布订阅,所有的订阅者都会收到消息并进行处理
什么是codis及作用?
豌豆荚团队提供的一个分布式集群 Redis 解决方案
Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别 (不支持的命令列表), 上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作, 所有后边的一切事情, 对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的 Redis 服务.
什么是twemproxy及作用?
Twemproxy 也叫 nutcraker。是 Twtter 开源的一个 Redis 和 Memcache 代理服务器,主要用于管理 Redis 和 Memcached 集群,减少与Cache 服务器直接连接的数量。

Twemproxy特性:

轻量级、快速
保持长连接
减少了直接与缓存服务器连接的连接数量
使用 pipelining 处理请求和响应
支持代理到多台服务器上
同时支持多个服务器池
自动分片数据到多个服务器上
实现完整的 memcached 的 ASCII 和再分配协议
通过 yaml 文件配置服务器池
支持多个哈希模式,包括一致性哈希和分布
能够配置删除故障节点
可以通过端口监控状态
支持 linux, *bsd,os x 和 solaris
Twemproxy安装配置参考官网: https://github.com/twitter/twemproxy
主要解决问题和缺点
其功能:
通过代理的方式减少缓存服务器的连接数。
自动在多台缓存服务器间共享数据。
通过不同的策略与散列函数支持一致性散列。
通过配置的方式禁用失败的结点。
运行在多个实例上,客户端可以连接到首个可用的代理服务器。
支持请求的流式与批处理,因而能够降低来回的消耗。
其缺点:
不支持针对多个值的操作,比如取sets的子交并补等。
不支持Redis的事务操作。
错误消息、日志信息匮乏,排查问题困难。
写代码实现redis事务操作。
import redis

pool = redis.ConnectionPool(host='10.211.55.4', port=6379)

conn = redis.Redis(connection_pool=pool)

# transaction默认为False,只可以完成批量提交的作用,节省网络延时
# 改为True后可以实现事务功能
# pipe = r.pipeline(transaction=False)
pipe = conn.pipeline(transaction=True)
# 开始事务
pipe.multi()

pipe.set('name', 'alex')
pipe.set('role', 'sb')
pipe.lpush('roless', 'sb')

# 提交
pipe.execute()
redis中的watch的命令的作用?
检测所操作的数据在操作时有没有改变 如果发生改变 则操作失败

数据库的锁
在Redis的事务中,WATCH命令可用于提供CAS(check-and-set)功能。假设我们通过WATCH命令在事务执行之前监控了多个Keys,倘若在WATCH之后有任何Key的值发生了变化,EXEC命令执行的事务都将被放弃,同时返回Null multi-bulk应答以通知调用者事务执行失败。

面试题:你如何控制剩余的数量不会出问题?
- 通过redis的watch实现
import redis
conn = redis.Redis(host='127.0.0.1',port=6379)

# conn.set('count',1000)
val = conn.get('count')
print(val)

with conn.pipeline(transaction=True) as pipe:

# 先监视,自己的值没有被修改过
conn.watch('count')

# 事务开始
pipe.multi()
old_count = conn.get('count')
count = int(old_count)
print('现在剩余的商品有:%s',count)
input("问媳妇让不让买?")
pipe.set('count', count - 1)

# 执行,把所有命令一次性推送过去
pipe.execute()
- 数据库的锁
基于redis如何实现商城商品数量计数器?
Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的10个用户–我们
称之为“user_scores”,我们只需要像下面一样执行即可:
当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行:
ZRANGE user_scores 0 10 WITHSCORES
Agora Games就是一个很好的例子,用Ruby实现的,它的排行榜就是使用Redis来存储数据的,你可以在这里看到

ps: 字符串的decr可以实现自减操作
简述redis分布式锁和redlock的实现机制。
在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段。 有很多三方库和文章描述如何用Redis实现一个分布式锁管理器,但是这些库实现的方式差别很大,而且很多简单的实现其实只需采用稍微增加一点复杂的设计就可以获得更好的可靠性。 这篇文章的目的就是尝试提出一种官方权威的用Redis实现分布式锁管理器的算法,我们把这个算法称为RedLock。
https://www.cnblogs.com/ironPhoenix/p/6048467.html
https://blog.csdn.net/junli_chen/article/details/79228282
什么是一致性哈希?Python中是否有相应模块?
实现服务器负载均衡时候可供选择的负载均衡的算法
from hash_ring import *
memcache_servers = ['192.168.0.246:11212',
'192.168.0.247:11212',
'192.168.0.249:11212']

ring = HashRing(memcache_servers)

server = ring.get_node('my_key')

print(server)
# '192.168.0.247:11212'

server = ring.get_node('my_keysdfsdf')

print(server)
# '192.168.0.249:11212'
Python模块--hash_ring,即Python中的一致性hash
如何高效的找到redis中所有以oldboy开头的key?
redis 有一个keys命令。
语法:KEYS pattern
说明:返回与指定模式相匹配的所用的keys。
该命令所支持的匹配模式如下:
(1)?:用于匹配单个字符。例如,h?llo可以匹配hello、hallo和hxllo等;
(2)*:用于匹配零个或者多个字符。例如,h*llo可以匹配hllo和heeeello等;
(3)[]:可以用来指定模式的选择区间。例如h[ae]llo可以匹配hello和hallo,但是不能匹配hillo。
同时,可以使用“/”符号来转义特殊的字符


第四部分 前端、框架和其他(155题)
谈谈你对http协议的认识。
http的协议是建立在tcp协议之上的,https协议体现在往这种www.cnblogs.com地址一发,就会拼接成下面的这种类型的字符串(两个\r\n),把字符串发过去了。
http协议规定了数据传输的格式(通过\r\n分割的规范分割),以及链接的特性(无状态,短连接)
pd: 浏览器本质,socket客户端遵循Http协议(通过\r\n分割的规范+请求响应断开连接=>无状态、短连接)
谈谈你对websocket协议的认识。
a. 什么是websocket?
websocket是给浏览器新建一套协议。协议规定:浏览器和服务端连接之后不断开,以此可以完成:服务端向客户端主动推送消息。
websocket协议额外做的一些前天操作:
- 握手,连接前进行校验
- 发送数据加密

b. websocket本质
- socket
- 握手,魔法字符串+加密
- 加密,payload_len=127/126/<=125 -> mask key
什么是magic string ?
websocket用于给数加密的特殊字符串

魔法字符串 : 258EAFA5-E914-47DA-95CA-C5AB0DC85B11
如何创建响应式布局?
pg是默认的(颜色);
当像素到768PX之后,则会发生变化(这里是颜色变化)
@media (min-width: 768px){设定分辨率样式}
你曾经使用过哪些前端框架?
vue query,bootstrap,
什么是ajax请求?并使用jQuery和XMLHttpRequest对象实现一个ajax请求。
不刷新页面的情况下发送请求
$.ajax({})

var xmlHttp = createXMLHttpRequest();
xmlHttp.open("GET", "/ajax_get/?a=1", true);
xmlHttp.send(null);
xmlHttp.onreadystatechange = function() {
if(xmlHttp.readyState == 4) {
alert('hello');
}
};
如何在前端实现轮训?
前端写一个定时器 每隔固定时间发起一次请求
如何在前端实现长轮训?
写一个函数,这个函数会向服务器发送请求(服务器没数据会夯住请求),

函数执行完毕后会再次调用自己,从而实现长轮询。
vuex的作用?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,
并以相应的规则保证状态以一种可预测的方式发生变化。
vue中的路由的拦截器的作用?

vue-resource的interceptors拦截器的作用正是解决此需求的妙方。在每次http的请求响应之后,如果设置了拦截器如下,会优先执行拦截器函数,获取响应体,然后才会决定是否把response返回给then进行接收
验证要访问的url,只让符合规则的通过。
axios的作用?
https://blog.csdn.net/qq_27626333/article/details/76254888
axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端

从浏览器中创建 XMLHttpRequest
从 node.js 发出 http 请求
支持 Promise API
拦截请求和响应
转换请求和响应数据
取消请求
自动转换JSON数据
客户端支持防止 CSRF/XSRF
列举vue的常见指令。
1、v-if指令:判断指令,根据表达式值得真假来插入或删除相应的值。
2、v-show指令:条件渲染指令,无论返回的布尔值是true还是false,元素都会存在在html中,只是false的元素会隐藏在html中,并不会删除.
3、v-else指令:配合v-if或v-else使用。
4、v-for指令:循环指令,相当于遍历。
5、v-bind:给DOM绑定元素属性。
6、v-on指令:监听DOM事件。
简述jsonp及实现原理?
JSONP是json用来跨域的一个东西。原理是通过script标签的跨域特性来绕过同源策略。(创建一个回调函数,然后在远程服务上调用这个函数并且将json数据形式作为参数传递,完成回调)。
http://www.cnblogs.com/huchong/p/8469053.html
是什么cors ?
跨域资源共享(CORS,Cross-Origin Resource Sharing),其本质是设置响应头,使得浏览器允许跨域请求。
http://www.cnblogs.com/huchong/p/8469063.html
列举Http请求中常见的请求方式?
请求方法有8种,分别为:
GET:请求获取由 Request-URI 所标识的资源。
POST:在 Request-URI 所标识的资源后附加新的数据。
HEAD:请求获取由 Request-URI 所标识的资源的响应消息报头。
OPTIONS:请求查询服务器的性能,或查询与资源相关的选项和需求。
PUT:请求服务器存储一个资源,并用 Request-URI作为其标识。
DELETE:请求服务器删除由 Request-URI所标识的资源。
TRACE:请求服务器回送收到的请求信息,主要用语测试或诊断。
CONNECT:HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
列举Http请求中的状态码?
常见的响应状态码有以下几种,在各种下面分别列几个常见的状态码:
1开头(信息)
2开头(成功)
200(OK):请求成功
202(Accepted):已接受请求,尚未处理
204(No Content):请求成功,且不需返回内容
3开头(重定向)
301(Moved Permanently):被请求的资源已永久移动到新位置
301(Moved Temporarily):被请求的资源已临时移动到新位置
4开头(客户端错误)
400(Bad Request):请求的语义或是参数有错
403(Forbidden):服务器拒绝了请求
404(Not Found):未找到请求的资源
5开头(服务器错误)
500(Internal Server Error):服务器遇到错误,无法完成请求
502(Bad Getway):网关错误,一般是服务器压力过大导致连接超时
503(Service Unavailable):服务器宕机
列举Http请求中常见的请求头?
Accept:
浏览器端可以接受的媒体类型,通配符 * 代表任意类型
Accept-Encoding:
浏览器申明自己接收的编码方法,例如: Accept-Encoding: zh-CN,zh;q=0.8
Accept-Language:
浏览器申明自己接收的语言,
Connection:
如Connection: keep-alive 当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,
如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。
Referer:
当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面链接过来的,服务器籍此可以获得一些信息用于处理。
User-Agent:
告诉HTTP服务器, 客户端使用的操作系统和浏览器的名称和版本.
Cookie:
Cookie是用来存储一些用户信息以便让服务器辨别用户身份的(大多数需要登录的网站上面会比较常见),比如cookie会存储一些用户的用户名和密码,
当用户登录后就会在客户端产生一个cookie来存储相关信息,这样浏览器通过读取cookie的信息去服务器上验证并通过后会判定你是合法用户,从而允许查看相应网页。
看图写结果:
<script>
var name = '吴佩琪';
function func() {
var name = '李杰';
function inner() {
alert(name);

}
return inner;

}
var ret = func();
ret()
</script>
执行结果------> 李杰
看图写结果:
#这个代码执行错误没成功
<script type="text/javascript">
function main() {
if(1==1){
var name = '吴佩琪';
}
console.log(name);

}
main()

</script>
别人的执行结果是吴佩琪
看图写结果:
老男孩
看图写结果:

undefined
看图写结果:
武沛齐
看图写结果:
django、flask、tornado框架的比较?
django:大而全的全的框架,重武器;内置很多组件:ORM、admin、Form、ModelForm、中间件、信号、缓存、csrf等
flask: 微型框架、可扩展强,如果开发简单程序使用flask比较快速,

如果实现负责功能就需要引入一些组件:flask-session/flask-SQLAlchemy/wtforms/flask-migrate/flask-script/blinker
Tornado:是一个轻量级的Web框架,异步非阻塞+内置WebSocket功能。
Django,flask这两个框架都是基于wsgi协议实现的,默认使用的wsgi模块不一样。
还有一个显著的特点,他们处理请求的方式不同:
django: 通过将请求封装成Request对象,再通过参数进行传递。
flask:通过上下文管理实现。
tornado,内置websocket模块
什么是wsgi?
wsgi是一个协议,也是一个规范。
Python Web服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)是Python应用程序或框架和Web服务器之间的一种接口,已经被广泛接受, 它已基本达成它的可移植性方面的目标。
http://python.jobbole.com/88653/
django请求的生命周期?
wsgi------>中间件(执行process-request)------>路由匹配------>找到相应的视图函数------>通过orm------>做数据库的操作------>获取到数据,通过模板进行字符串渲染,再经过所有的中间件------>再到wsgi------>把字符串返回给客户端

步骤总结:
a. wsgi, 创建socket服务端,用于接收用户请求并对请求进行初次封装。
b. 中间件,对所有请求到来之前,响应之前定制一些操作。
c. 路由匹配,在url和视图函数对应关系中,根据当前请求url找到相应的函数。
d. 执行视图函数,业务处理【通过ORM去数据库中获取数据,再去拿到模板,然后将数据和模板进行渲染】
e. 再经过所有中间件
f. 通过wsgi将响应返回给用户。
【图】
列举django的内置组件?
Model
Form
ModelForm
ps:在使用Model和Form时,都需要对字段进行定义并指定类型,通过ModelForm则可以省去From中字段的定义
跨站请求伪造
-django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.--CsrfViewMiddleware 来完成。
-全局:
中间件 django.middleware.csrf.CsrfViewMiddleware

-局部:
@csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
@csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
Cookie
Session
分页
缓存
序列化
serializers
json.dumps
信号
中间件
列举django中间件的5个方法?以及django中间件的应用场景?
所有方法:
- process_request
- process_view
- process_template_response , 当视图函数的返回值对象中有render方法时,该方法才会被调用。
- process_response
- process_excaption

应用场景,登录,权限,验证
简述什么是FBV和CBV?
FBV: 就是一个函数
def index(request):
pass

CBV: 就是类
class IndexView(View):

# 如果是crsf相关,必须放在此处,也就是必须放到下面的函数中
def dispach(self,request):
# 通过反射执行post/get

@method_decoretor(装饰器函数)
def get(self,request):
pass

def post(self,request):
pass

路由:IndexView.as_view()
django的request对象是在什么时候创建的?

请求到来时django.core.handlers.wsgi.WSGIHandler得到__call__方法被执行,将environ封装成了request
如何给CBV的程序添加装饰器?
CBV时的注意事项?
- 装饰器
from django.views import View
from django.utils.decorators import method_decorator

def auth(func):
def inner(*args,**kwargs):
return func(*args,**kwargs)
return inner

class UserView(View):

@method_decorator(auth)
def get(self,request,*args,**kwargs):
return HttpResponse('...')
- csrf的装饰器要加到dispath
from django.views import View
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt,csrf_protect


class UserView(View):

@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return HttpResponse('...')


from django.views import View
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt,csrf_protect

@method_decorator(csrf_exempt,name='dispatch')
class UserView(View):

def dispatch(self, request, *args, **kwargs):
return HttpResponse('...')

注意事项以及dispatch
列举django orm 中所有的方法(QuerySet对象的所有方法)
返回QuerySet对象的方法有:
all()
filter()
exclude()
order_by()
reverse()
distinct()
特殊的QuerySet:
values() 返回一个可迭代的字典序列
values_list() 返回一个可迭代的元组序列
返回具体对象的:
get()
first()
last()
返回布尔值的方法有:
exists()
返回数字的方法有:
count()
only和defer的区别?
only : 只查指定字段

defer : 不查指定字段

def defer(self, *fields):
models.UserInfo.objects.defer('username','id')

models.UserInfo.objects.filter(...).defer('username','id')
#映射中排除某列数据

def only(self, *fields):
#仅取某个表中的数据
models.UserInfo.objects.only('username','id')

models.UserInfo.objects.filter(...).only('username','id')
select_related和prefetch_related的区别?
都是提升查询效率的

select_ related : 做连表

prefetch_related : 通过两次查询,第一次根据一查多的范围,第二次差多的信息.对多得信息已经存在于一之中,不会产生额外的查询
filter和exclude的区别?
filter : 查询满足条件的

exclude : 排除满足条件的
列举django orm中三种能写sql语句的方法。
1.使用execute执行自定义SQL
# from django.db import connection, connections
# cursor = connection.cursor() # cursor = connections['default'].cursor()
# cursor.execute("""SELECT * from auth_user where id = %s""", [1])
# row = cursor.fetchone()

2.使用extra方法

# extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
# Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
# Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
# Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
# Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])

3.使用raw方法
  解释:执行原始sql并返回模型
  说明:依赖model多用于查询
  用法:
    book = Book.objects.raw("select * from hello_book")
    for item in book:
      print(item.title)
https://www.cnblogs.com/413xiaol/p/6504856.html
django orm 中如何设置读写分离?
问题:
app01中的表在default数据库创建
app02中的表在db1数据库创建

# 第一步:
python manage.py makemigraions

# 第二步:
app01中的表在default数据库创建
python manage.py migrate app01 --database=default

# 第三步:
app02中的表在db1数据库创建
python manage.py migrate app02 --database=db1

# 手动操作:
m1.UserType.objects.using('default').create(title='VVIP')
m2.Users.objects.using('db1').create(name='VVIP',email='xxx')
# 自动操作:
配置:
class Router1:
def db_for_read(self, model, **hints):
"""
Attempts to read auth models go to auth_db.
"""
if model._meta.app_label == 'app01':
return 'default'
else:
return 'db1'

def db_for_write(self, model, **hints):
"""
Attempts to write auth models go to auth_db.
"""
if model._meta.app_label == 'app01':
return 'default'
else:
return 'db1'

DATABASE_ROUTERS = ['db_router.Router1',]

使用:
m1.UserType.objects.using('default').create(title='VVIP')
m2.Users.objects.using('db1').create(name='VVIP',email='xxx')
其他:
数据库迁移时进行约束:
#下面是为了防止读写数据库时候发生错误,而写的代码,eg:如app01表示读取的,app02是写的。(跟下面注释相结合)
class Router1:
def allow_migrate(self, db, app_label, model_name=None, **hints):
"""
All non-auth models end up in this pool.
"""
if db=='db1' and app_label == 'app02': #当数据库是db1且应用名是app02的时候才是正确的,意思就是才能正常访问或者在数据库中正常操作
return True
elif db == 'default' and app_label == 'app01':
return True
else:
return False

# 如果返回None,那么表示交给后续的router,如果后续没有router,则相当于返回True

def db_for_read(self, model, **hints):
"""
Attempts to read auth models go to auth_db.
"""
if model._meta.app_label == 'app01': #model._meta.app_label 这个是死的,就得这么写
return 'default'
else:
return 'db1'

def db_for_write(self, model, **hints):
"""
Attempts to write auth models go to auth_db.
"""
if model._meta.app_label == 'app01':
return 'default'
else:
return 'db1'
F和Q的作用?
F : 对数据本身的值进行比较和判断
Q : 构造复杂的查询条件
values和values_list的区别?
values : 取字典的queryset
values_list : 取元组的queryset
如何使用django orm批量创建数据?
def bulk_create(self, objs, batch_size=None):
# 批量插入
# batch_size表示一次插入的个数
objs = [
models.DDD(name='r11'),
models.DDD(name='r22')
]
models.DDD.objects.bulk_create(objs, 10)
django的Form和ModeForm的作用?
Form : 构建form组件字符串,以及表单数据验证
ModeForm : 根据模型类来生成Form

- 作用:
- 对用户请求数据格式进行校验
- 自动生成HTML标签
- 区别:
- Form,字段需要自己手写。
class Form(Form):
xx = fields.CharField(.)
xx = fields.CharField(.)
xx = fields.CharField(.)
xx = fields.CharField(.)
- ModelForm,可以通过Meta进行定义
class MForm(ModelForm):
class Meta:
fields = "__all__"
model = UserInfo

- 应用:只要是客户端向服务端发送表单数据时,都可以进行使用,如:用户登录注册
django的Form组件中,如果字段中包含choices参数,请使用两种方式实现数据源实时更新。
方式一:重写构造方法,在构造方法中重新去数据库获取值
class UserForm(Form):
name = fields.CharField(label='用户名',max_length=32)
email = fields.EmailField(label='邮箱')
ut_id = fields.ChoiceField(
# choices=[(1,'二B用户'),(2,'山炮用户')]
choices=[]
)

def __init__(self,*args,**kwargs):
super(UserForm,self).__init__(*args,**kwargs)

self.fields['ut_id'].choices = models.UserType.objects.all().values_list('id','title')
方式二: ModelChoiceField字段
from django.forms import Form
from django.forms import fields
from django.forms.models import ModelChoiceField
class UserForm(Form):
name = fields.CharField(label='用户名',max_length=32)
email = fields.EmailField(label='邮箱')
ut_id = ModelChoiceField(queryset=models.UserType.objects.all())

依赖:
class UserType(models.Model):
title = models.CharField(max_length=32)

def __str__(self):
return self.title
django的Model中的ForeignKey字段中的on_delete参数有什么作用?
on_delete有CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET()五个可选择的值

CASCADE:此值设置,是级联删除。

PROTECT:此值设置,是会报完整性错误。

SET_NULL:此值设置,会把外键设置为null,前提是允许为null。

SET_DEFAULT:此值设置,会把设置为外键的默认值。

SET():此值设置,会调用外面的值,可以是一个函数。
django中csrf的实现机制?
CSRF(Cross-site request forgery), 中文名称:跨站请求伪造,CSRF(Cross-site request forgery), 中文名称:跨站请求伪造.
服务端生成一个随机字符串 返回时放到form表单的一个隐藏input标签中,或者放到cookie中,
以后每次访问时都要带上这个随机字符串 才能正常访问。

Django预防CSRF攻击的方法是在用户提交的表单中加入一个csrftoken的隐含值,这个值和服务器中保存的csrftoken的值相同,这样做的原理如下: 1、在用户访问django的可信站点时,django反馈给用户的表单中有一个隐含字段csrftoken,这个值是在服务器端随机生成的,每一次提交表单都会生成不同的值
2、当用户提交django的表单时,服务器校验这个表单的csrftoken是否和自己保存的一致,来判断用户的合法性
3、当用户被csrf攻击从其他站点发送精心编制的攻击请求时,由于其他站点不可能知道隐藏的csrftoken字段的信息这样在服务器端就会校验失败,攻击被成功防御
具体配置如下:

template中添加{%csrf_token%}标签
https://blog.csdn.net/u012556900/article/details/57412707
django如何实现websocket?
基于Python socket实现的WebSocket服务端或者channel插件 都需要前后端配合
https://www.cnblogs.com/huguodong/p/6611602.html
基于django使用ajax发送post请求时,都可以使用哪种方法携带csrf token?
放到请求体data中 ,或者请求头中,或者模板中直接是csrf
https://www.cnblogs.com/wxp5257/p/7834090.html
django中如何实现orm表中添加数据时创建一条日志记录。
利用信号或者触发器

LOGGING配置查看翻译的SQL:
在Django的日志设置中,配置上一个名为django.db.backends的logger实例即可查看翻译后的SQL语句。
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}  
http://www.cnblogs.com/owasp/p/5981355.html
django缓存如何设置?

# 全站缓存
MIDDLEWARE_CLASSES = (
‘django.middleware.cache.UpdateCacheMiddleware’, #第一
'django.middleware.common.CommonMiddleware',
‘django.middleware.cache.FetchFromCacheMiddleware’, #最后
)

# 视图缓存
from django.views.decorators.cache import cache_page
import time

@cache_page(15) #超时时间为15秒
def index(request):
t=time.time() #获取当前时间
return render(request,"index.html",locals())

# 模板缓存
{% load cache %}
<h3 style="color: green">不缓存:-----{{ t }}</h3>

{% cache 2 'name' %} # 存的key
<h3>缓存:-----:{{ t }}</h3>
{% endcache %}
django的缓存能使用redis吗?如果可以的话,如何配置?
ps: django缓存默认不支持redis
安装第三方组件支持redis:
django-redis组件

首先 要使用 Django-redis 模块
配置 settings.py 文件:

CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"PASSWORD": "mysecret"
}
}
}

#运行命令
python manage.py createcachetable
------>
Cache 参数
TIMEOUT:缓存的默认过期时间,以秒为单位, 这个参数默认是 300 seconds (5 分钟)。你可以设置 TIMEOUT 为 None 这样的话,缓存默认永远不会过期;如果把值设置成 0 缓存会立即失效(缓存就没有意义了)。

OPTIONS:这个参数应该被传到缓存后端。有效的可选项列表根据缓存的后端不同而不同,由第三方库所支持的缓存将会把这些选项直接配置到底层的缓存库。
缓存的后端实现自己的选择策略 (i.e., the locmem, filesystem and database backends) 将会履行下面这些选项:

MAX_ENTRIES:高速缓存允许的最大条目数,超出这个数则旧值将被删除,这个参数默认是 300。
CULL_FREQUENCY:当达到 MAX_ENTRIES 值的时候,被删除的条目比率。该比率可以理解为 1/CULL_FREQUENCY,所以设置 CULL_FREQUENCY 为 2 会在达到 MAX_ENTRIES 值时会删去一半的缓存。这个参数应该是整数,默认为 3。把 CULL_FREQUENCY的值设置为 0 意味着当达到 MAX_ENTRIES 值时,缓存将被清空。
KEY_PREFIX:将自动包含(默认情况下预置为)Django 服务器使用的所有缓存键的字符串。

VERSION:由 Django 服务器生成的缓存键的默认版本号。

KEY_FUNCTION 包含函数的虚线路径的字符串,定义如何将前缀,版本和键组成最终缓存键。

站点缓存:

settings.py
MIDDLEWARE = [
# 站点缓存 , 注意必须在第一个位置
'django.middleware.cache.UpdateCacheMiddleware',
...
# 站点缓存, 注意必须在最后一个位置
'django.middleware.cache.FetchFromCacheMiddleware',
]
------>
视图缓存:
views.py
from django.shortcuts import render
from django.views.decorators.cache import cache_page

from cache.models import Foo

# 在需要缓存的视图上添加装饰器, 参数是设置timeout 超时时间, 单位是秒,
@cache_page(60)
def index(request):
bar = Foo.objects.all()
return render(request, 'cache/index.html', {'bar': bar})
———————————————————————
django路由系统中name的作用?
当url太长书写困难时,可以给每个url起别名name='别名'

用于反向解析url字符串 使书写变得简单
django的模板中filter和simple_tag的区别?
filter : 类似管道,只能接受两个参数第一个参数是|前的数据

simple_tag : 类似函数
django-debug-toolbar的作用?
它是一个功能强大的调试工具,

Django Debug Toolbar是一组可配置的面板集合,用来显示Django Web应用当前请求/响应的各种调试信息。

响应时间 sql语句执行时间等。
django_debug_toolbar 是django的第三方工具包,给django扩展了调试功能。
包括查看执行的sql语句,db查询次数,request,headers,调试概览等。
https://blog.csdn.net/weixin_39198406/article/details/78821677
django中如何实现单元测试?
https://www.jianshu.com/p/34267dd79ad6

对于每一个测试方法都会将setUp()和tearDown()方法执行一遍
会单独新建一个测试数据库来进行数据库的操作方面的测试,默认在测试完成后销毁。
在测试方法中对数据库进行增删操作,最后都会被清除。也就是说,在test_add中插入的数据,在test_add测试结束后插入的数据会被清除。
django单元测试时为了模拟生产环境,会修改settings中的变量,例如, 把DEBUG变量修改为True, 把ALLOWED_HOSTS修改为[*]。

from django.test import TestCase
from myapp.models import Animal

# Django的单元测试基于unittest库
class StudentTestCase(TestCase):
# 测试函数执行前执行
def setUp(self):
print("======in setUp")

# 需要测试的内容
def test_add(self):
student = Student(name='aaa')
student.save()
self.assertEqual(student.name, 'aaa')

# 需要测试的内容
def test_check_exit(self):
self.assertEqual(0, Student.objects.count())

# 测试函数执行后执行
def tearDown(self):
print("======in tearDown")


# 测试整一个工程
$ ./manage.py test

# 只测试某个应用
$ ./manage.py test app --keepdb

# 只测试一个Case
$ ./manage.py test animals.tests.StudentTestCase

# 只测试一个方法
$ ./manage.py test animals.tests.StudentTestCase.test_add
解释orm中 db first 和 code first的含义?
DB First 数据库里先创建数据库表结构,根据表结构生成类,根据类操作数据库
Code First 先写代码,执行代码创建数据库表结构
django中如何根据数据库表生成model中的类?
Django引入外部数据库还是比较方便的,步骤如下
创建一个项目,修改seting文件,在setting里面设置你要连接的数据库类型和连接名称,地址之类,和创建新项目的时候一致
运行下面代码可以自动生成models模型文件
python manage.py inspectdb
这样就可以在命令行看到数据库的模型文件了

把模型文件导入到app中
创建一个app
django-admin.py startapp app
python manage.py inspectdb > app/models.py
ok模型文件已经生成好了。下面的工作就和之前一样了
ps:
https://jingyan.baidu.com/article/4ae03de3e513d23eff9e6bb7.html
使用orm和原生sql的优缺点?
ORM:Object Relational Mapping(关系对象映射)
类名对应------》数据库中的表名
类属性对应---------》数据库里的字段
类实例对应---------》数据库表里的一行数据
obj.id obj.name.....类实例对象的属性
可以通过类和对象来操作数据库, 本质上是对类和对象的操作转换成sql语句并执行
ORM书写比较方便简单 开发效率比较高 执行效率比较低
相比orm 原生sql书写就比较复杂 开发效率比较低 但是执行效率比较高(两个差距不是太大)
如果想要提高开发效率推荐使用ORM或者访问数量比较少的话 ORM更好一些
简述MVC和MTV
MVC是众所周知的模式,即:将应用程序分解成三个组成部分:model(模型),view(视图),和 controller(控制 器)。其中:
M 管理应用程序的状态(通常存储到数据库中),并约束改变状态的行为(或者叫做“业务规则”)。
C 接受外部用户的操作,根据操作访问模型获取数据,并调用“视图”显示这些数据。控制器是将“模型”和“视图”隔离,并成为二者之间的联系纽带。
V 负责把数据格式化后呈现给用户。

Django也是一个MVC框架。但是在Django中,控制器接受用户输入的部分由框架自行处理,所以 Django 里更关注的是模型(Model)、模板(Template)和视图(Views),称为 MTV模式:
M 代表模型(Model),即数据存取层。 该层处理与数据相关的所有事务: 如何存取、如何验证有效性、包含哪些行为以及数据之间的关系等。
T 代表模板(Template),即表现层。 该层处理与表现相关的决定: 如何在页面或其他类型文档中进行显示。
V 代表视图(View),即业务逻辑层。 该层包含存取模型及调取恰当模板的相关逻辑。 你可以把它看作模型与模板之间的桥梁。
MVC: model view controller
MTV: model tempalte view
django的contenttype组件的作用?
可以使用他再加上表中的两个字段实现:一张表和N张表创建FK关系。
  字段:表名称
  字段:数据行ID

contenttype是django的一个组件(app),为我们找到django程序中所有app中的所有表并添加到记录中。

可以使用他再加上表中的两个字段实现:一张表和N张表创建FK关系。
- 字段:表名称
- 字段:数据行ID

应用:路飞表结构优惠券和专题课和学位课关联。
http://www.cnblogs.com/iyouyue/p/8810464.html
谈谈你对restfull 规范的认识?
1. 谈谈你对restful 规范的理解?
- restful其实就是一套编写接口的协议,协议规定如何编写以及如何设置返回值、状态码等信息。
- 最显著的特点:
restful: 给用户一个url,根据method不同在后端做不同的处理,比如:post 创建数据、get获取数据、put和patch修改数据、delete删除数据。
no rest: 给调用者很多url,每个url代表一个功能,比如:add_user/delte_user/edit_user/
- 当然,还有协议其他的,比如:
- 版本,来控制让程序有多个版本共存的情况,版本可以放在 url、请求头(accept/自定义)、GET参数
- 状态码,200/300/400/500
- url中尽量使用名词,restful也可以称为“面向资源编程”
- api标示:
api.luffycity.com
www.luffycity.com/api/
...
接口的幂等性是什么意思?
一个接口通过1次相同的访问,再对该接口进行N次相同的访问时候,对资源不造影响,那么就认为接口具有幂等性。
比如:
GET, 第一次获取结果、第二次也是获取结果对资源都不会造成影响,幂等。
POST, 第一次新增数据,第二次也会再次新增,非幂等。
PUT, 第一次更新数据,第二次不会再次更新,幂等。
PATCH,第一次更新数据,第二次不会再次更新,非幂等。
DELTE,第一次删除数据,第二次不在再删除,幂等。
什么是RPC?
RPC是指远程过程调用,也就是说两台服务器A,B,一个应用部署在A服务器上,
想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。


RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
Http和Https的区别?
端口:
  Http: 80端
  https: 443端口


流程:
  自定义证书
    服务端:创建一对证书
    客户端:必须携带证书
  购买证书
    服务端: 创建一对证书,。。。。
    客户端: 去机构获取证书,数据加密后发给咱们的服务单
    证书机构:公钥给改机构

HTTP , 明文传输

HTTPS,为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL协议,

SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密
为什么要使用django rest framework框架?
在编写接口时可以不使用django rest framework框架,

如果不使用:也可以做,那么就可以django的CBV来实现,开发者编写的代码会更多一些。

如果使用: 内部帮助我们提供了很多方便的组件,我们通过配置就可以完成相应操作,如:
- 序列化,可以做用户请求数据校验+queryset对象的序列化称为json
- 解析器,获取用户请求数据request.data,会自动根据content-type请求头的不能对数据进行解析
- 分页,将从数据库获取到的数据在页面进行分页显示。
还有其他:
- 认证
- 权限
- 访问频率控制
- ...
django rest framework框架中都有那些组件?
- 路由,自动帮助开发者快速为一个视图创建4个url
www.oldboyedu.com/api/v1/student/$
www.oldboyedu.com/api/v1/student(?P<format>\w+)$

www.oldboyedu.com/api/v1/student/(?P<pk>\d+)/$
www.oldboyedu.com/api/v1/student/(?P<pk>\d+)(?P<format>\w+)$

- 版本处理
- 问题:版本都可以放在那里?
- url
- GET
- 请求头
- 认证
- 问题:认证流程?
APIView的dispatch方法会把request重新封装,加入了解析器和认证 ,
并且会进行版本解析,用户认证,权限认证,和频率认证,认证时候执行request的静态方法user,返回值可以有三种
- None , 匿名用户,- 异常 ,认证失败,抛元组,元组会赋值给request的user和auth属性
ps:三种返回值分别是?
- (user,auth),认证成功
- None , 匿名用户
- 异常 ,认证失败

- 权限
- 权限是否可以放在中间件中?以及为什么?

- 访问频率的控制
- 匿名用户可以真正的防止?无法做到真正的访问频率控制,只能把小白拒之门外。
如果要封IP,使用防火墙来做。

- 登录用户可以通过用户名作为唯一标示进行控制,如果有人注册很多账号,也无法防止。

- 视图

- 解析器 ,根据Content-Type请求头对请求体中的数据格式进行处理。request.data

- 分页

- 序列化
- 序列化
- source
- 定义方法
- 请求数据格式校验

- 渲染器
django rest framework框架中的视图都可以继承哪些类?
a. 继承 APIView
这个类属于rest framework中顶层类,内部帮助我们实现了只是基本功能:认证、权限、频率控制,但凡是数据库、分页等操作都需要手动去完成,比较原始。



class GenericAPIView(APIView)

def post(...):
pass



b. 继承 GenericViewSet(ViewSetMixin, generics.GenericAPIView)
如果继承它之后,路由中的as_view需要填写对应关系 .as_view({'get':'list','post':'create'})
在内部也帮助我们提供了一些方便的方法:
- get_queryset
- get_object
- get_serializer

注意:要设置queryset字段,否则会跑出断言的异常。
# 只提供增加功能
class TestView(GenericViewSet):
serializer_class = XXXXXXX

def create(self,*args,**kwargs):
pass # 获取数据并对数据进行操作


c. 继承
- ModelViewSet
- mixins.CreateModelMixin,GenericViewSet
- mixins.CreateModelMixin,DestroyModelMixin,GenericViewSet

对数据库和分页等操作不用我们在编写,只需要继承相关类即可。

示例:只提供增加功能
class TestView(mixins.CreateModelMixin,GenericViewSet):
serializer_class = XXXXXXX


类的继承关系
简述 django rest framework框架的认证流程。
9. 认证流程?
- 如何编写?写类并实现authticate
- 方法中可以定义三种返回值:
- (user,auth),认证成功
- None , 匿名用户
- 异常 ,认证失败
- 流程:
- dispatch
- 再去request中进行认证处理
django rest framework如何实现的用户访问频率控制?
10. 访问频率控制
- 匿名用户,根据用户IP或代理IP作为标识进行记录,为每一个用户在redis中创建一个列表
{
throttle_1.1.1.1:[1526868876.497521,152686885.497521...]
throttle_1.1.1.2:[1526868876.497521,152686885.497521...]
throttle_1.1.1.3:[1526868876.497521,152686885.497521...]
throttle_1.1.1.4:[1526868876.497521,152686885.497521...]
throttle_1.1.1.5:[1526868876.497521,152686885.497521...]
}

每个用户再来访问时,需要先去记录中剔除以及过期时间,再根据列表的长度判断是否可以继续访问。

如何封IP:在防火墙中进行设置
- 注册用户,根据用户名或邮箱进行判断。
{
throttle_xxxx1:[1526868876.497521,152686885.497521...]
throttle_xxxx2:[1526868876.497521,152686885.497521...]
throttle_xxxx3:[1526868876.497521,152686885.497521...]
throttle_xxxx4:[1526868876.497521,152686885.497521...]

}

每个用户再来访问时,需要先去记录中剔除以及过期时间,再根据列表的长度判断是否可以继续访问。

1分钟:40次
Flask框架的优势?
和Django相比的话

flask: 微型框架、可扩展强,如果开发简单程序使用flask比较快速,

如果实现负责功能就需要引入一些组件:flask-session/flask-SQLAlchemy/wtforms/flask-migrate/flask-script/blinker

一、整体设计方面
首先,两者都是非常优秀的框架。整体来讲,两者设计的哲学是区别最大的地方。Django提供一站式的解决方案,从模板、ORM、Session、Authentication等等都分配好了,连app划分都做好了,总之,为你做尽量多的事情,而且还有一个killer级的特性,就是它的admin,配合django-suit,后台就出来了,其实最初Django就是由在新闻发布公司工作的人设计的。Flask只提供了一些核心功能,非常简洁优雅。它是一个微框架,其他的由扩展提供,但它的blueprint使它也能够很方便的进行水平扩展。
二、路由设计
Django的路由设计是采用集中处理的方法,利用正则匹配。Flask也能这么做,但更多的是使用装饰器的形式,这个有优点也有缺点,优点是读源码时看到函数就知道怎么用的,缺点是一旦源码比较长,你要查路由就不太方便了,但这也促使你去思考如何更合理的安排代码。
三、应用模块化设计
Django的模块化是集成在命令里的,也就是说一开始Django的目标就是为以后玩大了做准备的。每个都是一个独立的模块,为以后的复用提供了便利。Flask通过Blueprint来提供模块化,自己对项目结构划分成不同的模块进行组织。
四、配置
Django的配置主要还是靠settings.py来做,当然为了Development和Production环境分离,还有一些方法来处理配置。Flask的配置很灵活,有多种方法配置,不同环境的配置也非常方便。
五、文档
两者都提供了详尽的文档,Flask的文档风格很受我个人喜好,Django的文档也非常优秀,当时用学Django时,就是只看了Django的文档。
六、社区
Django社区很大,各种插件很齐全,大部分情况下你都能找到你想要的。Flask起步晚,但社区也不小,之前有一次看在github上的star数,两个相差并不远,说明越来越多的人关注它,虽然插件没那么全,但常用的还都是有的,而且质量都比较高。
Flask框架依赖组件?
Flask依赖两个外部库:
Jinja2模板引擎
Werkzeng WSGI工具集。
Flask蓝图的作用?
当项目很大的时候,蓝图用于为应用提供目录划分:

将不同的功能 模块化;
构建大型的应用;
优化项目结构;
增强可读性,易于维护;
列举使用过的Flask第三方组件?
- flask-session ------>将原来保存在cookie中的session数据,放到redis/memcache/文件/数据库中。
- flask-sqlalchemy
- flask-migrate
- flask-script
- DBUtils ------>数据库连接池 #下面两个也是公共的
- wtforms ------>做表单验证+生成HTML标签
- 自定义 Auth,参考:flask-login组件

》》》
第三方:
- Flask组件:
- flask-session
- flask-SQLAlchemy
- flask-migrate
- flask-script
- blinker
- 公共组件:
- wtforms
- dbutile
- sqlalchemy
- 自定义Flask组件
- auth ,参考flask-login组件
》》》
简述Flask上下文管理流程?
- 前提:记得不太清除了,应该是xxx; 前两天恰好刚看的。
- 流程:
- 请求刚进来,RequestContext(request,session)、AppContext(app,g) -> LocalStack -> Local
- 视图处理,LocalProxy -> 偏函数 -> LocalStack -> Local
- 请求结束,sava_session -> LocalStack.pop()

白话:
我这个上下文流程分为三个阶段,首先请求刚进来把request、session封装在requestcontext中,把app和g封装在appcontext中,然后通过localstark把对象推送放到local中存起来,这就是一个简单过程;
第二点,当视图处理要去取值的时候,通过localproxy的执行偏函数来调用localstark,在通过llocalstark把之前放到local中的requestcontext对象再取出来。
第三点,请求结束,pop一下就可以。
Flask中的g的作用?
Flask中的g的作用?
可以认为是一次周期内的一个全局变量,但是它又不是全局变量,只能在一次请求周期内有效。

应用场景:
如果放在flask中,权限判断是在before request中来做的,做完权限之后,要传给视图函数,因为flask不是通过参数传的,所以要么是用g要么是封装在before request的权限中,就这两个途径。可以模仿django的认证功能,在flask中也这么写,写到权限中,认证成功之后,让它g.user或者g.token分别等于某某某,在视图函数中g.user就能获取到当前登录用户了,总的来说就是写flask-api认证的时候,就可以用g来做。
Flask中上下文管理主要涉及到了那些相关的类?并描述类主要作用?
local/localstark/localproxy/request context app context

Local : 他的实例数据隔离的对象

LocalStack : 通过此类实例来操作Local对象

RequestContext : 封装数据

LocalProxy : 通过此类中的方法来读写request,session
为什么要Flask把Local对象中的的值stack 维护成一个列表?
是为了构建成一个栈,为了是 可以做到“线程”间的数据隔离。

local是一个字典,而它里面的key就是每一个对象的唯一标识,一开始使用线程的getagent(这个不清楚)来做的,后来用getcurrent来做的,key就是satrk,里面是一个列表,只有写离线脚本且多app应用的情况下,才能遇到列表中多放几个值。
ps:在web运行的时候,列表中永远只有一个元素。
Flask中多app应用是怎么完成?
多APP应用本质上是对url的处理和分发

使用DispatcherMiddleware模块来完成


from flask import Flask
from werkzeug.wsgi import DispatcherMiddleware
from werkzeug.serving import run_simple

app01 = Flask('app01')
app02 = Flask('app02')

@app01.route('/login')
def login():
return 'app01.login'

@app02.route('/index')
def index():
return 'app02.index'


dm = DispatcherMiddleware(app01,{
'/app02': app02,
})

if __name__ == '__main__':
run_simple('localhost', 5000,dm)
在Flask中实现WebSocket需要什么组件?
gevent-websocket
wtforms组件的作用?
生成表单字符串,以及数据格式验证

WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证。
https://www.cnblogs.com/big-handsome-guy/p/8552079.html
https://www.cnblogs.com/liuwei0824/p/8330985.html
Flask框架默认session处理机制?
加密后存在cookie中

Flask的默认session利用了Werkzeug的SecureCookie,把信息做序列化(pickle)后编码(base64),
放到cookie里了。 过期时间是通过cookie的过期时间实现的。 为了防止cookie内容被篡改,
session会自动打上一个叫session的hash串,这个串是经过session内容、SECRET_KEY计算出来的,
看得出,这种设计虽然不能保证session里的内容不泄露,但至少防止了不被篡改
解释Flask框架中的Local对象和threading.local对象的区别?
自定义Local对象 作用:为每个线程(协程)开辟一块空间进行数据存储。
threading.local 作用:为每个线程开辟一块空间进行数据存储。
local对象比threading.local粒度更细

a. threading.local
作用:为每个线程开辟一块空间进行数据存储。

问题:自己通过字典创建一个类似于threading.local的东西。
storage={
4740:{val:0},
4732:{val:1},
4731:{val:3},
...
}

b. 自定义Local对象
作用:为每个线程(协程)开辟一块空间进行数据存储。

try:
from greenlet import getcurrent as get_ident
except Exception as e:
from threading import get_ident

from threading import Thread
import time

class Local(object):

def __init__(self):
object.__setattr__(self,'storage',{})

def __setattr__(self, k, v):
ident = get_ident()
if ident in self.storage:
self.storage[ident][k] = v
else:
self.storage[ident] = {k: v}

def __getattr__(self, k):
ident = get_ident()
return self.storage[ident][k]

obj = Local()

def task(arg):
obj.val = arg
obj.xxx = arg
print(obj.val)

for i in range(10):
t = Thread(target=task,args=(i,))
t.start()
Flask中 blinker 是什么?
81. Flask中 blinker 是什么?
Blinker 是一个基于Python的强大的信号库,它既支持简单的对象到对象通信,
也支持针对多个对象进行组播。Flask的信号机制就是基于它建立的。
Flask框架中的信号基于blinker,可以让开发者在flask请求过程中 定制一些用户行为执行。
在请求前后,模板渲染前后,上下文前后,异常 的时候
http://www.cnblogs.com/big-handsome-guy/p/8551973.html
SQLAlchemy中的 session和scoped_session 的区别?
session
无法提供线程共享功能,所以在开发时要注意,要给每个线程都创建自己的session
scoped_session
优点:支持线程安全,为每个线程都创建一个session:
两种方式:通过本地线程Threading.Local()和创建唯一标识的方法(参考flask请求源码)
实际两种方式原理都是一样的都是第一种,只是第二种将session放到了本地线程中,为每一个进程都设置了一个session,实现了线程安全
>>
使用scoped_session的目的主要是为了线程安全。
scoped_session类似单例模式,当我们调用使用的时候,会先在Registry里找找之前是否已经创建session了。
要是有,就把这个session返回。
要是没有,就创建新的session,注册到Registry中以便下次返回给调用者。
这样就实现了这样一个目的:在同一个线程中,call scoped_session 的时候,返回的是同一个对象
https://www.cnblogs.com/geeklove01/p/8179220.html
https://www.cnblogs.com/lianxuebin/p/8664401.html
SQLAlchemy如何执行原生SQL?
sqlalchemy是基于python实现的orm框架

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

engine = create_engine('mysql://root:*****@127.0.0.1/database?charset=utf8')
DB_Session = sessionmaker(bind=engine)
session = DB_Session()
session.execute('alter table mytablename drop column mycolumn ;')

https://www.cnblogs.com/franknihao/p/7268752.html
ORM的实现原理?
ORM的全称是Object Relational Mapping,即对象关系映射。它的实现思想就是将关系数据库中表的数据映射成为对象,
以对象的形式展现,这样开发人员就可以把对数据库的操作转化为对这些对象的操作。
因此它的目的是为了方便开发人员以面向对象的思想来实现对数据库的操作。

对象关系映射
类 -> 表
对象 -> 记录(一行数据)

当有了对应关系之后,不再需要编写SQL语句,取而代之的是操作:类、对象。
根据对象和类 通过字符串格式化 转化成sql语句
create 转化成 inscrt into 等

ORM解决的主要问题是对象关系的映射。域模型和关系模型分别是建立在概念模型的基础上的。域模型是面向对象的,而关系模型是面向关系的。一般情况下,一个持久化类和一个表对应,类的每个实例对应表中的一条记录,类的每个属性对应表的每个字段。
DBUtils模块的作用?
使用DBUtils模块
两种使用模式:
为每个线程创建一个连接,连接不可控,需要控制线程数
创建指定数量的连接在连接池,当线程访问的时候去取,如果不够了线程排队,直到有人释放。平时建议使用这种!
https://www.cnblogs.com/ArmoredTitan/p/Flask.html

>>>
Flask使用DBUtils模块连接数据库

Flask连接数据库

数据库连接池:
Django使用:django ORM(pymysql/MySqldb)
Flask/其他使用:
-原生SQL
-pymysql(支持python2/3)
-MySqldb(支持python2)
-SQLAchemy(ORM)

原生SQL
需要解决的问题:
-不能为每个用户创建一个连接
-创建一定数量的连接池,如果有人来

使用DBUtils模块
两种使用模式:
为每个线程创建一个连接,连接不可控,需要控制线程数
创建指定数量的连接在连接池,当线程访问的时候去取,如果不够了线程排队,直到有人释放。平时建议使用这种!!!
以下SQLAlchemy的字段是否正确?如果不正确请更正:

from datetime import datetime
from sqlalchemy.ext.declarative
import declarative_base
from sqlalchemy import Column, Integer, String, DateTime

Base = declarative_base()
class UserInfo(Base):
__tablename__ = 'userinfo'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(64), unique=True)
ctime = Column(DateTime, default=datetime.now())
###错误地方:ctime字段中的参数应该为default=datetime.now, now后面不应该加括号.如果加了,字段不会随时更新
SQLAchemy中如何为表设置引擎和字符编码?
sqlalchemy设置编码字符集一定要在数据库访问的URL上增加charset=utf8,否则数据库的连接就不是utf8的编码格式
eng = create_engine('mysql://root:root@localhost:3306/test2?charset=utf8',echo=True)
SQLAchemy中如何设置联合唯一索引?
UniqueConstraint 设置联合唯一索引
https://www.cnblogs.com/jasonwang-2016/p/5980237.html
简述Tornado框架的特点。
Tornado的独特之处在于其所有开发工具能够使用在应用开发的任意阶段以及任何档次的硬件资源上。而且,完整集的Tornado工具可以使开发人员完全不用考虑与目标连接的策略或目标存储区大小。Tornado 结构的专门设计为开发人员和第三方工具厂商提供了一个开放环境。已有部分应用程序接口可以利用并附带参考书目,内容从开发环境接口到连接实现。Tornado包括强大的开发和调试工具,尤其适用于面对大量问题的嵌入式开发人员。这些工具包括C和C++源码级别的调试器,目标和工具管理,系统目标跟踪,内存使用分析和自动配置. 另外,所有工具能很方便地同时运行,很容易增加和交互式开发。
简述Tornado框架中Future对象的作用?
简单来说future对象检测多个请求的状态 如果请求完成 调用对应的回调函数

def done(self):

Future的_result成员是否被设置
def result(self, timeout=None):

获取Future对象的结果
def add_done_callback(self, fn):

添加一个回调函数fn给Future对象。如果这个Future对象已经done,则直接执行fn,否则将fn加入到Future类的一个成员列表中保存。
def _set_done(self):

一个内部函数,主要是遍历列表,逐个调用列表中的callback函数,也就是前面add_done_calback加如来的。
def set_result(self, result):

给Future对象设置result,并且调用_set_done。也就是说,当Future对象获得result后,所有add_done_callback加入的回调函数就会执行。
Tornado框架中如何编写WebSocket程序?
https://www.cnblogs.com/aguncn/p/5665916.html
Tornado中静态文件是如何处理的?如: <link href="{{static_url("commons.css")}}" rel="stylesheet" />
如: <link href="{{static_url("commons.css")}}" rel="stylesheet" />
处理方法:
static_path = os.path.join(os.path.dirname(__file__), "static") #这里增加设置了静态路径
另外一个修改就是在实例化 tornado.web.Application() 的时候,在参数中,出了有静态路径参数 static_path ,还有一个参数设置 debug=True

https://blog.csdn.net/hqzxsc2006/article/details/72833012
Tornado操作MySQL使用的模块?
Tornado-MySQL
torndb是一个轻量级的基于MySQLdb封装的一个模块,从tornado3.0版本以后,其已经作为一个独立模块发行了。torndb依赖于MySQLdb模块,因此,在使用torndb模块时,要保证系统中已经有MySQLdb模块。
Tornado操作redis使用的模块?
tornado-redis
https://blog.csdn.net/guoqianqian5812/article/details/68587921
简述Tornado框架的适用场景?
操作io的时候
》》》》
Tornado是使用Python编写的一个强大的、可扩展的Web服务器。它在处理严峻的网络流量时表现得足够强健,但却在创建和编写时有着足够的轻量级,并能够被用在大量的应用和工具中。

我们现在所知道的Tornado是基于Bret Taylor和其他人员为FriendFeed所开发的网络服务框架,当FriendFeed被Facebook收购后得以开源。不同于那些最多只能达到10,000个并发连接的传统网络服务器,Tornado在设计之初就考虑到了性能因素,旨在解决C10K问题,这样的设计使得其成为一个拥有非常高性能的框架。此外,它还拥有处理安全性、用户验证、社交网络以及与外部服务(如数据库和网站API)进行异步交互的工具。
https://www.cnblogs.com/luotianshuai/p/5482612.html
git常见命令作用:
git init,初始化,表示即将对当前文件夹进行版本控制。
git status,查看Git当前状态,如:那些文件被修改过、那些文件还未提交到版本库等。
git add 文件名,将指定文件添加到版本库的暂存状态。
git commit -m '提交信息',将暂存区的文件提交到版本库的分支。
git log,查看提交记录,即:历史版本记录
git pull:从其他的版本库
git push:将本地commit的代码更新到远程版本库中
git stash 将当前工作区所有修改过的内容存储到“某个地方”,将工作区还原到当前版本未修改过的状态
git stash list 查看“某个地方”存储的所有记录
git stash clear 清空“某个地方”
git stash pop 将第一个记录从“某个地方”重新拿到工作区(可能有冲突)
git stash apply 编号, 将指定编号记录从“某个地方”重新拿到工作区(可能有冲突)
git stash drop 编号,删除指定编号的记录

git branch 分支名称 创建分支
git checkout 分支名称 切换分支
git branch -m 分支名称 创建并切换到指定分支
git branch 查看所有分支
git branch -d 分支名称 删除分支
git merge 分支名称 将指定分支合并到当前分支
简述以下git中stash命令作用以及相关其他命令。
stash用于将工作区发生变化的所有文件获取临时存储在“某个地方”,将工作区还原当前版本未操作前的状态;
stash还可以将临时存储在“某个地方”的文件再次拿回到工作区。
git stash 将当前工作区所有修改过的内容存储到“某个地方”,将工作区还原到当前版本未修改过的状态
git stash list 查看“某个地方”存储的所有记录 git stash clear 清空“某个地方”
git stash pop 将第一个记录从“某个地方”重新拿到工作区(可能有冲突)
git stash apply 编号, 将指定编号记录从“某个地方”重新拿到工作区(可能有冲突)
git stash drop 编号,删除指定编号的记录
git 中 merge 和 rebase命令 的区别。
git merge 分支名称 将指定分支合并到当前分支
git rebase 分支名称 合并+将提交记录合并到一条主线=> 提交记录整洁
公司如何基于git做的协同开发?
给每个人创建一个分支 各自写自己的代码 互不干扰
经过代码review后 在合并
如何基于git实现代码review?
创建一个专门用于代码review的分支 代码review后删除
》》》》。
https://blog.csdn.net/maray/article/details/50206927
操作过程
创建临时用于review的分支
git checkout -b expr_type_ctx
查看remote分支,确认review会发送到哪里

git remote -v
如果没有指向remote,可以人肉设定:
git remote set-url origin [email protected]:raywill/mycode.git
3 将remote最新代码拉取到本地

git pull
4 在remote创建一个分支,并将本地代码提交到这个分支。

git push origin expr_type_ctx
执行成功后,就可以去web上拿diff,让别人做review了。
一切搞定,删除这个临时分支

git push origin :expr_type_ctx
参考资料:

git远程分支
Future Works

探索以Merge Request方式进行代码提交
git如何实现v1.0 、v2.0 等版本的管理?
git log,查看提交记录,即:历史版本记录
回滚到指定版本: git reset --hard 6c439d2fd0d943f36f3ee84e158ff86b052961d2

git reflog 可以查看所有分支的所有操作记录(包括(包括commit和reset的操作),包括已经被删除的commit记录,git log则不能察看已经删除了的commit记录

回滚后 后悔再想回到之前最新的版本:git reset --hard 0972f4b
什么是gitlab?
GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的web服务。
github和gitlab的区别?
先说一下相同点,二者都是基于web的Git仓库,在很大程度上GitLab是仿照GitHub来做的,它们都提供了分享开源项目的平台,为开发团队提供了存储、分享、发布和合作开发项目的中心化云存储的场所。

GitHub作为开源代码库及版本控制系统,拥有超过900万的开发者用户,目前仍然是最火的开源项目托管系统。GitHub同时提供公共仓库和私有仓库,但如果要使用私有仓库,是需要付费的。

而GitLab解决了这个问题,你可以在上面创建私人的免费仓库。

GitLab让开发团队对他们的代码仓库拥有更多的控制,相比于GitHub,它有不少的特色:

允许免费设置仓库权限;允许用户选择分享一个project的部分代码;允许用户设置project的获取权限,进一步的提升安全性;可以设置获取到团队整体的改进进度;通过innersourcing让不在权限范围内的人访问不到该资源。

从代码私有性方面来看,有时公司并不希望员工获取到全部的代码,这个时候GitLab无疑是更好的选择。但对于开源项目而言,GitHub依然是代码托管的首选。
104如何为github上牛逼的开源项目贡献代码?
fork 功能 把代码fork到自己仓库 然后从自己仓库获取代码并编辑提交
创建并提交一个pull request,然后等待原作者是否同意这个pull request,如果同意那么在作者的源代码中就会出现自己贡献的代码
git中 .gitignore文件的作用?
.gitignore”文件,这个文件的作用就是告诉Git哪些文件不需要添加到版本管理中
什么是敏捷开发?
敏捷开发(AD:Agile Development )以用户的需求进化为核心,采用迭代、循序渐进的方法进行软件开发。
在敏捷开发中,软件项目在构建初期被切分成多个子项目,各个子项目的成果都经过测试,具备可视、
可集成和可运行使用的特征。换言之,就是把一个大项目分为多个相互联系,但也可独立运行的小项目,并分别完成,
在此过程中软件一直处于可使用状态
简述 jenkins 工具的作用?
Jenkins其实就是一个工具,这个工具的作用就是调用各种其他的工具来达成你的目的。
公司如何实现代码发布?
1、开发人员提交代码更新,主要提交的字段包括“更新理由”,“svn代码路径”;
2、后端收到请求后,把此数据插入到数据库,标记此更新单为“等待预发布环境更新”的状态;
3、后台进程定时查询是否有等待预发布环境更新的更新单,如果有,读取svn路径,执行svn up更新代码操作,并标记此更新单为“预发布环境已更新,等待完成测试”;
4、开发人员或者测试人员通过预发布环境的域名来测试功能是否正常,如果不正常,作代码修改后提交svn,再到web发布后台点击“返回修改”,对svn路径或者不做任何修改再点击“重新提交”,然后更新单又一次回到”等待预发布环境更新“状态。循环3、4步骤,直至预发布环境测试通过为止;
5、在确认测试通过后,开发人员点击”测试通过“,这时更新单进入”等待审核状态“;
6、负责人确认可以发布后,点击”审批“按钮,这时更新单进入”审核通过,等待执行发布操作“的状态。这时,开发人员得到发布代码的授权;
7、开发人员点击”发布代码“按钮,更新单进入”已执行发布,等待系统完成发布“状态;
8、后台进程查询状态为”已执行发布,等待系统完成发布“的更新单,执行git发布命令。git命令大概为,进入预发布代码目录,执行git add .;git commit -m “更新原因”;git tag 上一次版本号+1,再进入已发布代码的目录,执行git pull同步预发布代码目录的更改。最后调用rsync命令同步代码到生产环境。

http://blog.jobbole.com/110304/
简述 RabbitMQ、Kafka、ZeroMQ的区别?
RabbitMQ
RabbitMQ是使用Erlang编写的一个开源的消息队列,本身支持很多的协议:AMQP,XMPP, SMTP, STOMP,也正因如此,它非常重量级,更适合于企业级的开发。同时实现了Broker构架,这意味着消息在发送给客户端时先在中心队列排队。对路由,负载均衡或者数据持久化都有很好的支持。

Redis
Redis是一个基于Key-Value对的NoSQL数据库,开发维护很活跃。虽然它是一个Key-Value数据库存储系统,但它本身支持MQ功能,所以完全可以当做一个轻量级的队列服务来使用。对于RabbitMQ和Redis的入队和出队操作,各执行100万次,每10万次记录一次执行时间。测试数据分为28Bytes、12Bytes、K和0K四个不同大小的数据。实验表明:入队时,当数据比较小时Redis的性能要高于RabbitMQ,而如果数据大小超过了0K,Redis则慢的无法忍受;出队时,无论数据大小,Redis都表现出非常好的性能,而RabbitMQ的出队性能则远低于Redis。

ZeroMQ
ZeroMQ号称最快的消息队列系统,尤其针对大吞吐量的需求场景。ZeroMQ能够实现RabbitMQ不擅长的高级/复杂的队列,但是开发人员需要自己组合多种技术框架,技术上的复杂度是对这MQ能够应用成功的挑战。ZeroMQ具有一个独特的非中间件的模式,你不需要安装和运行一个消息服务器或中间件,因为你的应用程序将扮演这个服务器角色。你只需要简单的引用ZeroMQ程序库,可以使用NuGet安装,然后你就可以愉快的在应用程序之间发送消息了。但是ZeroMQ仅提供非持久性的队列,也就是说如果宕机,数据将会丢失。其中,Twitter的Storm 0.9.0以前的版本中默认使用ZeroMQ作为数据流的传输(Storm从0.9版本开始同时支持ZeroMQ和Netty作为传输模块)。

ActiveMQ
ActiveMQ是Apache下的一个子项目。 类似于ZeroMQ,它能够以代理人和点对点的技术实现队列。同时类似于RabbitMQ,它少量代码就可以高效地实现高级应用场景。

Kafka/Jafka
Kafka是Apache下的一个子项目,是一个高性能跨语言分布式发布/订阅消息队列系统,而Jafka是在Kafka之上孵化而来的,即Kafka的一个升级版。具有以下特性:快速持久化,可以在O(1)的系统开销下进行消息持久化;高吞吐,在一台普通的服务器上既可以达到0W/s的吞吐速率;完全的分布式系统,Broker、Producer、Consumer都原生自动支持分布式,自动实现负载均衡;支持Hadoop数据并行加载,对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。Kafka通过Hadoop的并行加载机制统一了在线和离线的消息处理。Apache Kafka相对于ActiveMQ是一个非常轻量级的消息系统,除了性能非常好之外,还是一个工作良好的分布式系统。
RabbitMQ如何在消费者获取任务后未处理完前就挂掉时,保证数据不丢失?
设置参数no-ack = False 当消费者处理任务失败的时候
RabbitMQ会重新将该任务添加到队列中 以保证数据不丢失
channel.basic_consume(callback, queue='hello', no_ack=False)
RabbitMQ如何对消息做持久化?
设置参数durable=True 保证在RabbitMQ退出或者crash(死机)了数据仍没有丢失
channel.queue_declare(queue='hello', durable=True) 或者
channel.queueDeclare("queue.persistent.name", true, false, false, null);
关键的是第二个参数设置为true,即durable=true.
RabbitMQ如何控制消息被消费的顺序?
https://blog.csdn.net/varyall/article/details/79111745
以下RabbitMQ的exchange type分别代表什么意思?如:fanout、direct、topic。
Exchange在定义的时候是有类型的,以决定到底是哪些Queue符合条件,可以接收消息
fanout
所有bind到此exchange的queue都可以接收消息
direct
通过routingKey和exchange决定的那个唯一的queue可以接收消息
topic
所有符合routingKey(此时可以是一个表达式)的routingKey所bind的queue可以接收消息
简述 celery 是什么以及应用场景?
Celery是由Python开发的一个简单、灵活、可靠的处理大量任务的分发系统,它不仅支持实时处理也支持任务调度。
http://www.cnblogs.com/wupeiqi/articles/8796552.html
简述celery运行机制。
celery如何实现定时任务?
简述 celery多任务结构目录?
celery中装饰器 @app.task 和 @shared_task的区别?
简述 requests模块的作用及基本使用?
模拟浏览器发送请求
http://www.cnblogs.com/linhaifeng/articles/7785043.html
简述 beautifulsoup模块的作用及基本使用?
解析HTML标签

Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库
http://www.cnblogs.com/linhaifeng/articles/7783586.html
简述 seleninu模块的作用及基本使用?
selenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题

selenium本质是通过驱动浏览器,完全模拟浏览器的操作,比如跳转、输入、点击、下拉等,来拿到网页渲染之后的结果,可支持多种浏览器
http://www.cnblogs.com/linhaifeng/articles/7783599.html
scrapy框架中各组件的工作流程?
#1、生成初始的Requests来爬取第一个URLS,并且标识一个回调函数
第一个请求定义在start_requests()方法内默认从start_urls列表中获得url地址来生成Request请求,默认的回调函数是parse方法。回调函数在下载完成返回response时自动触发

#2、在回调函数中,解析response并且返回值
返回值可以4种:
包含解析数据的字典
Item对象
新的Request对象(新的Requests也需要指定一个回调函数)
或者是可迭代对象(包含Items或Request)

#3、在回调函数中解析页面内容
通常使用Scrapy自带的Selectors,但很明显你也可以使用Beutifulsoup,lxml或其他你爱用啥用啥。

#4、最后,针对返回的Items对象将会被持久化到数据库
通过Item Pipeline组件存到数据库:https://docs.scrapy.org/en/latest/topics/item-pipeline.html#topics-item-pipeline)
或者导出到不同的文件(通过Feed exports:https://docs.scrapy.org/en/latest/topics/feed-exports.html#topics-feed-exports)
http://www.cnblogs.com/linhaifeng/articles/7811861.html
———————————————————————
Scrapy主要包括了以下组件:

引擎(Scrapy)
用来处理整个系统的数据流处理, 触发事务(框架核心)
调度器(Scheduler)
用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址
下载器(Downloader)
用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的)
爬虫(Spiders)
爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面
项目管道(Pipeline)
负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。
下载器中间件(Downloader Middlewares)
位于Scrapy引擎和下载器之间的框架,主要是处理Scrapy引擎与下载器之间的请求及响应。
爬虫中间件(Spider Middlewares)
介于Scrapy引擎和爬虫之间的框架,主要工作是处理蜘蛛的响应输入和请求输出。
调度中间件(Scheduler Middewares)
介于Scrapy引擎和调度之间的中间件,从Scrapy引擎发送到调度的请求和响应。
Scrapy运行流程大概如下:

引擎从调度器中取出一个链接(URL)用于接下来的抓取
引擎把URL封装成一个请求(Request)传给下载器
下载器把资源下载下来,并封装成应答包(Response)
爬虫解析Response
解析出实体(Item),则交给实体管道进行进一步的处理
解析出的是链接(URL),则把URL交给调度器等待抓取
在scrapy框架中如何设置代理(两种方法)?
scrapy自带的代理组件:
from scrapy.downloadermiddlewares.httpproxy import HttpProxyMiddleware
from urllib.request import getproxies
———————————————————————
设置代理本质就是在请求头中加数据
#第一种方法 内置代理
import os
import scrapy
from scrapy.http import Request

class ChoutiSpider(scrapy.Spider):
name = 'chouti'
allowed_domains = ['chouti.com']
start_urls = ['https://dig.chouti.com/']

def start_requests(self):
os.environ['HTTP_PROXY'] = "http://192.168.11.11"
for url in self.start_urls:
yield Request(url=url,callback=self.parse)

def parse(self, response):
print(response)


#os.environ['HTTP_PROXY'] = "http://192.168.11.11" 添加的代理
-------
#第二种方法 自定义中间件


import random
import base64
import six
def to_bytes(text, encoding=None, errors='strict'):
"""Return the binary representation of `text`. If `text`
is already a bytes object, return it as-is."""
if isinstance(text, bytes):
return text
if not isinstance(text, six.string_types):
raise TypeError('to_bytes must receive a unicode, str or bytes '
'object, got %s' % type(text).__name__)
if encoding is None:
encoding = 'utf-8'
return text.encode(encoding, errors)

class MyProxyDownloaderMiddleware(object):
def process_request(self, request, spider):
proxy_list = [
{'ip_port': '111.11.228.75:80', 'user_pass': 'xxx:123'},
{'ip_port': '120.198.243.22:80', 'user_pass': ''},
{'ip_port': '111.8.60.9:8123', 'user_pass': ''},
{'ip_port': '101.71.27.120:80', 'user_pass': ''},
{'ip_port': '122.96.59.104:80', 'user_pass': ''},
{'ip_port': '122.224.249.122:8088', 'user_pass': ''},
]
proxy = random.choice(proxy_list)
if proxy['user_pass'] is not None:
request.meta['proxy'] = to_bytes("http://%s" % proxy['ip_port'])
encoded_user_pass = base64.encodestring(to_bytes(proxy['user_pass']))
request.headers['Proxy-Authorization'] = to_bytes('Basic ' + encoded_user_pass)
else:
request.meta['proxy'] = to_bytes("http://%s" % proxy['ip_port'])

# 配置:
# DOWNLOADER_MIDDLEWARES = {
# # 'xiaohan.middlewares.MyProxyDownloaderMiddleware': 543,
# }
scrapy框架中如何实现大文件的下载?
持久化时:
from twisted.web.client import Agent, getPage, ResponseDone, PotentialDataLoss

from twisted.internet import defer, reactor, protocol
from twisted.web._newclient import Response
from io import BytesIO


class _ResponseReader(protocol.Protocol):

def __init__(self, finished, txresponse, file_name):
self._finished = finished
self._txresponse = txresponse
self._bytes_received = 0
self.f = open(file_name, mode='wb')

def dataReceived(self, bodyBytes):
self._bytes_received += len(bodyBytes)

# 一点一点的下载
self.f.write(bodyBytes)

self.f.flush()

def connectionLost(self, reason):
if self._finished.called:
return
if reason.check(ResponseDone):
# 下载完成
self._finished.callback((self._txresponse, 'success'))
elif reason.check(PotentialDataLoss):
# 下载部分
self._finished.callback((self._txresponse, 'partial'))
else:
# 下载异常
self._finished.errback(reason)

self.f.close()
scrapy中如何实现限速?
http://scrapy-chs.readthedocs.io/zh_CN/1.0/topics/autothrottle.html
scrapy中如何实现暂定爬虫?
有些情况下,例如爬取大的站点,我们希望能暂停爬取,之后再恢复运行。

Scrapy通过如下工具支持这个功能:

一个把调度请求保存在磁盘的调度器
一个把访问请求保存在磁盘的副本过滤器[duplicates filter]
一个能持续保持爬虫状态(键/值对)的扩展
Job 路径
要启用持久化支持,你只需要通过 JOBDIR 设置 job directory 选项。这个路径将会存储 所有的请求数据来保持一个单独任务的状态(例如:一次spider爬取(a spider run))。必须要注意的是,这个目录不允许被不同的spider 共享,甚至是同一个spider的不同jobs/runs也不行。也就是说,这个目录就是存储一个 单独 job的状态信息。
https://scrapy-chs.readthedocs.io/zh_CN/1.0/topics/jobs.html?highlight=item
scrapy中如何进行自定制命令?
在spiders同级创建任意目录,如:commands
在其中创建 crawlall.py 文件 (此处文件名就是自定义的命令)
from scrapy.commands import ScrapyCommand
from scrapy.utils.project import get_project_settings


class Command(ScrapyCommand):

requires_project = True

def syntax(self):
return '[options]'

def short_desc(self):
return 'Runs all of the spiders'

def run(self, args, opts):
spider_list = self.crawler_process.spiders.list()
for name in spider_list:
self.crawler_process.crawl(name, **opts.__dict__)
self.crawler_process.start()
在settings.py 中添加配置 COMMANDS_MODULE = '项目名称.目录名称'
在项目目录执行命令:scrapy crawlall

http://www.cnblogs.com/wupeiqi/articles/6229292.html
scrapy中如何实现的记录爬虫的深度?
class scrapy.contrib.spidermiddleware.depth.DepthMiddleware
DepthMiddleware是一个用于追踪每个Request在被爬取的网站的深度的中间件。 其可以用来限制爬取深度的最大深度或类似的事情。

DepthMiddleware 可以通过下列设置进行配置(更多内容请参考设置文档):

DEPTH_LIMIT - 爬取所允许的最大深度,如果为0,则没有限制。
DEPTH_STATS - 是否收集爬取状态。
DEPTH_PRIORITY - 是否根据其深度对requet安排优先级
scrapy中的pipelines工作原理?
Scrapy 提供了 pipeline 模块来执行保存数据的操作。在创建的 Scrapy 项目中自动创建了一个 pipeline.py 文件,同时创建了一个默认的 Pipeline 类。我们可以根据需要自定义 Pipeline 类,然后在 settings.py 文件中进行配置即可
https://blog.csdn.net/Ahri_J/article/details/72472170
scrapy的pipelines如何丢弃一个item对象?
#引入模块
from scrapy.exceptions import DropItem
class FilePipeline(object):

def process_item(self, item, spider):
print('写入文件',item['href'])

# return item
raise DropItem() #返回值 不在执行后边的pipeline
简述scrapy中爬虫中间件和下载中间件的作用?
作用:请求发送时和下载完成后都要经过下载中间件

所以可以在请求下载前后对请求(加请求头)和下载完成后(html数据)做一些操作

http://www.cnblogs.com/wupeiqi/articles/6229292.html
scrapy-redis组件的作用?
scheduler - 调度器
dupefilter - URL去重规则(被调度器使用)
pipeline - 数据持久化
scrapy-redis组件中如何实现的任务的去重?
1.去重规则通过redis的集合完成,集合的Key为:

key = defaults.DUPEFILTER_KEY % {'timestamp': int(time.time())}
默认配置:
DUPEFILTER_KEY = 'dupefilter:%(timestamp)s'

2.去重规则中将url转换成唯一标示,然后在redis中检查是否已经在集合中存在

from scrapy.utils import request
from scrapy.http import Request

req = Request(url='http://www.cnblogs.com/wupeiqi.html')
result = request.request_fingerprint(req)
print(result) # 8ea4fd67887449313ccc12e5b6b92510cc53675c

PS:
- URL参数位置不同时,计算结果一致;
- 默认请求头不在计算范围,include_headers可以设置指定请求头
scrapy-redis的调度器如何实现任务的深度优先和广度优先?
更改默认配置

# 有引擎来执行:自定义调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.LifoQueue' # 默认使用优先级队列(默认广度优先),

其他:PriorityQueue(有序集合),FifoQueue(列表)、LifoQueue(列表)
SCHEDULER_QUEUE_KEY = '%(spider)s:requests' # 调度器中请求存放在redis中的key
SCHEDULER_SERIALIZER = "scrapy_redis.picklecompat" # 对保存到redis中的数据进行序列化,默认使用pickle
SCHEDULER_PERSIST = True # 是否在关闭时候保留原来的调度器和去重记录,True=保留,False=清空
SCHEDULER_FLUSH_ON_START = False # 是否在开始之前清空 调度器和去重记录,True=清空,False=不清空
# SCHEDULER_IDLE_BEFORE_CLOSE = 10 # 去调度器中获取数据时,如果为空,最多等待时间(最后没数据,未获取到)。
SCHEDULER_DUPEFILTER_KEY = '%(spider)s:dupefilter' # 去重规则,在redis中保存时对应的key chouti:dupefilter
SCHEDULER_DUPEFILTER_CLASS = 'scrapy_redis.dupefilter.RFPDupeFilter' # 去重规则对应处理的类
DUPEFILTER_DEBUG = False


# 深度和优先级相关
DEPTH_PRIORITY = 1
简述 vitualenv 及应用场景?
virtualenv就是用来为一个应用创建一套“隔离”的Python运行环境。
https://www.cnblogs.com/technologylife/p/6635631.html
简述 pipreqs 及应用场景?
pipreqs是通过把项目读取解析后才会生成requirements.txt。requirements.txt中存放着所有的依赖目录
在根据requirements.txt中的目录安装项目的依赖模块
应用:拿到一个项目 想要在自己的电脑上运行 而又不知道 安装依赖的时候
- 项目依赖相关的软件 pip3 install pipreqs
- 生成依赖文件:pipreqs ./
- 安装依赖文件:pip3 install -r requirements.txt
在Python中使用过什么代码检查工具?
1)PyFlakes:静态检查Python代码逻辑错误的工具。
2)Pep8: 静态检查PEP8编码风格的工具。
3)NedBatchelder’s McCabe script:静态分析Python代码复杂度的工具。
Python代码分析工具:PyChecker、Pylint
简述 saltstack、ansible、fabric、puppet工具的作用?
远程批量管理服务器
B Tree和B+ Tree的区别?

https://www.jianshu.com/p/0371c9569736
请列举常见排序并通过代码实现任意三种。
冒泡/选择/插入/快排
https://www.cnblogs.com/Liqiongyu/p/5911613.html
http://www.cnblogs.com/feixuelove1009/p/6143539.html
请列举常见查找并通过代码实现任意三种。
无序查找/二分查找/插值查找
http://www.cnblogs.com/feixuelove1009/p/6148357.html
请列举你熟悉的设计模式?
工厂模式/单例模式等
https://www.cnblogs.com/Liqiongyu/p/5916710.html
有没有刷过leetcode?
刷过刷过刷过
https://leetcode-cn.com/problemset/all/
列举熟悉的的Linux命令。
1. mkdir –p 创建多级目录
2. ls -l 显示详细信息
3. cd change directory 进入到目录中
4. pwd print working directory 显示当前所在位置
5. touch 创建文件 修改文件的时间戳
6. vi 编辑文件
7. cat 显示文件内容
8. cp copy 复制
9. mv move 移动
10. rm 删除文件或目录 -f 强制删除不提示 -r 递归删除目录 慎用
11. find 查找 -type f(file) d(dir) -name 名字
12. grep 过滤 -v 排除
13. head 显示文件的前几行 默认显示文件的前10行 -n2 === -2 显示文件的前2行
14. tail 显示文件的最后几行 默认显示文件的后10行
-n1 === -1 显示文件的最后1行
-f 实时显示文件的更新
15. sed 取行
-n 取消默认输出
-i 修改文件的内容
16. tar 创建解压查看压缩包
17. yum install yum install -y
18. ping baidu.com
公司线上服务器是什么系统?
Linux/Centos
解释 PV、UV 的含义?
PV访问量(Page View),即页面访问量,每打开一次页面PV计数+1,刷新页面也是。
IP访问数指独立IP访问数,计算是以一个独立的IP在一个计算时段内访问网站计算为1次IP访问数。在同一个计算时段内不管这个IP访问多少次均计算为1次。计算时段有以1天为一个计算时段,也有以1个小时为一个计算时段。
UV访问数(Unique Visitor)指独立访客访问数,一台电脑终端为一个访客。
在同一个局域网中对互联网访问时对外通常是同一个IP,如果该局域网中有10台终端在同一个计算时段内访问同一个网站,对该网站的独立IP访问数贡献为1,而不是10。而此时UV访问数则为10。
解释 QPS的含义?
Query Per Second
每秒查询率QPS是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。
uwsgi和wsgi的区别?
WSGI:全称是Web Server Gateway Interface,WSGI不是服务器,python模块,框架,API或者任何软件,只是一种规范,描述web server如何与web application通信的规范。server和application的规范在PEP 3333中有具体描述。要实现WSGI协议,必须同时实现web server和web application,当前运行在WSGI协议之上的web框架有Bottle, Flask, Django。
uwsgi:与WSGI一样是一种通信协议,是uWSGI服务器的独占协议,用于定义传输信息的类型(type of information),每一个uwsgi packet前4byte为传输信息类型的描述,与WSGI协议是两种东西,据说该协议是fcgi协议的10倍快。
uWSGI:是一个web服务器,实现了WSGI协议、uwsgi协议、http协议等。
https://www.jianshu.com/p/679dee0a4193

wsgi 测试用

uwsgi 功能强大 上线用
supervisor的作用?
supervisor管理进程,是通过fork/exec的方式将这些被管理的进程当作supervisor的子进程来启动,所以我们只需要将要管理进程的可执行文件的路径添加到supervisor的配置文件中就好了。此时被管理进程被视为supervisor的子进程,若该子进程异常终端,则父进程可以准确的获取子进程异常终端的信息,通过在配置文件中设置autostart=ture,可以实现对异常中断的子进程的自动重启。
什么是反向代理?
反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。
简述SSH的整个过程。
SSH 为 Secure Shell 的缩写,由 IETF 的网络小组(Network Working Group)所制定;SSH 为建立在应用层基础上的安全协议。SSH 是目前较可靠,专为远程登录会话和其他网络服务提供安全性的协议。利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题。
https://www.jianshu.com/p/33461b619d53
有问题都去那些找解决方案?
知乎 思否
是否有关注什么技术类的公众号?
最近在研究什么新技术?
人工智能,图灵机器人相关,百度语音合成,语音识别
是否了解过领域驱动模型?
Domain-Driven Design
https://www.cnblogs.com/netfocus/archive/2011/10/10/2204949.html

猜你喜欢

转载自www.cnblogs.com/ouyang99-/p/9939183.html