1、为什么学习Python?
机器学习,脚本语言,快速开发
2、通过什么途径学习的Python?
文档,GitHub项目,博客
3、Python和Java、PHP、C、C#、C++等其他语言的对比?
· | Python | PHP |
---|---|---|
流行程度 | 非常流行 | 非常流行 |
框架 | 许多框架 | 较少框架 |
学习 | 易学 | 难学 |
· | Python | Java |
---|---|---|
不同操作系统的兼容性 | 是 | 是 |
跨平台应用 | 否 | 是 |
学习 | 易学 | 难学 |
基于网络的应用 | 否 | 是 |
· | Python | C# |
---|---|---|
简单性 | 是 | 否 |
脚本编写 | 任何环境 | 只在IDE |
库 | 很多个库 | 很少个库 |
性能 | 低 | 是 |
4、简述解释型和编译型编程语言?
编译型语言:
用编译型语言写的程序执行之前,需要一个专门的编译过程,通过编译系统(不仅仅只是通过编译器,编译器只是编译系统的一部分)把高级语言翻译成机器语言(具体翻译过程可以参看下图),把源高级程序编译成为机器语言文件
解释型语言:
使用专门的解释器对源程序逐行解释成特定平台的机器码并立即执行。
5、Python解释器种类以及特点?
CPython:
Cpython,这个解释器是用C语言开发的,所以叫CPython,
在命名行下运行python,就是启动CPython解释器,CPython是使用最广的Python解释器。
IPython:
IPython是基于CPython之上的一个交互式解释器,也就是说,IPython只是在交互方式上有所增强,
但是执行Python代码的功能和CPython是完全一样的,好比很多国产浏览器虽然外观不同,但内核其实是调用了IE。
PyPy:
PyPy是另一个Python解释器,它的目标是执行速度,
PyPy采用JIT技术,对Python代码进行动态编译,所以可以显著提高Python代码的执行速度。
Jython:
Jython是运行在Java平台上的Python解释器,可以直接把Python代码编译成Java字节码执行。
IronPython:
IronPython和Jython类似,只不过IronPython是运行
在微软.Net平台上的Python解释器,可以直接把Python代码编译成.Net的字节码。
6、位和字节的关系?
位(bit):简单来说一位就是一个二进制数
**字节:简单来说就是8个二进制数,即8 bit 就称为一个字节(Byte) **
6、b、B、KB、MB、GB 的关系?
bit就是位,也叫比特位,是计算机表示数据最小的单位
byte就是字节
3.1byte=8bit
4.1byte就是1B
5.一个字符=2字节
6.1KB=1024B
字节就是Byte,也是B
位就是bit也是b
转换关系如下:
1KB=1024B
1B= 8b
7、请至少列举5个 PEP8 规范(越多越好)。
模块命名尽量短小,使用全部小写的方式,可以使用下划线。
包命名尽量短小,使用全部小写的方式,不可以使用下划线。
类的命名使用CapWords的方式,模块内部使用的类采用_CapWords的方式。
异常命名使用CapWords+Error后缀的方式。
全局变量尽量只在模块内有效,类似C语言中的static。实现方法有两种,一是all机制;二是前缀一个下划线。
函数命名使用全部小写的方式,可以使用下划线。
常量命名使用全部大写的方式,可以使用下划线。
类的属性(方法和变量)命名使用全部小写的方式,可以使用下划线。
类的属性有3种作用域public、non-public和subclass API,可以理解成C++中的public、private、protected,non-public属性前,前缀一条下划线。
类的属性若与关键字名字冲突,后缀一下划线,尽量不要使用缩略等其他方式。
为避免与子类属性命名冲突,在类的一些属性前,前缀两条下划线。比如:类Foo中声明__a,访问时,只能通过Foo._Foo__a,避免歧义。如果子类也叫Foo,那就无能为力了。
类的方法第一个参数必须是self,而静态方法第一个参数必须是cls。
编码中考虑到其他python实现的效率等问题,比如运算符‘+’在CPython(Python)中效率很高,都是Jython中却非常低,所以应该采用.join()的方式。
尽可能使用‘is’‘is not’取代‘==’,比如if x is not None 要优于if x
使用基于类的异常,每个模块或包都有自己的异常类,此异常类继承自Exception。
常中不要使用裸露的except,except后跟具体的exceptions。例如
8、通过代码实现如下转换:
二进制转换成十进制:v = “0b1111011”
int("0b1111011",2) = 123
十进制转换成二进制:v = 18
bin(18) = 0b10010
八进制转换成十进制:v = “011”
int('011', 8) = 9
十进制转换成八进制:v = 30
oct(30) = 0o36
十六进制转换成十进制:v = “0x12”
int('ox12',16) =18
十进制转换成十六进制:v = 87
hex(87) = 0x57
9、请编写一个函数实现将IP地址转换成一个整数。
如 10.3.9.12 转换规则为:
10 00001010
3 00000011
9 00001001
12 00001100
再将以上二进制拼接起来计算十进制结果:00001010 00000011 00001001 00001100 = ?
def convert_int(a):
# 转换为4个段的列表
a_list = a.split('.',4)
print(a_list)
# a_list.reverse()
a_str = ''
for i in a_list:
a_tem = bin(int(i))[2:] # 字符串 从元素的索引第2个开始截取字符串
print('a_tem:',a_tem)
if len( a_tem) != 8:
# 在前面加 0
a_str += '0'*(8-len(a_tem))+a_tem
else:
a_str += a_tem
print (a_str)
return int(a_str,2)
def convert_ip(b):
#先转换为二进制
b_tem = bin(int(b))[2:]
b_str = ''
# 将所有的 0 补齐
if len(b_tem) != 32:
b_str += '0' * (32 - len(b_tem)) + b_tem
#切片处理
b1 = b_str[0:8]
b2 = b_str[8:16]
b3 = b_str[16:24]
b4 = b_str[24:]
b_out= str(int(b1,2))+'.'+str(int(b2 ,2))+'.'+str(int(b3,2))+'.'+str(int(b4,2))
return b_out
if __name__ == '__main__':
a = raw_input('您需要将IP转为整型,请输入IP:\n')
b = raw_input('您需要将整型转为IP,请输入整型:\n')
a_c = convert_int(a)
b_c = convert_ip(b)
print(a_c)
print(b_c)
10、python递归的最大层数?
一般来说是998层
python专门设置的一种机制用来防止无限递归造成Python溢出崩溃, 最大递归次数是可以重新调整的
sys.setrecursionlimit(1500) # set the maximum depth as 1500
11、求结果:
v1 = 1 or 3 ---1
v2 = 1 and 3 ---3
v3 = 0 and 2 and 1 ---0
v4 = 0 and 2 or 1 ---1
v5 = 0 and 2 or 1 or 4 ---1
v6 = 0 or Flase and 1 报错 --改成bool(False)结果为FALSE
11、ascii、unicode、utf-8、gbk 区别?
ascii:
A:00000010 8位 一个字节
unicode:
A:00000000 00000001 00000010 00000100 32位 四个字节
中:00000000 00000001 00000010 00000100 32位 四个字节
utf-8:
A:00000110 8位 一个字节
中:00000010 00000110 16位 两个字节
gbk:
A:00000110 8位 一个字节
中:00000010 00000110 16位 两个字节
1,各个编码之间的二进制,是不能互相识别的,会产生乱码。
2,文件的存储,传输,不能是unicode (只能是utf-8 utf-16 gbk gbk2312 ascii等)
==============================================================
python3:
str 在内存中是Unicode编码。
bytes类型
对于英文:
str:表现形式:s = 'twiss'
编码方式:010101010 unicode
bytes:表现形式:s = b'twiss'
编码方式:000101010 utf-8 gbk。。。。
对于中文:
str:表现形式:s = '北京'
编码方式:010101010 unicode
bytes: 表现形式:s = b' x\e91\e91\e01\e21\e31\e32'
编码方式:000101010 utf-8 gbk。。。。
encode 编码,如何将 str ——> bytes
使用方法: str.encode('utf-8')
decode 解码,如何将 bytes——> str
使用方法: bytes.decode('utf-8')
12、字节码和机器码的区别?
机器码
机器码(machine code),学名机器语言指令,有时也被称为原生码(Native Code),是电脑的CPU可直接解读的数据。
通常意义上来理解的话,机器码就是计算机可以直接执行,并且执行速度最快的代码。
字节码
字节码(Bytecode)是一种包含执行程序、由一序列 op 代码/数据对 组成的二进制文件。字节码是一种中间码,它比机器码更抽象,需要直译器转译后才能成为机器码的中间代码。
总结:字节码是一种中间状态(中间码)的二进制代码(文件)。需要直译器转译后才能成为机器码。
13、三元运算规则以及应用场景?
三元运算符就是在赋值变量的时候,可以直接加判断,然后赋值
三元运算符的功能与'if....else'流程语句一致,它在一行中书写,代码非常精炼,执行效率更高
格式:[on_true] if [expression] else [on_false]
res = 值1 if 条件 else 值2
14、列举 Python2和Python3的区别?
1、print
在python2中,print被视为一个语句而不是一个函数,python3中,print()被视为一个函数
2、整数的除法
在python2中,键入的任何不带小数的数字,将被视为整数的编程类型。比如5/2=2,解决方法:5.0/2.0=2.5
在python3中,整数除法变得更直观 5/2=2.5
3、Unicode
Python 2 默认使用 ASCII 字母表;Python 3 默认使用 Unicode
4、后续发展
Python 2.7 将在 2020 年失去后续的支持,
Python 3 将继续开发更多的功能和修复更多的错误。
15、用一行代码实现数值交换:
a = 1
b =2
答:a, b = b, a
16、Python3和Python2中 int 和 long的区别?
int(符号整数):通常被称为是整数或整数,没有小数点的正或负整数;
long(长整数):无限大小的整数,这样写整数和一个大写或小写的L。
17、xrange和range的区别?
range: 函数说明,range([start,] stop[, step]),根据start与stop指定的范围以及step设定的步长,生成一个列表。
xrange:函数说明,xrange 用法与 range 完全相同,所不同的是生成的不是一个list对象,而是一个生成器。
1、range和xrange都是在循环中使用,输出结果一样。
2、range返回的是一个list对象,而xrange返回的是一个生成器对象(xrange object)。
3、xrange则不会直接生成一个list,而是每次调用返回其中的一个值,内存空间使用极少,因而性能非常好。
注意:Python 3.x已经去掉xrange,全部用range代替。
18、文件操作时:xreadlines和readlines的区别?
二者使用时相同,但返回类型不同,xreadlines返回的是一个生成器,readlines返回的是list
19、列举布尔值为False的常见值?
0 , [ ] , " , ( ) , { }
20、字符串、列表、元组、字典每个常用的5个方法?
# 字符串
words = "today is a wonderfulday"
print(words.strip('today')) # 如果strip方法指定一个值的话,那么会去掉这两个值
print(words.count('a')) # 统计字符串出现的次数
print(words.index('is')) # 找下标
print(words.index('z')) # 找下标如果元素不找不到的话,会报错
print(words.find('z')) # 找下标,如果元素找不到的话,返回-1
print(words.replace('day','DAY'))# 字符串替换
#
# # 列表
sample_list = ['a', 1, ('a', 'b')] # 创建列表
sample_list = ['a', 'b', 0, 1, 3] # Python列表操作
value_start = sample_list[0] # 得到列表中的某一个值
end_value = sample_list[-1] # 得到列表中的某一个值
del sample_list[0] # 删除列表的第一个值
sample_list[0:0] = ['sample value'] # 在列表中插入一个值
# 元组
#元组也是一个list,他和list的区别是元组的元素无法修改
tuple1 = (2, 3, 4, 5, 6, 4, 7)
print(type(tuple1))
print(tuple1[:7])
print(tuple1[: 5: -1])
for i in range(6):
print(tuple1[i])
for i in tuple1:
print(i)
# 字典
D.get(key, 0) # 同dict[key],多了个没有则返回缺省值,0。[]没有则抛异常
D.has_key(key) # 有该键返回TRUE,否则FALSE
D.keys() # 返回字典键的列表
D.clear() # 清空字典,同del dict
D.copy() # 拷贝字典
21、lambda表达式格式以及应用场景?
lambda表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数。
add = lambda x, y : x+y
print(add(1,2)) # 结果为3
应用在函数式编程中 应用在闭包中
22、pass的作用?
1、空语句 do nothing
2、保证格式完整,保证语义完整
3、占位语句
23、*arg和**kwarg作用
*args:可以理解为只有一列的表格,长度不固定。
**kwargs:可以理解为字典,长度也不固定。
1、函数调用里的*arg和**kwarg:
(1) *arg:元组或列表“出现”
**kwarg:字典“出没”
(2)分割参数
2、函数定义时传的*arg /**kwarg:
(1)接收参数
24、is和==的区别
is是对比地址(id),==是对比值
25、简述Python的深浅拷贝以及应用场景?
浅拷贝:copy.copy 深拷贝:copy.deepcopy
浅拷贝指仅仅拷贝数据集合的第一层数据, 深拷贝指拷贝数据集合的所有层
主要应用在字符串,数字的深浅拷贝
26、Python垃圾回收机制?
Python的GC模块主要运用了“引用计数”(reference counting)来跟踪和回收垃圾。在引用计数的基础上,还可以通
过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用的问题。通过“分代回收”(generation collection)以空间换取时间来进一步提高垃圾回收的效率。
27、Python的可变类型和不可变类型?
Python的每个对象都分为可变和不可变
可变:列表、字典 不可变:数字、字符串、元组
28、求结果:
v = dict.fromkeys(['k1','k2'],[])
v[‘k1’].append(666)
print(v)
{'k1': [666], 'k2': [666]}
v[‘k1’] = 777
print(v)
{'k1': 777, 'k2': [666]}
求结果:
29、列举常见的内置函数?
简单的内置函数
len 求长度
min 求最小值
max 求最大值
sorted 排序
reversed 反向
sum 求和
进制转换
bin 转为二进制
oct 转为八进制
hex 转为十六进制
ord 字符转ASCII码
chr ASCII码字符
高级内置函数
enumerate 返回一个可以枚举的对象,常用于生成可迭代的字典
eval 将字符串的内容当成表达式计算
exec 执行print编译过的字符串
filter 过滤器,第一个参数是函数名,第二个参数为可迭代对象,把函数返回True的参数帅选出来并组成一个列表。
map 同样是过滤,与filter不同的是它得到的是函数的返回值。
zip 将两个对象逐一匹配,常用于生成字典
30、filter、map、reduce的作用?
这里如果用filter的话,说明匿名函数lambda给出的是个筛选条件,从1到19中筛选出奇数来,但这里如果用map的话,就好像变成了它判断对错的条件,只打印true和false。
reduce这样的累加函数,并不是很常用,在python3中已将其从全局空间移除,现被放置在functools的模块里,用之前需要引入 from functools import reduce
31、一行代码实现9*9乘法表
print('\n'.join([' '.join(['%d*%d=%-2d' % (i, j, i * j) for i in range(1, j + 1)]) for j in range(1, 10)]))
还是两个for循环,但是两个for循环被join分割开了,而且join的分割符号,也不一样,这样就可以有空格和错行。‘%-2d’,是为了统一打印格式,使其靠左。
32、如何安装第三方模块?以及用过哪些第三方模块?
$ pip install requests
requests获取URL资源
$ pip install pipreqs
找到项目使用的所有组件和版本
33、至少列举8个常用模块都有那些?
pip、pygame、pyMysql、sys、math、time、os、wxPython
34、re的match和search区别?
re.match()从开头开始匹配string。
re.search()从anywhere 来匹配string。
35、什么是正则的贪婪匹配?
贪婪匹配:正则表达式一般趋向于最大长度匹配,也就是所谓的贪婪匹配
非贪婪匹配:就是匹配到结果就好,就少的匹配字符
默认是贪婪模式;在量词后面直接加上一个问号?就是非贪婪模式
36、求结果:
a. [ i % 2 for i in range(10) ]
b. ( i % 2 for i in range(10) )
a = [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
b = 是生成器表达式 (generator)
37、求结果:
a. 1 or 2
b. 1 and 2
c. 1 < (2==2)
d. 1 < 2 == 2
a = 1
b = 2
c = False
d = True
38、def func(a,b=[]) 这种写法有什么坑?
因为b是可变参数,每次调用这个方法b不会每次都初始化为[],而是调用相同的[]。
39、如何实现 “1,2,3” 变成 [‘1’,’2’,’3’] ?
a = "1,2,3"
a.split(',')
40、如何实现[‘1’,’2’,’3’]变成[1,2,3] ?
1、a = ['1', '2', '3'] b = [int(x) for x in a]
2、list(map(lambda x : int(x),a))
41、比较: a = [1,2,3] 和 b = [(1),(2),(3) ] 以及 b = [(1,),(2,),(3,) ] 的区别?
a和b相同,因为只有一个元素的元组需要加,来表示(1,)
b1表示的是列表元素为整数,b2表示的是列表元素是元组
42、如何用一行代码生成[1,4,9,16,25,36,49,64,81,100] ?
[x**2 for x in range(1,11)]
43、一行代码实现删除列表中重复的值 ?
list(set(a))
44、如何在函数中设置一个全局变量 ?
global 变量名
45、logging模块的作用?以及应用场景?
可以通过设置不同的日志等级,在release版本中只输出重要信息,而不必显示大量的调试信息;
print将所有信息都输出到标准输出中,严重影响开发者从标准输出中查看其它数据;
logging则可以由开发者决定将信息输出到什么地方,以及怎么输出;
46、请用代码简答实现stack 。
class Stack(object):
def __init__(self,item=[]):
self.item = []
if len(item):
for i in item:
self.item.append(i)
def push(self,item):
self.item.append(item)
def pop(self):
if self.isempty():
rais exception("stack is empty")
else:
data = self.top()
self.item.pop()
return data
def top(self):
return self.item[-1]
def clear(self):
del self.item
def isempty(self):
return item.size() ==0
def size(self):
return len(self.item)
def showList(self):
print(self.item)
47、常用字符串格式化哪几种?
%、format、f
迭代器理解
迭代是Python最强大的功能之一,是访问集合元素的一种方式。
迭代器是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
迭代器有两个基本的方法:iter() 和 next()。
字符串,列表或元组对象都可用于创建迭代器:
任何实现了__iter__和__next__()方法的对象都是迭代器。__iter__返回迭代器自身,__next__返回容器中的下一个值
实现方法:
class iterdemo():
def __init__(self):
self.number=1
#重写 __iter__方法 说明有可以迭代的能力( iterable)
def __iter__(self):
print("__iter__")
return self
#重写 __next__方法 说明是 迭代器 (iterator)
def __next__(self):
print("__next__")
self.number += 1
return self.number
=================================================
生成器:
生成器是一种特殊的迭代器,它的返回值不是通过return而是用yield
生成器算得上是Python语言中最吸引人的特性之一,生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅。它不需要再像上面的类一样写__iter__()和__next__()方法了,只需要一个yiled关键字。 生成器一定是迭代器(反之不成立)
方式一:
gen =(x+2 for x in range(10))
print(gen)
方式二:
#每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
def number():
number=1
print("number=",number)
yield number
number+=1
print("number=", number)
yield number
number += 1
n = number()#调用一个生成器函数,返回的是一个迭代器对象。
print(n)
结果是: 说明是生成器
如果把yield删除掉
结果是: number= 1
None
说明是普通的函数而已
调用
print(next(n))
print(next(n))
调用2次的结果是:
number= 1
1
number= 2
2
但是再调用一次
print(next(n))就会有异常StopIteration 没有已经没有迭代项了
49、用Python实现一个二分查找的函数。
def binary_search(lis, num):
left = 0
right = len(lis) - 1
while left <= right: #循环条件
mid = (left + right) / 2 #获取中间位置,数字的索引(序列前提是有序的)
if num < lis[mid]: #如果查询数字比中间数字小,那就去二分后的左边找,
right = mid - 1 #来到左边后,需要将右变的边界换为mid-1
elif num > lis[mid]: #如果查询数字比中间数字大,那么去二分后的右边找
left = mid + 1 #来到右边后,需要将左边的边界换为mid+1
else:
return mid #如果查询数字刚好为中间值,返回该值得索引
return -1 #如果循环结束,左边大于了右边,代表没有找到
lis = [11, 32, 51, 21, 42, 9, 5, 6, 7, 8]
print(lis)
lis.sort()
print(lis)
while 1:
num = int(input('输入要查找的数:'))
res = binary_search(lis, num)
print(res)
if res == -1:
print('未找到!')
else:
print('找到!')
2.递归算法
def binary_search(lis, left, right, num):
if left > right: #递归结束条件
return -1
mid = (left + right) / 2
if num < lis[mid]:
right = mid -1
elif num > lis[mid]:
left = mid + 1
else:
return mid
return binary_search(lis, left, right, num)
#这里之所以会有return是因为必须要接收值,不然返回None
#回溯到最后一层的时候,如果没有return,那么将会返回None
lis = [11, 32, 51, 21, 42, 9, 5, 6, 7, 8]
print(lis)
lis.sort()
print(lis)
while 1:
num = int(input('输入要查找的数:'))
res = binary_search(lis, 0, len(lis)-1,num)
print(res)
if res == -1:
print('未找到!')
else:
print('找到!')
50、谈谈你对闭包的理解?
https://blog.csdn.net/Yeoman92/article/details/67636060
在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。
一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。
---------------------
def outer(a):
b = 10
def inner():
print(a+b)
return inner
51、os和sys模块的作用?
os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口;
sys模块负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境。
详细:https://blog.csdn.net/qq_38276669/article/details/83687738
52、如何生成一个随机数?
#python中利用random获取一个0到1的随机浮点数
a = random.random()
print(a)
#python中利用random获取一定范围内的(10到20)的随机浮点数
b = random.uniform(10,20)
print(b)
#python利用random获取一定范围内(10到20)的随机整数
c = random.randint(10,20)
print(c)
#python利用random从列表集合中获取一个随机值
list = [5,'hello',9,'xiong_it',3,'Python']
d = random.choice(list)
print(d)
53、如何使用python删除一个文件?
使用python删除一个文件或文件夹,需要使用os模块。
import os
os.remove(path) # path是文件的路径,如果这个路径是一个文件夹,则会抛出OSError的错误,这时需用用rmdir()来删除
os.rmdir(path) # path是文件夹路径,注意文件夹需要时空的才能被删除
os.unlink('F:\新建文本文档.txt') # unlink的功能和remove一样是删除一个文件,但是删除一个删除一个正在使用的文件会报错。
import os
path = 'F:/新建文本文档.txt' # 文件路径
if os.path.exists(path): # 如果文件存在
# 删除文件,可使用以下两种方法。
os.remove(path)
#os.unlink(path)
else:
print('no such file:%s'%my_file) # 则返回文件不存在
import os
os.removedirs(path) # 递归地删除目录。如果子目录成功被删除,则将会成功删除父目录,子目录没成功删除,将抛异常。
import os
for root, dirs, files in os.walk(top, topdown=False):
for name in files:
os.remove(os.path.join(root, name))
for name in dirs:
os.rmdir(os.path.join(root, name))
另一种方法
import shutil
shutil.rmtree()
54、谈谈你对面向对象的理解?
python面试笔记35
55、Python面向对象中的继承有什么特点?
1:在继承中基类的构造(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。
2:在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数
3:Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找,即先在本类中查找调用的方法,找不到才去基类中找。
如果在继承元组中列了一个以上的类,那么它就被称作“多重继承” 。
私有属性的访问方法:
例子中的 __money就是私有属性,需要用set,get方法进行访问。
56、面向对象深度优先和广度优先是什么?
MRO即方法解析顺序(method resolution order),用于判断子类调用的属性来自于哪个父类。在Python2.3之前,MRO是基于深度优先算法的,自2.3开始使用C3算法,定义类时需要继承object,这样的类称为新式类,否则为旧式类
--------------------------------------------
经典类采用深度优先搜索
class P1:
def foo(self):
print 'p1-foo'
class P2 :
def foo(self):
print 'p2-foo'
def bar(self):
print 'p2-bar'
class C1 (P1,P2):
pass
class C2 (P1,P2):
def bar(self):
print 'C2-bar'
class D(C1,C2):
pass
d = D()
d.foo() # 输出 p1-foo
d.bar() # 输出 p2-bar
实例d调用foo()时,搜索顺序是 D => C1 => P1
实例d调用bar()时,搜索顺序是 D => C1 => P1 => P2
经典类的搜索方式:从左到右,深度优先
---------------------------------------
新式类采用广度优先搜索
class P1(object):
def foo(self):
print 'p1-foo'
class P2(object):
def foo(self):
print 'p2-foo'
def bar(self):
print 'p2-bar'
class C1 (P1,P2):
pass
class C2 (P1,P2):
def bar(self):
print 'C2-bar'
class D(C1,C2):
pass
d=D()
d.foo() # 输出 p1-foo
d.bar() # 输出 c2-bar
实例d调用foo()时,搜索顺序是 D => C1 => C2 => P1
实例d调用bar()时,搜索顺序是 D => C1 => C2
57、面向对象中super的作用?
class Bicycle(object):
def __init__(self, name):
self.name = name
def run(self):
print('我是%s的run方法'%self.name)
class E_Bicycle(Bicycle): # 继承自行车
def __init__(self, name, age):
super().__init__(name) # 调用父类的name属性
self.age = age
def run(self):
super().run() # 调用父类的run方法
print('被主人改装%s年了'%(self.age)
b = Bicycle()
b.run()
e_b = E_Bicycle('电动车', 3)
e_b.run()
---------------------------------------------------
super() 函数是用于调用父类(超类)的一个方法。
super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。
MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。
以下是 super() 方法的语法:
super(type[, object-or-type])
参数
type -- 类。
object-or-type -- 类,一般是 self
Python3.x 和 Python2.x 的一个区别是: Python 3 可以使用直接使用 super().xxx 代替 super(Class, self).xxx :
----------------------------------------
super不是一个关键字,也是不是有函数,他是一个类
super()的作用不是查找父类,而是找MRO列表的上一个类
super()和父类没有任何实质性的关系,只是有时候能调用到父类而已。
在单继承的情况下,super()永远调用的是父类/父对象
super()多用于菱形继承
格式:
super().方法() #python3的格式
functools用于高阶函数:指那些作用于函数或者返回其他函数的函数。通常情况下,只要是可以被当做函数调用的对象就是这个模块的目标。
-------------------------------
partial
首先是partial函数,它可以重新绑定函数的可选参数,生成一个callable的partial对象
update_wrapper
接着是update_wrapper函数,它可以把被封装函数的__name__、__module__、__doc__和 __dict__都复制到封装函数去:
wraps
再有是wraps函数,它将update_wrapper也封装了进来
total_ordering
最后至于total_ordering函数则给予类丰富的排序方法,使用装饰器简化了操作。如果使用必须在类里面定义一个__lt__(),__le__(), __gt__(), 或__ge__()。应该给类添加一个__eq__() 方法。
59、列举面向对象中带爽下划线的特殊方法,如:new、init
类的特殊成员方法
__doc__ :打印类的描述信息
__init__初始化魔术对象,当一个对象被实例化是自动触发
__new__ 当一个对象被实例化前自动触发,通过传递参数判断对象是否被创建或其他
__del__当一个对象没有任何引用是被触发,回收内存
__call__将对象当作函数调用时触发
__module__:表示当前操作的对象在那个模块
__class__:表示当前操作的对象的类是什么
__str__:如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值
60、如何判断是函数还是方法?
什么是函数?什么是方法?
def func():
pass
class Foo(object):
def func(self):
pass
# 执行方式一
# obj = Foo()
# obj.func() # 方法
# 执行方式二
# Foo.func(123) # 函数
from types import FunctionType,MethodType
# obj = Foo()
# print(isinstance(obj.func,FunctionType)) # False
# print(isinstance(obj.func,MethodType)) # True
print(isinstance(Foo.func,FunctionType)) # True
print(isinstance(Foo.func,MethodType)) # False
61、静态方法和类方法区别?
实例方法,类方法,静态方法都可以通过实例或者类调用,只不过实例方法通过类调用时需要传递实例的引用(python 3可以传递任意对象,其他版本会报错)。
三种方法从不同层次上来对方法进行了描述:实例方法针对的是实例,类方法针对的是类,他们都可以继承和重新定义,而静态方法则不能继承,可以认为是全局函数。
62、列举面向对象中的特殊成员以及应用场景
魔术方法 用于在某一时刻调用时
`__str__`魔术方法:
1. 在打印某个对象的时候,会调用这个对象的`__str__`方法,打印这个方法的返回值。
2. 如果在使用`str(obj)`这个函数的时候,也会调用`__str__`方法。
`__repr__`魔术方法:
1. `__repr__`魔术方法是用来表述某个对象在内存中的展示形式。
2. 如果在终端直接输入一个对象,然后按回车,那么将会执行这个对象的`__repr__`方法。
3. 如果你将几个对象扔到一个容器中(比如:列表),那么你在打印这个容器的时候,会依次调用这个容器中的元素的`__repr__`方法。如果没有实现这个`__repr__`方法,那么得到的将是一个`类名+地址`的形式,这种形式的是不好理解的。
`__dict__`魔术属性:
1. 用来获取用户自定义的属性,以及这个属性对应的值。返回的是一个字典。
2. 和`dir`函数做一个区分。`dir`函数返回的是这个对象上拥有的所有属性,包括`Python`内置的属性和用户自己添加的,并且只是获取属性名字,不会获取这个属性对应的值。
63、1、2、3、4、5 能组成多少个互不相同且无重复的三位数
for x in range(1, 5):
for z in range(1, 5):
for i in range(1, 5):
if i != x and i != z and x != z:
print(i, x, z)
64、什么是反射?以及应用场景?
反射就是通过字符串的形式,导入模块;通过字符串的形式,去模块寻找指定函数,并执行。利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员,一种基于字符串的事件驱动!
1. getattr()函数是Python自省的核心函数,具体使用大体如下:
class A:
def __init__(self):
self.name = 'twiss'
#self.age='24'
def method(self):
print"method print"
Instance = A()
print getattr(Instance , 'name, 'not find') #如果Instance 对象中有属性
name则打印self.name的值,否则打印'not find'
print getattr(Instance , 'age', 'not find') #如果Instance 对象中有属性
age则打印self.age的值,否则打印'not find'
print getattr(a, 'method', 'default') #如果有方法method,否则打印其地址,
否则打印default
print getattr(a, 'method', 'default')() #如果有方法method,运行函数并
打印None否则打印default
2. hasattr(object, name)
说明:判断对象object是否包含名为name的特性(hasattr是通过调用getattr(ojbect, name)
是否抛出异常来实现的)
3. setattr(object, name, value)
这是相对应的getattr()。参数是一个对象,一个字符串和一个任意值。字符串可能
会列出一个现有的属性或一个新的属性。这个函数将值赋给属性的。该对象允许它提供
。例如,setattr(x,“foobar”,123)相当于x.foobar = 123。
4. delattr(object, name)
与setattr()相关的一组函数。参数是由一个对象(记住python中一切皆是对象)和一
个字符串组成的。string参数必须是对象属性名之一。该函数删除该obj的一个由string
指定的属性。delattr(x, 'foobar')=del x.foobar
67、metaclass作用?以及应用场景?
元类就是创建类这种对象的东西
当python在执行带class语句的时候,会初始化一个类对象放在内存里面。例如这里会初始化一个Trick对象
这个对象(类)自身拥有创建对象(通常我们说的实例,但是在python中还是对象)的能力。
1.类由type创建,创建类时,type的__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法)
2.对象由类创建,创建对象时,类的__init__方法自动执行,对象()执行类的 __call__ 方法
68、用尽量多的方法实现单例模式。
单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。
实现单例模式的几种方式
使用模块
其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做
class Singleton(object):
def foo(self):
pass
singleton = Singleton()
将上面的代码保存在文件 mysingleton.py 中,要使用时,直接在其他文件中导入此文件中的对象,这个对象即是单例模式的对象
from a import singleton
69、装饰器的写法以及应用场景。
装饰器是一个工厂函数,接受一个函数作为参数,然后返回一个新函数,
其闭包中包含被装饰的函数。有了装饰器,
可以提取大量函数中与本身功能无关的类似代码 ( 这块在Flask中用于定义路由的@app.route,就是一个很好的例子),达到代码重用的目的。
可应用于插入日志、性能测试、事务处理等方面。
---------------------
def deco(func):
def warpper(*args, **kwargs):
print(‘start‘)
func(*args, **kwargs)
print(‘end‘)
return warpper
@deco
def myfunc(parameter):
print("run with %s" % parameter)
myfunc("something")
70、异常处理写法以及如何主动跑出异常(应用场景)
try:
pirnt('123')
except:
print('456')
通过raise 异常对象主动抛出异常
71、什么是面向对象的mro
Method Resolution Order 用来制作一个继承关系的列表
MRO列表的制作原则:
1.子类永远在父类的前面
2.如果继承了多个父类,那么按照()中的顺序在列表中摆放
3.如果多个类同时继承了一个父类,孙子类中只会选取第一个父类中的父类的该方法
72、isinstance作用以及应用场景?
检测一个数据是否由指定的类型创建
73、写代码并实现:
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]
def nums(lists, n):
if isinstance(lists, list):
for i in range(len(lists)):
for v in lists:
if lists[i] + v == n:
print(i, lists.index(v))
break
74、json序列化时,可以处理的数据类型有哪些?如何定制支持datetime类型?
#字符串、字典、列表、数字、布尔值、None、、自定义class类
import json
import datetime
class MyEncoder(json.JSONEncoder):
def default(self, o): # o是数据类型
if isinstance(o, datetime.datetime)
return o.strftime('%Y-%m-%d')
else:
return super(MyEncoder, self).default(o)
75、json序列化时,默认遇到中文会转换成unicode,如果想要保留中文怎么办?
json.dumps(jsonData,ensure_ascii=False);
76、什么是断言?应用场景?
在没完善一个程序之前,我们不知道程序在哪里会出错,与其让它在运行最崩溃,不如在出现错误条件时就崩溃,这时候就需要assert断言的帮助
python assert断言是声明其布尔值必须为真的判定,如果发生异常就说明表达示为假。可以理解assert断言语句为raise-if-not,用来测试表示式,其返回值为假,就会触发异常。
断言条件为真时,代码继续执行,负责抛出异常,这个异常通常不会去捕获他,我们设置一个断言目的就是要求必须实现某个条件。
assert True
77、有用过with statement吗?它的好处是什么?
with语句的作用是通过某种方式简化异常处理
自动管理文件关闭
78、使用代码实现查看列举目录下的所有文件。
# 1递归方法
def print_directory_contents(sPath):
import os
for sChild in os.listdir(sPath):
sChildPath = os.path.join(sPath,sChild)
if os.path.isdir(sChildPath):
print_directory_contents(sChildPath)
else:
print(sChildPath)
print_directory_contents('./test/')
#2
tapath = './test/'
for i in os.listdir(tapath):
print(i)
79、简述 yield和yield from关键字。
yield 的作用就是把一个函数变成一个生成器, 带有yield的函数不再是一个普通的函数。python解释器会将其视为一个generator
yield:生成器函数关键字
yield from:相当于 for i in obj : yield i
def a():
yield 1
def b():
yield from a()
80、求结果
def num():
return [lambda x:i*x for i in range(4)]
print([m2 for m in num()])
===========================
[6, 6, 6, 6]
1、简述 OSI 七层协议。
1、物理层
为数据链路层提供物理连接,实现比特流的透明传输,所传输数据的单位是比特,该层定义了通信设备与传输线接口硬件的电气、机械以及功能和过程的特性。
2、数据链路层
在通信的实体之间建立数据链路连接,传送以帧为单位的数据,通过检查发生在连接通信系统间传送路上的比特错误并进行恢复,确保比特序列组成为数据流准确无误地传送给对方的系统。数据链路层在相邻的节点之间实现透明的高可靠性传输。
3、网络层
解决多节点传送时的路由选择、拥挤控制及网络互连等,控制分组传送系统的操作,它的特性对高层是透明的,同时,根据传输层的要求选择服务质量,并向传输层报告未恢复的差错。
4、传输层
为两个端系统(源站和目标站)的会话层之间建立一条传输连接,可靠、透明地传送报文,执行端一端差错控制、顺序和流量控制、管理多路复用等。本层提供建立、维护和拆除传送连接的功能,并保证网络连接的质量。它向高层屏蔽了下层数据通信的细节,因而是OSI网络参考模型中最需要的一层。
5、会话层
不参与具体的数据传输,但对数据传输的同步进行管理。它主要负责提供两个进程之间建立、维护和结束会话连接功能,同时要对进程中必要的信息传送方式、进程间的同步以及重新同步进行管理。
6、表示层
解决在两个通信系统中交换信息时不同数据格式的编码之间的转换,语法选择,数据加密与解密及文本压缩等。
7、应用层
负责向用户提供各种网络应用服务,如文件传输、电子邮件、远程访问等。把进程中于对方进程通信的部分放入应用实体中,同时,对各种业务内容的通信功能进行管理。
2、什么是C/S和B/S架构?
C/S架构软件(即客户机/服务器模式)分为客户机和服务器两层:第一层是在客户机系统上结合了表示与业务逻辑,第二层是通过网络结合了数据库服务器。简单的说就是第一层是用户表示层,第二层是数据库层。客户端和服务器直接相连,这两个组成部分都承担着重要的角色。
B/S型模式,即浏览器/服务器结构。它是C/S架构的一种改进,可以说属于三层C/S架构。主要是利用了不断成熟的WWW浏览器技术,用通用浏览器就实现了原来需要复杂专用软件才能实现的强大功能,并节约了开发成本,是一种全新的软件系统构造技术。
3、简述 三次握手、四次挥手的流程。
所谓三次握手(Three-Way Handshake)即建立TCP连接,就是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发
1. 第一次握手:
Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
1. 第二次握手:
Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
1. 第三次握手:
Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。
所谓四次挥手(Four-Way Wavehand)即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发
第一次挥手:
Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
第二次挥手:
Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
第三次挥手:
Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
第四次挥手:
Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。
4、什么是arp协议?
地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议。
5、TCP和UDP的区别?
基于连接与无连接
TCP要求系统资源较多,UDP较少;
UDP程序结构较简单
流模式(TCP)与数据报模式(UDP);
TCP保证数据正确性,UDP可能丢包
TCP保证数据顺序,UDP不保证
6、什么是局域网和广域网?
局域网和广域网是按规模大小而划分的两种计算机网络。范围在几千米以内的计算机网络统称为局域网;而连接的范围超过10千米的,则称为广域网,因特网(Intenet)就是目前最大的广域网。
7、为何基于tcp协议的通信比基于udp协议的通信更可靠?
TCP的可靠保证,是它的三次握手双向机制,这一机制保证校验了数据,保证了他的可靠性。而UDP就没有了,udp信息发出后,不验证是否到达对方,所以不可靠。
8、什么是socket?简述基于tcp协议的套接字通信流程。
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
9、什么是粘包? socket 中造成粘包的原因是什么? 哪些情况会发生粘包现象?
指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能由接收方造成。
socket粘包:
socket 交互send时,连续处理多个send时会出现粘包,soket会把两条send作为一条send强制发送,会粘在一起。
send发送会根据recv定义的数值发送一个固定的数值,如果最后一次,所剩的数值小于recv定义数就会连带两条send数据同时发送,发生粘包状况。
解决方案:
方案1:可以使用time.sleep 在两send之间加上时间(不建议)
方案2:可以在send两条之间加入一条 conn.recv(1024)
10、IO多路复用的作用?
I/O多路复用是通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。
首先,输入操作一般包含两个步骤:
等待数据准备好(waiting for data to be ready)。对于一个套接口上的操作,这一步骤关系到数据从网络到达,并将其复制到内核的某个缓冲区。
将数据从内核缓冲区复制到进程缓冲区(copying the data from the kernel to the process)。
阻塞I/O模型
非阻塞I/O模型
I/O复用模型
正因为阻塞I/O只能阻塞一个I/O操作,而I/O复用模型能够阻塞多个I/O操作,所以才叫做多路复用。
11、什么是防火墙以及作用?
简单的来说,防火墙就是一种,避免你的电脑被黑客入侵的一种防护工具,一种确保网络安全的方法!
1.允许网络管理员定义一个中心点来防止非法用户进入内部网络。
2.可以很方便地监视网络的安全性,并报警。
3.可以作为部署NAT(Network Address Translation,网络地址变换)的地点,利用NAT技术,将有限的IP地址动态或静态地与内部的IP地址对应起来,用来缓解地址空间短缺的问题等
12、select、poll、epoll 模型的区别?
1)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用 epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在 epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的 时候只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间。这就是回调机制带来的性能提升。
(2)select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把current往设备等待队列中挂一次,而epoll只要 一次拷贝,而且把current往等待队列上挂也只挂一次(在epoll_wait的开始,注意这里的等待队列并不是设备等待队列,只是一个epoll内 部定义的等待队列)。这也能节省不少的开销。
13、简述 进程、线程、协程的区别 以及应用场景?
进程拥有自己的堆和栈,既不共享堆也不共享栈 进程由操作系统调度
线程拥有自己的堆和共享的栈 共享栈 但不共享堆 线程也是由操作系统调度
协程和线程一样有自己的堆和共享的栈 共享栈但不共享堆 协程由开发人员在适当情况调用
14、GIL锁是什么鬼?
GIL:全局解释器锁。当我们用多线程的时候,
每一个进程中只有一个GIL锁,那么这多个线程中谁拿到GIL锁,
谁即可以用cpu(ps:多个进程有多个Gil锁,但每个进程中只有一个GIL)
15、Python中如何使用线程池和进程池?
进程池:使用multiprocessing.Pool
线程池:使用ThreadPool模块
16、threading.local的作用?
threadLocal解决了参数在一个线程中各个函数之间相互传递的问题
一个threadLocal变量虽然是全局变量,但每个线程都只能读写自己线程的独立副本 互不干扰
17、进程之间如何进行通信?
创建一个queue队列,或使用 from multiprocessing import Manage管理要进行通信的数据
18、什么是并发和并行?
并发(concurrency)和并行(parallellism)是:
解释一:并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。
解释二:并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。
解释三:在一台处理器上“同时”处理多个任务,在多台处理器上同时处理多个任务。如hadoop分布式集群
所以并发编程的目标是充分的利用处理器的每一个核,以达到最高的处理性能。
19、进程锁和线程锁的作用?
当多进程或多线程是不用进程访问相同一个变量
是会造成同一时间执行相同的事 而得不到正确的结果 所以需要用锁锁上这个全局变量,
当某一个进程或线程访问时其他进程或线程均无法访问
20、解释什么是异步非阻塞?
异步双方不需要共同的时钟,也就是接收方不知道发送方什么时候发送,
所以在发送的信息中就要有提示接收方开始接收的信息,如开始位,同时在结束时有停止位。
非阻塞模式是指利用socket事件的消息机制,Server端与Client端之间的通信处于异步状态。
21、路由器和交换机的区别?
一、工作所在的OSI层次不一样(根本区别,导致接下来的区别)
交换机工作在 OSI模型的数据链路层,所以工作原理比较简单;
路由器工作在OSI模型的网络层,具备更多的网络协议信息,所以可以做出更好的数据转发策略。
二、数据转发所依据的对象也不一样。
交换机工作在数据链路层,所以交换机转发数据依靠的是每个物理地址(MAC地址),MAC地址一般是设备生产商在设备出厂时固定在设备中的,不能进行更改。
路由器工作在网络层,所以其交换数据依靠网络地址(IP地址),而IP地址是由网络管理员自己分配或者系统自动获取的。
三、是否可以分割广播域
由交换机连接的所有端口仍然属于同一个广播域,所以极有可能会产生数据拥堵;
连接到路由器上的所有端口不在属于同一个广播域,所以不会产生类似的数据拥堵问题。
22、什么是域名解析?
域名解析是把域名指向网站空间IP,让人们通过注册的域名可以方便地访问到网站的一种服务
23、如何修改本地hosts文件?
# 127.0.0.1 localhost
# ::1 localhost
127.0.0.1 www.gkate.com
修改后用浏览器访问“www.gkate.com”会被解析到127.0.0.1,导致无法显示该网页
24、生产者消费者模型应用场景及优势?
应用于一个生产数据一个处理数据的场景
优势生产者和消费者之间不直接进行通信 而是通过一个队列相当于一个缓冲区,
平衡了生产者和消费者的处理能力
25、什么是cdn?
尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,
使内容传输的更快、更稳定。通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、
负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。
26、LVS是什么及作用?
LVS 是 Linux Virtual Server ,Linux 虚拟服务器;是一个虚拟的服务器集群【多台机器 LB IP】。LVS 集群分为三层结构:
负载调度器(load balancer):它是整个LVS 集群对外的前端机器,负责将client请求发送到一组服务器[多台LB IP]上执行,而client端认为是返回来一个同一个IP【通常把这个IP 称为虚拟IP/VIP】
服务器池(server pool):一组真正执行client 请求的服务器,一般是我们的web服务器;除了web,还有FTP,MAIL,DNS
共享存储(shared stored):它为 server pool 提供了一个共享的存储区,很容易让服务器池拥有相同的内容,提供相同的服务[不是很理解]
LVS :单向的
End user ------>LVS --------> tomcat .......> end user
Ngnix 有个来回
End user ------>Ngnix--------> tomcat---->Ngnix .......> end user
27、Nginx是什么及作用?
Nginx是一个http服务器。同效果的http服务器还有Apache、tomcat等
作用:
1、 http服务器。Nginx是一个http服务可以独立提供http服务。可以做网页静态服务器。
2、 虚拟主机。可以实现在一台服务器虚拟出多个网站。例如个人网站使用的虚拟主机。基于端口的,不同的端口基于域名的,不同域名
3、 反向代理,负载均衡。当网站的访问量达到一定程度后,单台服务器不能满足用户的请求时,需要用多台服务器集群可以使用nginx做反向代理。并且多台服务器可以平均分担负载,不会因为某台服务器负载高宕机而某台服务器闲置的情况。
28、keepalived是什么及作用?
29、haproxy是什么以及作用?
30、什么是负载均衡?
负载均衡是高可用网络基础架构的的一个关键组成部分,
有了负载均衡,我们通常可以将我们的应用服务器部署多台,
然后通过负载均衡将用户的请求分发到不同的服务器用来提高网站、
应用、数据库或其他服务的性能以及可靠性。
31、什么是rpc及应用场景?
32、简述 asynio模块的作用和应用场景。
asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。
asyncio的编程模型就是一个消息循环。我们从asyncio模块中直接获取一个
EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO。
33、简述 gevent模块的作用和应用场景。
当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,
等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,
经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。
由于切换是在IO操作时自动完成,所以gevent需要修改Python自带的一些标准库,
这一过程在启动时通过monkey patch完成
34、twisted框架的使用和应用?
Twisted是用Python实现的基于事件驱动的网络引擎框架,
Twisted支持许多常见的传输及应用层协议,包括TCP、UDP、SSL/TLS、HTTP、IMAP、SSH、IRC以及FTP。就像Python一样,Twisted也具有“内置电池”(batteries-included)的特点。
Twisted对于其支持的所有协议都带有客户端和服务器实现,同时附带有基于命令行的工具,
使得配置和部署产品级的Twisted应用变得非常方便。
1、列举常见的关系型数据库和非关系型都有那些?
关系型:Mysql / Oracle / SQL Server
非关系型:redis / MongoDB…
2、MySQL常见数据库引擎及比较?
MySQL数据库中的表引擎一般常用两种:MyISAM和InnoDB
区别:
MyISAM类型的数据文件有三个1.frm(结构)、2.MYD(数据)、3.MYI(索引)
MyISAM类型中的表数据增 删 改速度快,不支持事务,没有InnoDB安全。
InnoDB类型的数据文件只有一个 .frm
InnoDB类型的表数据增 删 改速度没有MyISAM的快,但支持事务,相对安全。
3、简述数据三大范式?
第一范式(1NF):原子性 字段不可再分,否则就不是关系数据库;
第二范式(2NF):唯一性 一个表只说明一个事物;
第三范式(3NF):每列都与主键有直接关系,不存在传递依赖;
1NF:列表字段不可分;
2NF:有主键且非主键依赖主键;
3NF:非主键字段不能相互依赖;
4、什么是事务?MySQL如何支持事务?
同时对一组数据进行操作的语句就成为事务
在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。
5、简述数据库设计中一对多和多对多的应用场景?
一对多 :一个学生对多门考试成绩
多对多 :一个老师教多个学生 一个学生让好几个老师教
6、如何基于数据库实现商城商品计数器?
设置一个商品计数的列 自动递增为1
7、常见SQL(必备)
8、简述触发器、函数、视图、存储过程?
触发器:制定一个sql条件和要做的事当满足的时候自动触发并执行要做的事
函数(存储过程):Mysql储存过程简而言之就是一组已经好的命令,需要使用的时候拿出来用就可以
视图:将一个写好的查询语句封装起来 当调用的时看到的数据就是满足条件的数据 不用每次都写同样的代码
9、MySQL索引种类
唯一索引
主键索引
普通索引
全文索引
10、索引在什么情况下遵循最左前缀的规则?
联合索引
11、主键和外键的区别?
. | 主键 | 外键 |
---|---|---|
定义 | 允许唯一标识,一条记录,不允许重复,不允许为空 | 表的外键是另外一表的主键,外键可以有重复,可以为空值 |
作用 | 用来保证数据完整性 | 用来和其他表建立关系 |
个数 | 主键只有一个 | 一个表可以有多个外键 |
12、MySQL常见的函数?
*concat(s1,s2,…Sn) 连接s1,s2..Sn为一个字符串
*length(str) 返回值为字符串str 的长度
*datediff(expr,expr2) 返回起始时间和结束时间的间隔天数
13、列举 创建索引但是无法命中索引的8种情况。
面试笔记28.4
14、如何开启慢日志查询?
1.查看慢查询是否开启
show variables like ‘slow_query%’;
show variables like ‘long_query_time’;
2.打开慢查询
set global slow_query_log=’ON’;
3.设置慢查询日志记录文件
set global slow_query_log_file=’/var/lib/mysql/test-10-226-slow.log’;
4.指定慢查询事件
set global long_query_time=1;
15、数据库导入导出命令(结构+数据)?
导出:
mysql dump -u root -p 库名 >导出的文件.sql
导入:
mysql -u root -p 库名
16、数据库优化方案?
python面试笔记28.5
17、char和varchar的区别?
char的长度是不可变的,而varchar的长度是可变的,也就是说,定义一个char[10]和varchar[10],如果存进去的是‘csdn’,那么char所占的长度依然为10,除了字符‘csdn’外,后面跟六个空格,而varchar就立马把长度变为4了
18、简述MySQL的执行计划?
数据库的执行计划通俗点说就是,数据库服务器在执行sql语句的时候,会准备几套方案,最后选择消耗资源最小的那个方案。就是执行计划。
19、在对name做了唯一索引前提下,简述以下区别:
select * from tb where name = ‘twiss’ ----—–取出所有name= twiss
select * from tb where name = ‘twiss’ limit 1 ---—–只取出第一条 name= twiss
20、1000w条数据,使用limit offset 分页时,为什么越往后翻越慢?如何解决?
当一个数据库表过于庞大,LIMIT offset, length中的offset值过大,则SQL查询语句会非常缓慢,增加order by,并且order by字段需要建立索引。
21、什么是索引合并?
1、索引合并是把几个索引的范围扫描合并成一个索引。
2、索引合并的时候,会对索引进行并集,交集或者先交集再并集操作,以便合并成一个索引。
3、这些需要合并的索引只能是一个表的。不能对多表进行索引合并。
22、什么是覆盖索引?
就是select的数据列只用从索引中就能够取得,不必从数据表中读取,换句话说查询列要被所使用的索引覆盖。
23、简述数据库读写分离?
对于数据存储层高并发问题,最先想到的可能就是读写分离,在网站访问量大并且读写不平均的情况下,将存储分为master,slave两台,所有的写都路由到master上,所有的读都路由到slave上,然后master和slave同步。如果一台salve不够,可以加多台,比如一台master,3台slave。
24、简述数据库分库分表?(水平、垂直)
分区的主要目的是将数据按照一个较粗的粒度分在不同的表中,这样可以将相关的数据存放在一起,而且如果想一次性的删除整个分区的数据也很方便。
通过一些HASH算法或者工具实现将一张数据表垂直或者水平进行物理切分
25、redis和memcached比较?
1、Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其他东西,例如图片、视频等等;
2、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储;
3、虚拟内存–Redis当物理内存用完时,可以将一些很久没用到的value 交换到磁盘;
4、过期策略–memcache在set时就指定,例如set key1 0 0 8,即永不过期。Redis可以通过例如expire 设定,例如expire name 10;
5、分布式–设定memcache集群,利用magent做一主多从;redis可以做一主多从。都可以一主一从;
6、存储数据安全–memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化);
7、灾难恢复–memcache挂掉后,数据不可恢复; redis数据丢失后可以通过aof恢复;
26、redis中数据库默认是多少个db 及作用?
redis默认有十六个db
27、python操作redis的模块?
import redis
r = redis.Redis(host='127.0.0.1', port=6379,decode_responses=True)
r.set('name', 'OK')
print(r.get('name'))
28、如果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)
20、redis如何实现主从复制?以及数据同步机制?
在Master和Slave互通之后,首先,Slave会发送sync同步指令,当Master收到指令后,将在后台启动存盘进程,同时收集所有来自Slave的修改数据集的指令信息,当后台进程完成之后,Master将发送对应的数据库文件到对应的Slave中,以完成一次完整的同步工作。其次Slave在接受到数据库文件之后,将其存盘并加载到内存中。最后,Master继续收集修改命令和新增的修改指令,并依次发送给Slave,其将在本次执行这些数据的修改命令,从而最终达到数据同步的实现。
30、redis中的sentinel的作用?
Redis Sentinel 为Redis提供了高可用的实现。通俗来说就是你可以部署一套无需人为干预即可防灾的Redis环境。
RS同时为客户端提供了其他诸如监控,通知的功能。
帮助我们自动在主从之间进行切换
检测主从中 主是否挂掉,且超过一半的sentinel检测到挂了之后才进行进行切换。
如果主修复好了,再次启动时候,会变成从。
启动主redis:
redis-server /etc/redis-6379.conf 启动主redis
redis-server /etc/redis-6380.conf 启动从redis
在linux中:
找到 /etc/redis-sentinel-8001.conf 配置文件,在内部:
- 哨兵的端口 port = 8001
- 主redis的IP,哨兵个数的一半/1
找到 /etc/redis-sentinel-8002.conf 配置文件,在内部:
- 哨兵的端口 port = 8002
- 主redis的IP, 1
启动两个哨兵
31、如何实现redis集群?
redis集群、分片、分布式redis
redis-py-cluster
集群方案:
- redis cluster 官方提供的集群方案。
- codis,豌豆荚技术团队。
- tweproxy,Twiter技术团队。
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 实例中。
32、redis中默认有多少个哈希槽?
有2**14个哈希槽 16384个
33、简述redis的有哪几种持久化策略及比较?
rdb:快照形式是直接把内存中的数据保存到一个dump文件中,定时保存,保存策略
aof:把所有的对redis的服务器进行修改的命令都存到一个文件里,命令的集合
RDB:每隔一段时间对redis进行一次持久化。
- 缺点:数据不完整
- 优点:速度快
AOF:把所有命令保存起来,如果想到重新生成到redis,那么就要把命令重新执行一次。
- 缺点:速度慢,文件比较大
- 优点:数据完整
34、列举redis支持的过期策略。
定时删除
含义:在设置key的过期时间的同时,为该key创建一个定时器,让定时器在key的过期时间来临时,对key进行删除
惰性删除
含义:key过期的时候不删除,每次从数据库获取key的时候去检查是否过期,若过期,则删除,返回null。
定期删除
含义:每隔一段时间执行一次删除(在redis.conf配置文件设置hz,1s刷新的频率)过期key操作
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(驱逐):禁止驱逐数据
35、MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 redis 中都是热点数据?
LRU(最近少用的淘汰)
即redis的缓存每命中一次,就给命中的缓存增加一定ttl(过期时间)(根据具体情况来设定, 比如10分钟).一段时间后, 热数据的ttl都会较大, 不会自动失效, 而冷数据基本上过了设定的ttl就马上失效了.
相关知识:redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略(回收策略)。redis 提供 6种数据淘汰策略:
volatile-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(驱逐):禁止驱逐数据
36、写代码,基于redis的列表实现 先进先出、后进先出队列、优先级队列。
from . import picklecompat
class Base(object):
"""Per-spider base queue class"""
def __init__(self, server, spider, key, serializer=None):
"""Initialize per-spider redis queue.
Parameters
----------
server : StrictRedis
Redis client instance.
spider : Spider
Scrapy spider instance.
key: str
Redis key where to put and get messages.
serializer : object
Serializer object with ``loads`` and ``dumps`` methods.
"""
if serializer is None:
# Backward compatibility.
# TODO: deprecate pickle.
serializer = picklecompat
if not hasattr(serializer, 'loads'):
raise TypeError("serializer does not implement 'loads' function: %r"
% serializer)
if not hasattr(serializer, 'dumps'):
raise TypeError("serializer '%s' does not implement 'dumps' function: %r"
% serializer)
self.server = server
self.spider = spider
self.key = key % {'spider': spider.name}
self.serializer = serializer
def _encode_request(self, request):
"""Encode a request object"""
obj = request_to_dict(request, self.spider)
return self.serializer.dumps(obj)
def _decode_request(self, encoded_request):
"""Decode an request previously encoded"""
obj = self.serializer.loads(encoded_request)
return request_from_dict(obj, self.spider)
def __len__(self):
"""Return the length of the queue"""
raise NotImplementedError
def push(self, request):
"""Push a request"""
raise NotImplementedError
def pop(self, timeout=0):
"""Pop a request"""
raise NotImplementedError
def clear(self):
"""Clear queue/stack"""
self.server.delete(self.key)
class FifoQueue(Base):
"""Per-spider FIFO queue"""
def __len__(self):
"""Return the length of the queue"""
return self.server.llen(self.key)
def push(self, request):
"""Push a request"""
self.server.lpush(self.key, self._encode_request(request))
def pop(self, timeout=0):
"""Pop a request"""
if timeout > 0:
data = self.server.brpop(self.key, timeout)
if isinstance(data, tuple):
data = data[1]
else:
data = self.server.rpop(self.key)
if data:
return self._decode_request(data)
class PriorityQueue(Base):
"""Per-spider priority queue abstraction using redis' sorted set"""
def __len__(self):
"""Return the length of the queue"""
return self.server.zcard(self.key)
def push(self, request):
"""Push a request"""
data = self._encode_request(request)
score = -request.priority
# We don't use zadd method as the order of arguments change depending on
# whether the class is Redis or StrictRedis, and the option of using
# kwargs only accepts strings, not bytes.
self.server.execute_command('ZADD', self.key, score, data)
def pop(self, timeout=0):
"""
Pop a request
timeout not support in this queue class
"""
# use atomic range/remove using multi/exec
pipe = self.server.pipeline()
pipe.multi()
pipe.zrange(self.key, 0, 0).zremrangebyrank(self.key, 0, 0)
results, count = pipe.execute()
if results:
return self._decode_request(results[0])
class LifoQueue(Base):
"""Per-spider LIFO queue."""
def __len__(self):
"""Return the length of the stack"""
return self.server.llen(self.key)
def push(self, request):
"""Push a request"""
self.server.lpush(self.key, self._encode_request(request))
def pop(self, timeout=0):
"""Pop a request"""
if timeout > 0:
data = self.server.blpop(self.key, timeout)
if isinstance(data, tuple):
data = data[1]
else:
data = self.server.lpop(self.key)
if data:
return self._decode_request(data)
# TODO: Deprecate the use of these names.
SpiderQueue = FifoQueue
SpiderStack = LifoQueue
SpiderPriorityQueue = PriorityQueue
37、如何基于redis实现消息队列?
Redis中五大数据结构之一—列表,其PUSH和POP命令遵循FIFO先进先出原则。当我们需要发布消息的时候执行LPUSH(消息从左边进入队列),消息接收端执行RPOP获得消息(消息从右侧弹出)。对于列表,Redis提供了带有阻塞的命令(命令前加B)。因此,生产者lpush消息,消费者brpop(从列表中弹出最右端元素,如无元素则一直阻塞到timeout)消息,并设定超时时间timeout,可以减少redis的压力。
不要使用redis去做消息队列,这不是redis的设计目标。
但实在太多人使用redis去做去消息队列,redis的作者看不下去,另外基于redis的核心代码,另外实现了一个消息队列disque:https://github.com/antirez/disque
38、如何基于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)
39、什么是codis及作用?
Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别 (不支持的命令列表), 上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作, 所有后边的一切事情, 对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的 Redis 服务.
40、什么是twemproxy及作用?
Twemproxy是一种代理分片机制,由Twitter开源。Twemproxy作为代理,可接受来自多个程序的访问,按照路由规则,转发给后台的各个Redis服务器,再原路返回。该方案很好的解决了单个Redis实例承载能力的问题。
是 Twtter 开源的一个 Redis 和 Memcache 代理服务器,主要用于管理 Redis 和 Memcached 集群,减少与Cache 服务器直接连接的数量。
41、写代码实现redis事务操作。
import redis
pool = redis.ConnectionPool(host='10.211.55.4', port=6379)
conn = redis.Redis(connection_pool=pool)
# pipe = r.pipeline(transaction=False)
pipe = conn.pipeline(transaction=True)
# 开始事务
pipe.multi()
pipe.set('name', 'bendere')
pipe.set('role', 'sb')
# 提交
pipe.execute()
注意:咨询是否当前分布式redis是否支持事务
42、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()
- 数据库的锁
43、基于redis如何实现商城商品数量计数器?
Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的10个用户–我们
称之为“user_scores”,我们只需要像下面一样执行即可:
当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行:
ZRANGE user_scores 0 10 WITHSCORES
Agora Games就是一个很好的例子,用Ruby实现的,它的排行榜就是使用Redis来存储数据的,你可以在这里看到
44 、简述redis分布式锁和redlock的实现机制。
在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段。
一个Client想要获得一个锁需要以下几个操作:
得到本地时间Client使用相同的key和随机数,按照顺序在每个Master实例中尝试获得锁。在获得锁的过程中,为每一个锁操作设置一个快速失败时间(如果想要获得一个10秒的锁, 那么每一个锁操作的失败时间设为5-50ms)。
这样可以避免客户端与一个已经故障的Master通信占用太长时间,通过快速失败的方式尽快的与集群中的其他节点完成锁操作。
客户端计算出与master获得锁操作过程中消耗的时间,当且仅当Client获得锁消耗的时间小于锁的存活时间,并且在一半以上的master节点中获得锁。才认为client成功的获得了锁。
如果已经获得了锁,Client执行任务的时间窗口是锁的存活时间减去获得锁消耗的时间。
如果Client获得锁的数量不足一半以上,或获得锁的时间超时,那么认为获得锁失败。客户端需要尝试在所有的master节点中释放锁, 即使在第二步中没有成功获得该Master节点中的锁,仍要进行释放操作。
45、什么是一致性哈希?Python中是否有相应模块?
对节点和数据,都做一次哈希运算,然后比较节点和数据的哈希值,数据取和节点最相近的节点做为存放节点。这样就保证当节点增加或者减少的时候,影响的数据最少。
hash_ring 是python中做一致性哈希的模块
Python模块--hash_ring,即Python中的一致性hash
46、如何高效的找到redis中所有以twiss开头的key?
key twiss*
redis 有一个keys命令。
语法:KEYS pattern
说明:返回与指定模式相匹配的所用的keys。
该命令所支持的匹配模式如下:
(1)?:用于匹配单个字符。例如,h?llo可以匹配hello、hallo和hxllo等;
(2)*:用于匹配零个或者多个字符。例如,h*llo可以匹配hllo和heeeello等;
(3)[]:可以用来指定模式的选择区间。例如h[ae]llo可以匹配hello和hallo,但是不能匹配hillo。
同时,可以使用“/”符号来转义特殊的字符
1、谈谈你对http协议的认识。
HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传送协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。
HTTP是一个应用层协议,由请求和响应构成,是一个标准的客户端服务器模型。HTTP是一个无状态的协议。端口号为80
2、谈谈你对websocket协议的认识。
WebSocket是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。
3、什么是magic string ?
有触发时机在满足条件时自动触发就是魔术方法
4、如何创建响应式布局?
使用媒体查询的方式,创建多个元素宽度是相对的的布局理想的响应式布局是指的对PC/移动各种终端进行响应的
@media (min-width: 768px){
.pg-header{
background-color: green;
}
}
@media (min-width: 992px){
.pg-header{
background-color: pink;
}
}
5、你曾经使用过哪些前端框架?
Bootstrap / vue / React
6、什么是ajax请求?并使用jQuery和XMLHttpRequest对象实现一个ajax请求。
AJAX是在不加载整个页面的情况异步下与服务器发送请求交换数据并更新部分网页的艺术
$.ajax({
url:'user/add',//当前请求的url地址
type:'get',//当前请求的方式 get post
data:{id:100},//请求时发送的参数
dataType:'json',//返回的数据类型
success:function(data){
//ajax请求成功后执行的代码
console.log(data);
},
error:function(){
//ajax执行失败后执行的代码
alert('ajax执行错误');
},
timeout:2000,//设置当前请求的超时时间 异步请求生效
async:true //是否异步 false同步 true异步
})
7、如何在前端实现轮训?
轮询:客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并关闭连接。
优点:后端程序编写比较容易。 缺点:请求中有大半是无用,浪费带宽和服务器资源。 实例:适于小型应用。
https://www.cnblogs.com/zhaowinter/p/5332681.html
8、如何在前端实现长轮训?
客户端向服务器发送Ajax请求,服务器接到请求后hold住连接,直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求。
优点:在无消息的情况下不会频繁的请求,耗费资小。
缺点:服务器hold连接会消耗资源,返回数据顺序无保证,难于管理维护。 Comet异步的ashx,
实例:WebQQ、Hi网页版、Facebook IM。
9、vuex的作用?
在使用库或框架时,需要注意一个「适用性」的问题。
Vuex 或者说实现了 Flux 思想的库,解决了几个问题:
组件之间的数据通信
使用单向数据流的方式进行数据的中心化管理
为什么要解决这样的问题呢?其实是因为当程序逻辑过于复杂的时候,非中心化的数据管理会让整个 app 的逻辑非常混乱。
举一个不使用中心化的数据管理机制的具体例子:
一个 app ,有四个 tab,每个 tab 都需要读取用户的资料。如果数据在每个 tab 的控制器里(或者说组件里)都存了一份,那么在用户手动更新了用户资料之后,就需要在每一个 tab 里都更新一遍用户资料,才能保证用户看到的永远是最新的资料。
如你问题里所说,我每进一个 tab 的时候重新请求一下不就好了吗?
这样的解决方案不是不可以,但弊端也非常明显:
1) 对于服务器端来说,频繁的请求是非常占用资源的,如果你的 app 用户足够多,那么每多出一个请求,对公司来说,都是一大笔钱。如果数据存在了 store 中,并且所有的 tab 都读取同一份数据,在用户更新资料时,在前端更新了 store 中的数据,是不是在切换 tab 时就减少了四个请求呢?
2) 对于前端开发者来说,如果你的项目足够复杂,团队的规模也不仅是一个人,那么前端代码就会因为数据分散管理而产生非常严重的性能和稳定性的隐患(比如你的同事觉得进入模块就刷新用户资料太慢了,手贱把刷新的代码删了,你又没发现)。
https://segmentfault.com/q/1010000011402824
10、vue中的路由的拦截器的作用?
判断每一个页面的http请求的状态获取内容做响应的处理
vue-resource的interceptors拦截器的作用正是解决此需求的妙方。在每次http的请求响应之后,如果设置了拦截器如下,会优先执行拦截器函数,获取响应体,然后才会决定是否把response返回给then进行接收
11、axios的作用?
在浏览器中发送 XMLHttpRequests 请求
在 node.js 中发送 http请求
支持 Promise API
拦截请求和响应
转换请求和响应数据
自动转换 JSON 数据
客户端支持保护安全免受 XSRF 攻击
12、列举vue的常见指令。
条件判断使用 v-if指令
循环使用 v-for 指令。
事件监听可以使用 v-on 指令:
14、简述jsonp及实现原理?
JSONP是用来解决跨域请求问题的
跨域:协议 域名 端口号有一个不一样就是跨域
实现原理:
script标签src属性中的链接却可以访问跨域的js脚本,利用这个特性,服务端不再返回JSON格式的数据,而是返回一段调用某个函数的js代码,在src中进行了调用,这样实现了跨域。
14、是什么cors ?
CORS 全称是跨域资源共享(Cross-Origin Resource Sharing),是一种 AJAX 跨域请求资源的方式,支持现代浏览器,IE支持10以上。
15、列举Http请求中常见的请求方式?
GET:请求获取由 Request-URI 所标识的资源。
POST:在 Request-URI 所标识的资源后附加新的数据。
HEAD:请求获取由 Request-URI 所标识的资源的响应消息报头。
OPTIONS:请求查询服务器的性能,或查询与资源相关的选项和需求。
PUT:请求服务器存储一个资源,并用 Request-URI作为其标识。
DELETE:请求服务器删除由 Request-URI所标识的资源。
TRACE:请求服务器回送收到的请求信息,主要用语测试或诊断。
CONNECT:HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
16、列举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):服务器宕机
17、列举Http请求中常见的请求头?
User-Agent:浏览器类型,如果Servlet返回的内容与浏览器类型有关则该值非常有用。
Cookie:这是最重要的请求头信息之一
Content-Type:请求类型
18、求结果
alter(Gkate)
19、求结果
console.log(Twiss)
20、
console.log(‘Iran’)
21、
undefine
22、
alter(‘Gkate’)
23、
var name ='twiss'
function foo(){
this.name = 'Gkate'
this.func = function(){
(function(){
alter(this.name)
})
}
}
var obj = new foo();
obj.func();
alter(Gkate)
24、django、flask、tornado框架的比较?
Django:Python 界最全能的 web 开发框架,battery-include 各种功能完备,可维护性和开发速度一级棒。常有人说 Django 慢,其实主要慢在 Django ORM 与数据库的交互上,所以是否选用 Django,取决于项目对数据库交互的要求以及各种优化。而对于 Django 的同步特性导致吞吐量小的问题,其实可以通过 Celery 等解决,倒不是一个根本问题。Django 的项目代表:Instagram,Guardian。
Tornado:天生异步,性能强悍是 Tornado 的名片,然而 Tornado 相比 Django 是较为原始的框架,诸多内容需要自己去处理。当然,随着项目越来越大,框架能够提供的功能占比越来越小,更多的内容需要团队自己去实现,而大项目往往需要性能的保证,这时候 Tornado 就是比较好的选择。Tornado项目代表:知乎。
Flask:微框架的典范,号称 Python 代码写得最好的项目之一。Flask 的灵活性,也是双刃剑:能用好 Flask 的,可以做成 Pinterest,用不好就是灾难(显然对任何框架都是这样)。Flask 虽然是微框架,但是也可以做成规模化的 Flask。加上 Flask 可以自由选择自己的数据库交互组件(通常是 Flask-SQLAlchemy),而且加上 celery +redis 等异步特性以后,Flask 的性能相对 Tornado 也不逞多让,也许Flask 的灵活性可能是某些团队更需要的。
25、什么是wsgi?
WSGI(Web Server Gateway Interface,Web 服务器网关接口)则是Python语言中1所定义的Web服务器和Web应用程序之间或框架之间的通用接口标准。
WSGI就是一座桥梁,桥梁的一端称为服务端或网关端,另一端称为应用端或者框架端,WSGI的作用就是在协议之间进行转化。WSGI将Web组件分成了三类:Web 服务器(WSGI Server)、Web中间件(WSGI Middleware)与Web应用程序(WSGI Application)。
Web Server接收HTTP请求,封装一系列环境变量,按照WSGI接口标准调用注册的WSGI Application,最后将响应返回给客户端。
26、django请求的生命周期?
前端请求—>nginx—>uwsgi.—>中间件—>url路由—->view试图—>orm—->拿到数据返回给view—->试图将数据渲染到模版中拿到字符串—->中间件—>uwsgi—->nginx—->前端渲染
27、列举django的内置组件?
url 、view、model、template、中间件
28、列举django中间件的5个方法?以及django中间件的应用场景?
process_request(self,request)
process_view(self, request, callback, callback_args, callback_kwargs)
process_exception(self, request, exception)
process_response(self, request, response)
1 请求先执行所有中间件的process_request,然后做路由匹配,找到函数不执行。
2 再执行所有的process_view,在执行视图函数。
3 再执行process_response
4 如果程序报错执行process_exception
5 如果程序有render方法则执行process_template_response
29、简述什么是FBV和CBV?
1 FBV方式请求的过程
用户发送url请求,Django会依次遍历路由映射表中的所有记录,一旦路由映射表其中的一条匹配成功了,
就执行视图函数中对应的函数名,这是fbv的执行流程
2 CBV方式请求的过程
当服务端使用CBV模式的时候,用户发给服务端的请求包含url和method,这两个信息都是字符串类型
服务端通过路由映射表匹配成功后会自动去找dispatch方法,然后Django会通过dispatch反射的方式找到类中对应的方法并执行
类中的方法执行完毕之后,会把客户端想要的数据返回给dispatch方法,由dispatch方法把数据返回经客户端
把上面的例子中的视图函数修改成如下:
from django.views import View
class CBV(View):
def dispatch(self, request, *args, **kwargs):
print("dispatch......")
res=super(CBV,self).dispatch(request,*args,**kwargs)
return res
def get(self,request):
return render(request, "cbv.html")
def post(self,request):
return HttpResponse("cbv.get")
3 FBV和CBV的区别?
- 没什么区别,因为他们的本质都是函数。CBV的.as_view()返回的view函数,view函数中调用类的dispatch方法,在dispatch方法中通过反射执行get/post/delete/put等方法。
- CBV比较简洁,GET/POST等业务功能分别放在不同get/post函数中。FBV自己做判断进行区分。
30、django的request对象是在什么时候创建的?
当请求一个页面时,Django会建立一个包含请求元数据的 HttpRequest 对象。 当Django 加载对应的视图时,HttpRequest 对象将作为视图函数的第一个参数。每个视图会返回一个HttpResponse 对象。
31、如何给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('...')
32、列举django orm 中所有的方法(QuerySet对象的所有方法)
返回Query Set对象的方法有:
* all()
* filter()
* exclude()
* order_by()
* reverse()
* dictinct()
特殊的QuerySet:
* values() 返回一个可迭代的字典序列
* values_list() 返回一个可迭代的元祖序列
返回具体对象的:
* get()
* first()
* last()
返回布尔值的方法有:
* existe()
返回数学的方法有:
* count( )
33、only和defer的区别?
defer : 映射中排除某列数据
only : 仅取某个列中的数据
34、select_related和prefetch_related的区别?
select_related通过多表join关联查询,一次性获得所有数据,通过降低数据库查询次数来提升性能,但关联表不能太多,因为join操作本来就比较消耗性能
prefetch_related()的解决方法是,分别查询每个表,然后用Python处理他们之间的关系!
都是为了减少SQL查询的数量
title = models.CharField(max_length=32)
class UserInfo(models.Model):
name = models.CharField(max_length=32)
email = models.CharField(max_length=32)
ut = models.ForeignKey(to='UserType')
ut = models.ForeignKey(to='UserType')
ut = models.ForeignKey(to='UserType')
ut = models.ForeignKey(to='UserType')
# 1次SQL
# select * from userinfo
objs = UserInfo.obejcts.all()
for item in objs:
print(item.name)
# n+1次SQL
# select * from userinfo
objs = UserInfo.obejcts.all()
for item in objs:
# select * from usertype where id = item.id
print(item.name,item.ut.title)
示例1:
.select_related()
# 1次SQL
# select * from userinfo inner join usertype on userinfo.ut_id = usertype.id
objs = UserInfo.obejcts.all().select_related('ut')
for item in objs:
print(item.name,item.ut.title)
示例2:
.prefetch_related()
# select * from userinfo where id <= 8
# 计算:[1,2]
# select * from usertype where id in [1,2]
objs = UserInfo.obejcts.filter(id__lte=8).prefetch_related('ut')
for obj in objs:
print(obj.name,obj.ut.title)
两个函数的作用都是减少查询次数
35、filter和exclude的区别?
filter是查询满足条件的数据
exclude是查询不满足添加的数据
36、列举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)
37、django orm 中如何设置读写分离?
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':
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':
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'
38、F和Q的作用?
F:操作数据表中的某列值,F( )允许Django在未实际链接数据的情况下具有对数据库字段的值的引用,不用获取对象放在内存中再对字段进行操作,直接执行原生产sql语句操作。
通常情况下我们在更新数据时需要先从数据库里将原数据取出后方在内存里,然后编辑某些属性,最后提交
Q:对对象进行复杂查询,并支持&(and),|(or),~(not)操作符。
F:
Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。
修改操作也可以使用F函数,比如将每一本书的价格提高30元
例:把所有书名后面加上(第一版)
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.all().update(title=Concat(F("title"), Value("("), Value("第一版"), Value(")")))
Q:
Q(条件1) | Q(条件2) 或
Q(条件1) & Q(条件2) 且
Q(条件1) & ~Q(条件2) 非
39、values和values_list的区别?
values方法可以获取number字段的字典列表。
values_list可以获取number的元组列表。
values_list方法加个参数flat=True可以获取number的值列表。
40、如何使用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)
41、django的Form和ModeForm的作用?
- 作用:
- 对用户请求数据格式进行校验
- 自动生成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
- 应用:只要是客户端向服务端发送表单数据时,都可以进行使用,如:用户登录注册
42、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
43、django的Model中的ForeignKey字段中的on_delete参数有什么作用?
on_delete有CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET()五个可选择的值
CASCADE:此值设置,是级联删除。
PROTECT:此值设置,是会报完整性错误。
SET_NULL:此值设置,会把外键设置为null,前提是允许为null。
SET_DEFAULT:此值设置,会把设置为外键的默认值。
SET():此值设置,会调用外面的值,可以是一个函数。
44、django中csrf的实现机制?
Django预防CSRF攻击的方法是在用户提交的表单中加入一个csrftoken的隐含值,这个值和服务器中保存的csrftoken的值相同,这样做的原理如下:
1、在用户访问django的可信站点时,django反馈给用户的表单中有一个隐含字段csrftoken,这个值是在服务器端随机生成的,每一次提交表单都会生成不同的值
2、当用户提交django的表单时,服务器校验这个表单的csrftoken是否和自己保存的一致,来判断用户的合法性
3、当用户被csrf攻击从其他站点发送精心编制的攻击请求时,由于其他站点不可能知道隐藏的csrftoken字段的信息这样在服务器端就会校验失败,攻击被成功防御
具体配置如下:
template中添加{%csrf_token%}标签
45、django如何实现websocket?
https://www.cnblogs.com/huguodong/p/6611602.html
46、基于django使用ajax发送post请求时,都可以使用哪种方法携带csrf token?
方法一:
方法二:
//模板页面中必须要有 {% csrf_token %}
方法三:
//必须先引入它
47、django中如何实现orm表中添加数据时创建一条日志记录。
在settings.py中添加:
LOGGING = {
'disable_existing_loggers': False,
'version': 1,
'handlers': {
'console': {
# logging handler that outputs log messages to terminal
'class': 'logging.StreamHandler',
'level': 'DEBUG', # message level to be written to console
},
},
'loggers': {
'': {
# this sets root level logger to log debug and higher level
# logs to console. All other loggers inherit settings from
# root level logger.
'handlers': ['console'],
'level': 'DEBUG',
'propagate': False, # this tells logger to send logging message
# to its parent (will send if set to True)
},
'django.db': {
# # django also has database level logging
'handlers': ['console'],
'level': 'DEBUG',
'propagate': False,
},
},
}
48、django缓存如何设置?
三种粒度缓存
1 中间件级别
'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',
CACHE_MIDDLEWARE_SECONDS=10
2 视图级别
from django.views.decorators.cache import cache_page
@cache_page(15)
def index(request):
import time
t=time.time()
return render(request,"index.html",locals())
3 局部缓存
{% load cache %}
...
...
{% cache 15 "time_cache" %}
缓存时间:{{ t }}
{% endcache %}
49、django的缓存能使用redis吗?如果可以的话,如何配置?
pip install django-redis
apt-get install redis-server
然后在settings.py 里面添加CACHES = {
'default': {
'BACKEND': 'redis_cache.cache.RedisCache',
'LOCATION': '127.0.0.1:6379',
"OPTIONS": {
"CLIENT_CLASS": "redis_cache.client.DefaultClient",
},
}
在类中引用
conn = get_redis_connection("default")
50、django路由系统中name的作用?
name 可以用于在 templates, models, views ……中得到对应的网址,相当于“给网址取了个小名”,只要这个名字不变,网址变了也能通过名字获取到。
51、django的模板中filter和simple_tag的区别?
simple_tag
-参数任意,但是不能作为if条件判断的条件
filter
-参数最多只能有两个,但是可以作为if条件判断的条件。
52、django-debug-toolbar的作用?
django_debug_toolbar 是django的第三方工具包,给django扩展了调试功能。
包括查看执行的sql语句,db查询次数,request,headers,调试概览等。
https://blog.csdn.net/weixin_39198406/article/details/78821677
53、django中如何实现单元测试?
对于每一个测试方法都会将setUp()和tearDown()方法执行一遍
会单独新建一个测试数据库来进行数据库的操作方面的测试,默认在测试完成后销毁。
在测试方法中对数据库进行增删操作,最后都会被清除。也就是说,在test_add中插入的数据,在test_add测试结束后插入的数据会被清除。
django单元测试时为了模拟生产环境,会修改settings中的变量,例如, 把DEBUG变量修改为True, 把ALLOWED_HOSTS修改为[*]。
https://www.jianshu.com/p/34267dd79ad6
54、解释orm中 db first 和 code first的含义?
datebase first就是代表数据库优先,那么前提就是先创建数据库。
model first就是代表model优先,那么前提也就是先创建model,然后根据model自动建立数据库。
55、django中如何根据数据库表生成model中的类?
https://jingyan.baidu.com/article/4ae03de3e513d23eff9e6bb7.html
56、使用orm和原生sql的优缺点?
ORM框架:
对象关系映射,通过创建一个类,这个类与数据库的表相对应!类的对象代指数据库中的一行数据。
简述ORM原理:
让用户不再写SQL语句,而是通过类以及对象的方式,和其内部提供的方法,进行数据库操作!把用户输入的类或对象转换成SQL语句,转换之后通过pymysql执行完成数据库的操作。
ORM的优缺点:
优点:
* 提高开发效率,降低开发成本
* 使开发更加对象化
* 可移植
* 可以很方便地引入数据缓存之类的附加功能
缺点:
* 在处理多表联查、where条件复杂之类的查询时,ORM的语法会变得复杂。就需要写入原生SQL。
57、简述MVC和MTV
MVC: 模型 视图 控制器
MTV: 模型 模板 视图
58、django的contenttype组件的作用?
contenttype是django的一个组件(app),为我们找到django程序中所有app中的所有表并添加到记录中。
可以使用他再加上表中的两个字段实现:一张表和N张表创建FK关系。
- 字段:表名称
- 字段:数据行ID
59、谈谈你对restfull 规范的认识?
- 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.YueNet.com
www.YueNet.com/api/
-------------------------------------------------
- https
- 域名
- api.twiss.com
- www.twiss.com/api
- 版本:
- www.twiss.com/api/v1
- URL资源,名词
- www.twiss.com/api/v1/student
- 请求方式:
- GET/POST/PUT/DELETE/PATCH/OPTIONS/HEADERS/TRACE
- 返回值:
- www.twiss.com/api/v1/student/ -> 结果集
- www.twiss.com/api/v1/student/1/ -> 单个对象
- URL添加条件
- www.twiss.com/api/v1/student?page=11&size=9
- 状态码:
- 200
- 300
- 301
- 302
- 400
- 403
- 404
- 500
- 错误信息
{
code:1000,
meg:'xxxx'
}
- hyperlink
{
id:1
name: ‘xiangl’,
type: http://www.xxx.com/api/v1/type/1/
}
60、接口的幂等性是什么意思?
一个接口通过首先进行1次访问,然后对该接口进行N次相同访问的时候,对访问对象不造成影响,那么就认为接口具有幂等性。
比如:
GET, 第一次获取数据、第二次也是获取结果,幂等。
POST, 第一次新增数据,第二次也会再次新增,非幂等。
PUT, 第一次更新数据,第二次不会再次更新,幂等。
PATCH,第一次更新数据,第二次可能再次更新,非幂等。
DELTE,第一次删除数据,第二次不会再次删除,幂等。
61、什么是RPC?
RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
62、Http和Https的区别?
超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此,HTTP协议不适合传输一些敏感信息,比如:信用卡号、密码等支付信息。
为了解决HTTP协议的这一缺陷,需要使用另一种协议:安全套接字层超文本传输协议HTTPS,为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。
63、为什么要使用django rest framework框架?
1.客户端-服务端分离
优点:提高用户界面的便携性,通过简化服务器提高可伸缩性....
2.无状态(Stateless):从客户端的每个请求要包含服务器所需要的所有信息
优点:提高可见性(可以单独考虑每个请求),提高了可靠性(更容易从局部故障中修复),提高可扩展性(降低了服务器资源使用)
3.缓存(Cachable):服务器返回信息必须被标记是否可以缓存,如果缓存,客户端可能会重用之前的信息发送请求
优点:减少交互次数,减少交互的平均延迟
4.统一接口
优点:提高交互的可见性,鼓励单独改善组件
5.支持按需代码(Code-On-Demand 可选)
优点:提高可扩展性
64、django rest framework框架中都有那些组件?
- 路由,自动帮助开发者快速为一个视图创建4个url
www.gkate.com/api/v1/student/$
www.gkate.com/api/v1/student(?P\w+)$
www.gkate.com/api/v1/student/(?P\d+)/$
www.gkate.com/api/v1/student/(?P\d+)(?P\w+)$
- 版本处理
- 问题:版本都可以放在那里?
- url
- GET
- 请求头
- 认证
- 问题:认证流程?
- 权限
- 权限是否可以放在中间件中?以及为什么?
- 访问频率的控制
- 匿名用户可以真正的防止?无法做到真正的访问频率控制,只能把小白拒之门外。
如果要封IP,使用防火墙来做。
- 登录用户可以通过用户名作为唯一标示进行控制,如果有人注册很多账号,也无法防止。
- 视图
- 解析器 ,根据Content-Type请求头对请求体中的数据格式进行处理。request.data
- 分页
- 序列化
- 序列化
- source
- 定义方法
- 请求数据格式校验
- 渲染器
65、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
66、简述 django rest framework框架的认证流程。
- 如何编写?写类并实现authticate
- 方法中可以定义三种返回值:
- (user,auth),认证成功
- None , 匿名用户
- 异常 ,认证失败
- 流程:
- dispatch
- 再去request中进行认证处理
67、django rest framework如何实现的用户访问频率控制?
a. 基于用户IP限制访问频率
b. 基于用户IP显示访问频率(利于Django缓存)
c. view中限制请求频率
d. 匿名时用IP限制+登录时用Token限制
e. 全局使用
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'api.utils.throttles.throttles.LuffyAnonRateThrottle',
'api.utils.throttles.throttles.LuffyUserRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {
'anon': '10/day',
'user': '10/day',
'luffy_anon': '10/m',
'luffy_user': '20/m',
},
}
68、Flask框架的优势?
一、整体设计方面
首先,两者都是非常优秀的框架。整体来讲,两者设计的哲学是区别最大的地方。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数,两个相差并不远,说明越来越多的人关注它,虽然插件没那么全,但常用的还都是有的,而且质量都比较高。
69、Flask框架依赖组件?
Flask依赖两个外部库:
Jinja2模板引擎
Werkzeng WSGI工具集。
70、Flask蓝图的作用?
将不同的功能 模块化;
构建大型的应用;
优化项目结构;
增强可读性,易于维护;
71、列举使用过的Flask第三方组件?
内置:
- 配置
- 路由
- 视图
- 模板
- session
- 闪现
- 蓝图
- 中间件
- 特殊装饰器
第三方:
- Flask组件:
- flask-session
- flask-SQLAlchemy
- flask-migrate
- flask-script
- blinker
- 公共组件:
- wtforms
- dbutile
- sqlalchemy
- 自定义Flask组件
- auth ,参考flask-login组件
72、简述Flask上下文管理流程?
每次有请求过来的时候,flask 会先创建当前线程或者进程需要处理的两个重要上下文对象,把它们保存到隔离的栈里面,这样视图函数进行处理的时候就能直接从栈上获取这些信息。
73、Flask中的g的作用?
g 相当于一次请求的全局变量,当请求进来时将g和current_app封装为一个APPContext类,在通过LocalStack将Appcontext放入Local中,取值时通过偏函数,LocalStack、loca l中取值,响应时将local中的g数据删除
74、Flask中上下文管理主要涉及到了那些相关的类?并描述类主要作用?
flask
requestcontext
request
securecookiesessioninterface
securecookiesession
75、为什么要Flask把Local对象中的的值stack 维护成一个列表?
当是web应用时:不管是单线程还是多线程,栈中只有一个数据
- 服务端单线程:
{
111:{stack: [ctx, ]}
}
- 服务端多线程:
{
111:{stack: [ctx, ]}
112:{stack: [ctx, ]}
}
76、Flask中多app应用是怎么完成?
目的是想要将local中的值维护成一个栈,例如:在多app应用中编写离线脚本时,可以实用上。
from m_app import app01,app02
from flask import current_app
"""
{
1231: {
stack: [app01,app02,]
}
}
"""
with app01.app_context():
print(current_app)
with app02.app_context():
print(current_app)
print(current_app)
77、在Flask中实现WebSocket需要什么组件?
Flask-SocketIO
Flask-Sockets是Flask框架的一个扩展,通过它,Flask应用程序可以使用WebSocket。
https://blog.csdn.net/u013793383/article/details/72848252
https://github.com/miguelgrinberg/Flask-SocketIO
78、wtforms组件的作用?
WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证。
https://www.cnblogs.com/big-handsome-guy/p/8552079.html
https://www.cnblogs.com/liuwei0824/p/8330985.html
79、Flask框架默认session处理机制?
Flask的默认session利用了Werkzeug的SecureCookie,把信息做序列化(pickle)后编码(base64),放到cookie里了。
过期时间是通过cookie的过期时间实现的。
为了防止cookie内容被篡改,session会自动打上一个叫session的hash串,这个串是经过session内容、SECRET_KEY计算出来的,看得出,这种设计虽然不能保证session里的内容不泄露,但至少防止了不被篡改。
https://blog.csdn.net/qq_33733970/article/details/79008831
80、解释Flask框架中的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()
81、Flask中 blinker 是什么?
Flask框架中的信号基于blinker,可以让开发者在flask请求过程中 定制一些用户行为执行。
在请求前后,模板渲染前后,上下文前后,异常 的时候
82、SQLAlchemy中的 session和scoped_session 的区别?
使用scoped_session的目的主要是为了线程安全。
scoped_session类似单例模式,当我们调用使用的时候,会先在Registry里找找之前是否已经创建session了。
要是有,就把这个session返回。
要是没有,就创建新的session,注册到Registry中以便下次返回给调用者。
这样就实现了这样一个目的:在同一个线程中,call scoped_session 的时候,返回的是同一个对象
83、SQLAlchemy如何执行原生SQL?
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 ;')
84、ORM的实现原理?
概念: 对象关系映射(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。
详细介绍: 让我们从O/R开始。字母O起源于"对象"(Object),而R则来自于"关系"(Relational)。几乎所有的程序里面,都存在对象和关系数据库。在业务逻辑层和用户界面层中,我们是面向对象的。当对象信息发生变化的时候,我们需要把对象的信息保存在关系数据库中。
当你开发一个应用程序的时候(不使用O/R Mapping),你可能会写不少数据访问层的代码,用来从数据库保存,删除,读取对象信息,等等。你在DAL中写了很多的方法来读取对象数据,改变状态对象等等任务。而这些代码写起来总是重复的。
ORM解决的主要问题是对象关系的映射。域模型和关系模型分别是建立在概念模型的基础上的。域模型是面向对象的,而关系模型是面向关系的。一般情况下,一个持久化类和一个表对应,类的每个实例对应表中的一条记录,类的每个属性对应表的每个字段。
ORM技术特点:
1.提高了开发效率。由于ORM可以自动对Entity对象与数据库中的Table进行字段与属性的映射,所以我们实际可能已经不需要一个专用的、庞大的数据访问层。
2.ORM提供了对数据库的映射,不用sql直接编码,能够像操作对象一样从数据库获取数据。
85、DBUtils模块的作用?
使用DBUtils模块
两种使用模式:
1 为每个线程创建一个连接,连接不可控,需要控制线程数
2 创建指定数量的连接在连接池,当线程访问的时候去取,如果不够了线程排队,直到有人释放。平时建议使用这种!
86、以下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后面不应该加括号.如果加了,字段不会随时更新
87、SQLAchemy中如何为表设置引擎和字符编码?
sqlalchemy设置编码字符集一定要在数据库访问的URL上增加charset=utf8,否则数据库的连接就不是utf8的编码格式
eng = create_engine('mysql://root:root@localhost:3306/test2?charset=utf8',echo=True)
88、SQLAchemy中如何设置联合唯一索引?
UniqueConstraint 设置联合唯一索引
https://www.cnblogs.com/jasonwang-2016/p/5980237.html
89、简述Tornado框架的特点。
Tornado的独特之处在于其所有开发工具能够使用在应用开发的任意阶段以及任何档次的硬件资源上。而且,完整集的Tornado工具可以使开发人员完全不用考虑与目标连接的策略或目标存储区大小。Tornado 结构的专门设计为开发人员和第三方工具厂商提供了一个开放环境。已有部分应用程序接口可以利用并附带参考书目,内容从开发环境接口到连接实现。Tornado包括强大的开发和调试工具,尤其适用于面对大量问题的嵌入式开发人员。这些工具包括C和C++源码级别的调试器,目标和工具管理,系统目标跟踪,内存使用分析和自动配置. 另外,所有工具能很方便地同时运行,很容易增加和交互式开发。
90、简述Tornado框架中Future对象的作用?
http://python.jobbole.com/87310/
91、Tornado框架中如何编写WebSocket程序?
https://www.cnblogs.com/aguncn/p/5665916.html
92、Tornado中静态文件是如何处理的?
如:
处理方法:
static_path = os.path.join(os.paht.dirname(__file__), "static") #这里增加设置了静态路径
另外一个修改就是在实例化 tornado.web.Application() 的时候,在参数中,出了有静态路径参数 static_path ,还有一个参数设置 debug=True
93、Tornado操作MySQL使用的模块?
torndb是一个轻量级的基于MySQLdb封装的一个模块,从tornado3.0版本以后,其已经作为一个独立模块发行了。torndb依赖于MySQLdb模块,因此,在使用torndb模块时,要保证系统中已经有MySQLdb模块。
94、Tornado操作redis使用的模块?
tornado-redis
https://blog.csdn.net/guoqianqian5812/article/details/68587921
95、简述Tornado框架的适用场景?
Tornado是使用Python编写的一个强大的、可扩展的Web服务器。它在处理严峻的网络流量时表现得足够强健,但却在创建和编写时有着足够的轻量级,并能够被用在大量的应用和工具中。
我们现在所知道的Tornado是基于Bret Taylor和其他人员为FriendFeed所开发的网络服务框架,当FriendFeed被Facebook收购后得以开源。不同于那些最多只能达到10,000个并发连接的传统网络服务器,Tornado在设计之初就考虑到了性能因素,旨在解决C10K问题,这样的设计使得其成为一个拥有非常高性能的框架。此外,它还拥有处理安全性、用户验证、社交网络以及与外部服务(如数据库和网站API)进行异步交互的工具。
https://www.cnblogs.com/luotianshuai/p/5482612.html
96、git常见命令作用:
某个文件夹中的内容进行版本管理:
进入文件夹,右键git bash
git init 初始化,当前所在的文件夹可以被管理且以后版本相关的数据都会存储到.git文件中
git status 查看当前文件夹以及子目录中文件是否发生变化:内容修改/新增文件/删除,已经变化的文件会变成红色,已经add的文件会变成绿色
git add . 给发生变化的文件(贴上一个标签)或 将发生变化的文件放到某个地方,只写一个句点符就代表把git status中红色的文件全部打上标签
git commit -m '新增用户登录认证功能以及xxx功能' 将“绿色”文件添加到版本中
git log 查看所有版本提交记录,可以获取版本号
git reset --hard 版本号 将最新的版本回退到更早的版本
git reflog 回退到之前版本后悔了,再更新到最新或者最新之前的版本
git reset --hard 版本 回退
97、简述以下git中stash命令作用以及相关其他命令。
stash用于将工作区发生变化的所有文件获取临时存储在“某个地方”,将工作区还原当前版本未操作前的状态;stash还可以将临时存储在“某个地方”的文件再次拿回到工作区。
git stash 将当前工作区所有修改过的内容存储到“某个地方”,将工作区还原到当前版本未修改过的状态
git stash list 查看“某个地方”存储的所有记录
git stash clear 清空“某个地方”
git stash pop 将第一个记录从“某个地方”重新拿到工作区(可能有冲突)
git stash apply 编号, 将指定编号记录从“某个地方”重新拿到工作区(可能有冲突)
git stash drop 编号,删除指定编号的记录
98、git 中 merge 和 rebase命令 的区别。
https://www.cnblogs.com/xueweihan/p/5743327.html
99、公司如何基于git做的协同开发?
https://www.cnblogs.com/abelsu/p/5138136.html
100、如何基于git实现代码review?
https://blog.csdn.net/maray/article/details/50206927
101、git如何实现v1.0 、v2.0 等版本的管理?
https://blog.csdn.net/zhazhaji/article/details/75258426
102、什么是gitlab?
GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的web服务。安装方法是参考GitLab在GitHub上的Wiki页面。
103、github和gitlab的区别?
先说一下相同点,二者都是基于web的Git仓库,在很大程度上GitLab是仿照GitHub来做的,它们都提供了分享开源项目的平台,为开发团队提供了存储、分享、发布和合作开发项目的中心化云存储的场所。
GitHub作为开源代码库及版本控制系统,拥有超过900万的开发者用户,目前仍然是最火的开源项目托管系统。GitHub同时提供公共仓库和私有仓库,但如果要使用私有仓库,是需要付费的。
而GitLab解决了这个问题,你可以在上面创建私人的免费仓库。
GitLab让开发团队对他们的代码仓库拥有更多的控制,相比于GitHub,它有不少的特色:
允许免费设置仓库权限;允许用户选择分享一个project的部分代码;允许用户设置project的获取权限,进一步的提升安全性;可以设置获取到团队整体的改进进度;通过innersourcing让不在权限范围内的人访问不到该资源。
从代码私有性方面来看,有时公司并不希望员工获取到全部的代码,这个时候GitLab无疑是更好的选择。但对于开源项目而言,GitHub依然是代码托管的首选。
104、如何为github上牛逼的开源项目贡献代码?
对一个开源项目有足够了解的情况下,如果你发现问题或者更好的解决方案的话,可以开个issue先。
一般情况下维护这个项目的人或者其他使用这个项目的人会参与讨论的,然后基于这些讨论你可以发一些pull requests。
如果你的方案得到很多人赞同的话,项目维护人员会把他们merge,你也就成了这个项目的contributor了。
当然很多情况下,你开的这个issue已经有人提过了,或者说是你自己误解了,但是相信在和其他开发人员交流的过程中,你也能学到许多。
105、git中 .gitignore文件的作用?
一般来说每个Git项目中都需要一个“.gitignore”文件,这个文件的作用就是告诉Git哪些文件不需要添加到版本管理中。
实际项目中,很多文件都是不需要版本管理的,比如Python的.pyc文件和一些包含密码的配置文件等等。
106、什么是敏捷开发?
敏捷开发以用户的需求进化为核心,采用迭代、循序渐进的方法进行软件开发。在敏捷开发中,软件项目在构建初期被切分成多个子项目,各个子项目的成果都经过测试,具备可视、可集成和可运行使用的特征。换言之,就是把一个大项目分为多个相互联系,但也可独立运行的小项目,并分别完成,在此过程中软件一直处于可使用状态。
107、简述 jenkins 工具的作用?
Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。
108、公司如何实现代码发布?
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命令同步代码到生产环境。
109、简述 RabbitMQ、Kafka、ZeroMQ的区别?
RabbitMQ
RabbitMQ是使用Erlang编写的一个开源的消息队列,本身支持很多的协议:AMQP,XMPP, SMTP, STOMP,也正因如此,它非常重量级,更适合于企业级的开发。同时实现了Broker构架,这意味着消息在发送给客户端时先在中心队列排队。对路由,负载均衡或者数据持久化都有很好的支持。
Redis
Redis是一个基于Key-Value对的NoSQL数据库,开发维护很活跃。虽然它是一个Key-Value数据库存储系统,但它本身支持MQ功能,所以完全可以当做一个轻量级的队列服务来使用。对于RabbitMQ和Redis的入队和出队操作,各执行100万次,每10万次记录一次执行时间。测试数据分为128Bytes、512Bytes、1K和10K四个不同大小的数据。实验表明:入队时,当数据比较小时Redis的性能要高于RabbitMQ,而如果数据大小超过了10K,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)的系统开销下进行消息持久化;高吞吐,在一台普通的服务器上既可以达到10W/s的吞吐速率;完全的分布式系统,Broker、Producer、Consumer都原生自动支持分布式,自动实现负载均衡;支持Hadoop数据并行加载,对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。Kafka通过Hadoop的并行加载机制统一了在线和离线的消息处理。Apache Kafka相对于ActiveMQ是一个非常轻量级的消息系统,除了性能非常好之外,还是一个工作良好的分布式系统。
110、RabbitMQ如何在消费者获取任务后未处理完前就挂掉时,保证数据不丢失?
111、RabbitMQ如何对消息做持久化?
https://www.cnblogs.com/xiangjun555/articles/7874006.html
112、RabbitMQ如何控制消息被消费的顺序?
https://blog.csdn.net/varyall/article/details/79111745
113、以下RabbitMQ的exchange type分别代表什么意思?如:fanout、direct、topic。
https://www.cnblogs.com/shenyixin/p/9084249.html
114、简述 celery 是什么以及应用场景?
Celery是由Python开发的一个简单、灵活、可靠的处理大量任务的分发系统,它不仅支持实时处理也支持任务调度。
http://www.cnblogs.com/wupeiqi/articles/8796552.html
115、简述celery运行机制。
116、celery如何实现定时任务?
117、简述 celery多任务结构目录?
118、celery中装饰器 @app.task 和 @shared_task的区别?
119、简述 requests模块的作用及基本使用?
模拟浏览器发送请求
http://www.cnblogs.com/linhaifeng/articles/7785043.html
120、简述 beautifulsoup模块的作用及基本使用?
Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库
http://www.cnblogs.com/linhaifeng/articles/7783586.html
121、简述 seleninu模块的作用及基本使用?
selenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题
selenium本质是通过驱动浏览器,完全模拟浏览器的操作,比如跳转、输入、点击、下拉等,来拿到网页渲染之后的结果,可支持多种浏览器
http://www.cnblogs.com/linhaifeng/articles/7783599.html
122、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)
123、在scrapy框架中如何设置代理(两种方法)?
scrapy自带的代理组件:
from scrapy.downloadermiddlewares.httpproxy import HttpProxyMiddleware
from urllib.request import getproxies
124、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()
125、scrapy中如何实现限速?
ttp://scrapy-chs.readthedocs.io/zh_CN/1.0/topics/autothrottle.html
126、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
127、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
128、scrapy中如何实现的记录爬虫的深度?
class scrapy.contrib.spidermiddleware.depth.DepthMiddleware
DepthMiddleware是一个用于追踪每个Request在被爬取的网站的深度的中间件。 其可以用来限制爬取深度的最大深度或类似的事情。
DepthMiddleware 可以通过下列设置进行配置(更多内容请参考设置文档):
DEPTH_LIMIT - 爬取所允许的最大深度,如果为0,则没有限制。
DEPTH_STATS - 是否收集爬取状态。
DEPTH_PRIORITY - 是否根据其深度对requet安排优先级
129、scrapy中的pipelines工作原理?
Scrapy 提供了 pipeline 模块来执行保存数据的操作。在创建的 Scrapy 项目中自动创建了一个 pipeline.py 文件,同时创建了一个默认的 Pipeline 类。我们可以根据需要自定义 Pipeline 类,然后在 settings.py 文件中进行配置即可
https://blog.csdn.net/Ahri_J/article/details/72472170
130、scrapy的pipelines如何丢弃一个item对象?
131、简述scrapy中爬虫中间件和下载中间件的作用?
http://www.cnblogs.com/wupeiqi/articles/6229292.html
132、scrapy-redis组件的作用?
scheduler - 调度器
dupefilter - URL去重规则(被调度器使用)
pipeline - 数据持久化
133、scrapy-redis组件中如何实现的任务的去重?
定义去重规则(被调度器调用并应用)
a. 内部会使用以下配置进行连接Redis
# REDIS_HOST = 'localhost' # 主机名
# REDIS_PORT = 6379 # 端口
# REDIS_URL = 'redis://user:pass@hostname:9001' # 连接URL(优先于以上配置)
# REDIS_PARAMS = {} # Redis连接参数 默认:REDIS_PARAMS = {'socket_timeout': 30,'socket_connect_timeout': 30,'retry_on_timeout': True,'encoding': REDIS_ENCODING,})
# REDIS_PARAMS['redis_cls'] = 'myproject.RedisClient' # 指定连接Redis的Python模块 默认:redis.StrictRedis
# REDIS_ENCODING = "utf-8" # redis编码类型 默认:'utf-8'
b. 去重规则通过redis的集合完成,集合的Key为:
key = defaults.DUPEFILTER_KEY % {'timestamp': int(time.time())}
默认配置:
DUPEFILTER_KEY = 'dupefilter:%(timestamp)s'
c. 去重规则中将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可以设置指定请求头
示例:
from scrapy.utils import request
from scrapy.http import Request
req = Request(url='http://www.baidu.com?name=8&id=1',callback=lambda x:print(x),cookies={'k1':'vvvvv'})
result = request.request_fingerprint(req,include_headers=['cookies',])
print(result)
req = Request(url='http://www.baidu.com?id=1&name=8',callback=lambda x:print(x),cookies={'k1':666})
result = request.request_fingerprint(req,include_headers=['cookies',])
print(result)
"""
# Ensure all spiders share same duplicates filter through redis.
# DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
134、scrapy-redis的调度器如何实现任务的深度优先和广度优先?
# SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue' # 默认使用优先级队列(默认),其他: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
# SCHEDULER_DUPEFILTER_CLASS = 'scrapy_redis.dupefilter.RFPDupeFilter'# 去重规则对应处理的类
#
#
#
# REDIS_HOST = '10.211.55.13' # 主机名
# REDIS_PORT = 6379 # 端口
# # REDIS_URL = 'redis://user:pass@hostname:9001' # 连接URL(优先于以上配置)
# # REDIS_PARAMS = {} # Redis连接参数 默认:REDIS_PARAMS = {'socket_timeout': 30,'socket_connect_timeout': 30,'retry_on_timeout': True,'encoding': REDIS_ENCODING,})
# # REDIS_PARAMS['redis_cls'] = 'myproject.RedisClient' # 指定连接Redis的Python模块 默认:redis.StrictRedis
# REDIS_ENCODING = "utf-8" # redis编码类型 默认:'utf-8'
135、述 vitualenv 及应用场景?
virtualenv就是用来为一个应用创建一套“隔离”的Python运行环境。
https://www.cnblogs.com/technologylife/p/6635631.html
136、简述 pipreqs 及应用场景?
查找python项目依赖并生成requirements.txt
137、在Python中使用过什么代码检查工具?
1)PyFlakes:静态检查Python代码逻辑错误的工具。
2)Pep8: 静态检查PEP8编码风格的工具。
3)NedBatchelder’s McCabe script:静态分析Python代码复杂度的工具。
Python代码分析工具:PyChecker、Pylint
138、简述 saltstack、ansible、fabric、puppet工具的作用?
139、B Tree和B+ Tree的区别?
https://www.jianshu.com/p/0371c9569736
140、请列举常见排序并通过代码实现任意三种。
冒泡/选择/插入/快排
https://blog.csdn.net/qq_27695659/article/details/88937361
141、请列举常见查找并通过代码实现任意三种。
无序查找/二分查找/插值查找
https://blog.csdn.net/qq_27695659/article/details/88937699
142、请列举你熟悉的设计模式?
工厂模式/单例模式等
https://www.cnblogs.com/Liqiongyu/p/5916710.html
143、有没有刷过leetcode?
刷过--英文的
144、列举熟悉的的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
145、公司线上服务器是什么系统?
Linux/Centos
146、解释 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。
147、解释 QPS的含义?
Query Per Second
每秒查询率QPS是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。
148、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协议等。
149、supervisor的作用?
supervisor管理进程,是通过fork/exec的方式将这些被管理的进程当作supervisor的子进程来启动,所以我们只需要将要管理进程的可执行文件的路径添加到supervisor的配置文件中就好了。此时被管理进程被视为supervisor的子进程,若该子进程异常终端,则父进程可以准确的获取子进程异常终端的信息,通过在配置文件中设置autostart=ture,可以实现对异常中断的子进程的自动重启。
150、什么是反向代理?
反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。
151、简述SSH的整个过程。
SSH 为 Secure Shell 的缩写,由 IETF 的网络小组(Network Working Group)所制定;SSH 为建立在应用层基础上的安全协议。SSH 是目前较可靠,专为远程登录会话和其他网络服务提供安全性的协议。利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题。
152、有问题都去那些找解决方案?
cn.bing.cn
google.com
csdn.net
zhihu.com
stackflow
github.com/issue
cnblogs
jianshu
官方文档
153、是否有关注什么技术类的公众号?
机器之心
AIlearning
PaperWeekly
154、最近在研究什么新技术?
机器学习
神经网络
算法
论文
NP完全问题、霍奇猜想、庞加莱猜想、黎曼假设、杨-米尔斯存在性和质量缺口、纳卫尔-斯托可方程、BSD猜想
155、是否了解过领域驱动模型?
https://www.cnblogs.com/netfocus/archive/2011/10/10/2204949.html