程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长

+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

python后端面试题

发布于2019-07-12 10:01     阅读(3720)     评论(0)     点赞(1)     收藏(17)


 

 


===============第一部分 Python基础篇(80题)===============

1. 为什么学习Python?


  是爱吗?是责任吗?都不是,是TMD穷!

2. 通过什么途径学习的Python?


  大街上有人看我骨骼精奇,是万中无一的编程奇才,卖我本《21天精通Python》,然后……

3. Python和Java、PHP、C、C#、C++等其他语言的对比?

  
  PHP是世界上最好的语言,Python多少差点意思

4. 简述解释型和编译型编程语言?

    编译型:运行前先由编译器将高级语言代码编译为对应机器的cpu汇编指令集,再由汇编器汇编为目标机器码,生成可执行文件,然最后运行生成的可执行文件。最典型的代表语言为C/C++,一般生成的可执行文件及.exe文件。 

    解释型:在运行时由翻译器将高级语言代码翻译成易于执行的中间代码,并由解释器(例如浏览器、虚拟机)逐一将该中间代码解释成机器码并执行(可看做是将编译、运行合二为一了)。最典型的代表语言为JavaScript、Python、Ruby和Perl等。 

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

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

  IronPython

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

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

6. 位和字节的关系?

  1.位(bit) 
  来自英文bit,表示二进制位。位是计算机内部数据储存的最小单位,11010100是一个8位二进制数。一个二进制位只可以表示0和1两种状态;两个二进制位可以表示00、01、10、11四种状态;三位二进制数可表示八种状态。  

  2.字节(byte)  
  字节来自英文Byte,习惯上用大写的“B”表示。  
  字节是计算机中数据处理的基本单位。计算机中以字节为单位存储和解释信息,规定一个字节由八个二进制位构成,即1个字节等于8个比特(1Byte=8bit)。八位二进制数最小为00000000,最大为11111111;通常1个字节可以存入一个ASCII码,2个字节可以存放一个汉字国标码。

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

  
  1024

8. 请至少列举5个 PEP8 规范(越多越好)。

  缩进/空格/注释/命名等
  http://blog.sae.sina.com.cn/archives/4781

9. 通过代码实现进制转换

  ## 二进制转换成十进制:v = “0b1111011”
  ## 十进制转换成二进制:v = 18
  ## 八进制转换成十进制:v = “011”
  ## 十进制转换成八进制:v = 30
  ## 十六进制转换成十进制:v = “0x12”
  ## 十进制转换成十六进制:v = 87
  1) 二进制数、转换为十进制数的规律是:把二进制数按位权形式展开多项式和的形式,求其最后的和,就是其对应的十进制数——简称“按权求和”。
  2) 十进制整数转换为二进制整数采用"除2取余,逆序排列"法。具体做法是:用2去除十进制整数,可以得到一个商和余数;再用2去除商,又会得到一个商和余数,如此进行,直到商为零时为止,然后把先得到的余数作为二进制数的低位有效位,后得到的余数作为二进制数的高位有效位,依次排列起来。

  10进制,当然是便于我们人类来使用,我们从小的习惯就是使用十进制,这个毋庸置疑。
  2进制,是供计算机使用的,1,0代表开和关,有和无,机器只认识2进制。
  16进制,内存地址空间是用16进制的数据表示, 如0x8039326。

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

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


  ip_addr='192.168.2.10'
  # transfer ip to int
  def ip2long(ip):
      ip_list=ip.split('.')
      result=0
      for i in range(4):  #0,1,2,3
          result=result+int(ip_list[i])*256**(3-i)
      return result


  long=3232236042

  # transfer int to ip
  def long2ip(long):
      floor_list=[]
      yushu=long
      for i in reversed(range(4)):   #3,2,1,0
          res=divmod(yushu,256**i)
          floor_list.append(str(res[0]))
          yushu=res[1]
      return '.'.join(floor_list)



  a=long2ip(long)
  print(a)

11. python递归的最大层数?


  998

12. 求逻辑运算符的结果

  ##     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   # False

结论:
真假比 若都真
or选前 and选后

13. ascii、unicode、utf-8、gbk 区别?


  http://www.cnblogs.com/zhuwenlubin/p/5131026.html

14. 字节码和机器码的区别?

  机器码
  机器码(machine code),学名机器语言指令,有时也被称为原生码(Native Code),是电脑的CPU可直接解读的数据。

  通常意义上来理解的话,机器码就是计算机可以直接执行,并且执行速度最快的代码。

  用机器语言编写程序,编程人员要首先熟记所用计算机的全部指令代码和代码的涵义。手编程序时,程序员得自己处理每条指令和每一数据的存储分配和输入输出,还得记住编程过程中每步所使用的工作单元处在何种状态。这是一件十分繁琐的工作,编写程序花费的时间往往是实际运行时间的几十倍或几百倍。而且,编出的程序全是些0和1的指令代码,直观性差,还容易出错。现在,除了计算机生产厂家的专业人员外,绝大多数的程序员已经不再去学习机器语言了。

  机器语言是微处理器理解和使用的,用于控制它的操作二进制代码。
  8086到Pentium的机器语言指令长度可以从1字节到13字节。
  尽管机器语言好像是很复杂的,然而它是有规律的。
  存在着多至100000种机器语言的指令。这意味着不能把这些种类全部列出来。
  总结:机器码是电脑CPU直接读取运行的机器指令,运行速度最快,但是非常晦涩难懂,也比较难编写,一般从业人员接触不到。

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

  通常情况下它是已经经过编译,但与特定机器码无关。字节码通常不像源码一样可以让人阅读,而是编码后的数值常量、引用、指令等构成的序列。

  字节码主要为了实现特定软件运行和软件环境、与硬件环境无关。字节码的实现方式是通过编译器和虚拟机器。编译器将源码编译成字节码,特定平台上的虚拟机器将字节码转译为可以直接执行的指令。字节码的典型应用为Java bytecode。

  字节码在运行时通过JVM(JAVA虚拟机)做一次转换生成机器指令,因此能够更好的跨平台运行。

  总结:字节码是一种中间状态(中间码)的二进制代码(文件)。需要直译器转译后才能成为机器码。

15. 三元运算规则以及应用场景?


  简化if语句

16. 列举 Python2和Python3的区别?

  py2和py3:
  1. 文件操作:  xreadlines

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

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

  f.close()

  2. 字符串:
  py2:
  str: 字符串   -> 字节
  unicode: u"sdfsdf"
  py3:
    bytes:
  str:
  3. 默认解释器编码
  py2: ascii
  py3: utf-8

  5. 
  py2: range/xrange 
  py3:       range 

  6. 
  py2: int / long
  py3: int 

  7. input/raw_input 

  8. 
  py2: yield
  py3: yield/yield from 

  9. 
  py2: 新式类和经典类
  py3: 新式类

17. 用一行代码实现数值交换


  a,b=b,a

18. Python3和Python2中 int 和 long的区别?


  python3 彻底废弃了 long+int 双整数实现的方法, 统一为 int , 支持高精度整数运算.

19. xrange和range的区别?


  函数说明:和range 的用法完全相同,但是返回的是一个生成器。 

20. 文件操作时:xreadlines和readlines的区别?

   1) read([size])方法从文件当前位置起读取size个字节,若无参数size,则表示读取至文件结束为止,它范围为字符串对象
    2) 从字面意思可以看出,该方法每次读出一行内容,所以,读取时占用内存小,比较适合大文件,该方法返回一个字符串对象。
    3) readlines()方法读取整个文件所有行,保存在一个列表(list)变量中,每行作为一个元素,但读取大文件会比较占内存。

21. 列举布尔值为False的常见值?

  布尔型,False表示False,其他为True
  整数和浮点数,0表示False,其他为True
  字符串和类字符串类型(包括bytes和unicode),空字符串表示False,其他为True
  序列类型(包括tuple,list,dict,set等),空表示False,非空表示True
  None永远表示False

22. 字符串、列表、元组、字典每个常用的5个方法?

  - 字符串  split/strip/replace/find/index ...
  - 列表     append/extend/insert/push/pop/reverse/sort ...
  - 元组     len/max/min/count/index ...
  - 字典     keys/values/pop/clear/del ...
  - 集合  add/remove/clear/交集&、并集 |、差集 - 
   
  - collections  Python内建的一个集合模块,提供了许多有用的集合类。
      1.Counter是一个简单的计数器,例如,统计字符出现的个数;
      2.OrderedDict可以实现一个FIFO(先进先出)的dict,当容量超出限制时,先删除最早添加的Key;
      3.deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈;
      4.defaultdict使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict;

23. lambda表达式格式以及应用场景?

  省去函数命名的烦恼
  http://www.cnblogs.com/guigujun/p/6134828.html

24. pass的作用?


  当你在编写一个程序时,执行语句部分思路还没有完成,这时你可以用pass语句来占位,也可以当做是一个标记,是要过后来完成的代码。

25. arg和kwarg作用

  *args:(表示的就是将实参中按照位置传值,多出来的值都给args,且以元组的方式呈现)
  **kwargs:(表示的就是形参中按照关键字传值把多余的传值以字典的方式呈现)
  http://www.cnblogs.com/xuyuanyuan123/p/6674645.html

26. is和==的区别

  is 比较的是两个实例对象是不是完全相同,它们是不是同一个对象,占用的内存地址是否相同。莱布尼茨说过:“世界上没有两片完全相同的叶子”,这个is正是这样的比较,比较是不是同一片叶子(即比较的id是否相同,这id类似于人的身份证标识)。

  == 比较的是两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以了。这里比较的并非是同一片叶子,可能叶子的种类或者脉络相同就可以了。默认会调用对象的 __eq__()方法。

27. 简述Python的深浅拷贝以及应用场景?

  Python采用基于值得内存管理模式,赋值语句的执行过程是:首先把等号右侧标识的表达式计算出来,然后在内存中找一个位置把值存放进去,最后创建变量并指向这个内存地址。Python中的变量并不直接存储值,而是存储了值的内存地址或者引用
  简单地说,浅拷贝只拷贝一层(如果有嵌套),深拷贝拷贝所有层。
  一层的情况:
    import copy

    # 浅拷贝

    li1 = [1, 2, 3]
    li2 = li1.copy()
    li1.append(4)
    print(li1, li2)  # [1, 2, 3, 4] [1, 2, 3]

    # 深拷贝

    li1 = [1, 2, 3]
    li2 = copy.deepcopy(li1)
    li1.append(4)
    print(li1, li2)  # [1, 2, 3, 4] [1, 2, 3]
  多层的情况:
    import copy

    # 浅拷贝

    li1 = [1, 2, 3, [4, 5], 6]
    li2 = li1.copy()
    li1[3].append(7)
    print(li1, li2)  # [1, 2, 3, [4, 5, 7], 6] [1, 2, 3, [4, 5, 7], 6]

    # 深拷贝

    li1 = [1, 2, 3, [4, 5], 6]
    li2 = copy.deepcopy(li1)
    li1[3].append(7)
    print(li1, li2)  # [1, 2, 3, [4, 5, 7], 6] [1, 2, 3, [4, 5], 6]

28. Python垃圾回收机制?

  Python GC主要使用引用计数(reference counting)来跟踪和回收垃圾。在引用计数的基础上,通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用问题,通过“分代回收”(generation collection)以空间换时间的方法提高垃圾回收效率。

  1 引用计数

  PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少.引用计数为0时,该对象生命就结束了。

  优点:

  简单 实时性 缺点:

  维护引用计数消耗资源 循环引用

  2 标记-清除机制

  基本思路是先按需分配,等到没有空闲内存的时候从寄存器和程序栈上的引用出发,遍历以对象为节点、以引用为边构成的图,把所有可以访问到的对象打上标记,然后清扫一遍内存空间,把所有没标记的对象释放。

  3 分代技术

  分代回收的整体思想是:将系统中的所有内存块根据其存活时间划分为不同的集合,每个集合就成为一个“代”,垃圾收集频率随着“代”的存活时间的增大而减小,存活时间通常利用经过几次垃圾回收来度量。

  Python默认定义了三代对象集合,索引数越大,对象存活时间越长。

  http://python.jobbole.com/82061/

29. Python的可变类型和不可变类型?

  在Python中不可变对象指:一旦创建就不可修改的对象,包括字符串,元组,数字

  在Python中可变对象是指:可以修改的对象,包括:列表、字典

30. 求可变数据类型结果

  v = dict.fromkeys(['k1','k2'],[])
  v['k1'].append(666)
  print(v)    # {'k1': [666], 'k2': [666]}
  v['k1'] = 777
  print(v)    # {'k1': 777, 'k2': [666]}

31. 求匿名函数结果

  def num():
    return[lambda x: i*x for i in range(4)]

  print([m(2) for m in num()])    # [6, 6, 6, 6]

32. 列举常见的内置函数?

   long(x)
    float(x)  # 把x转换成浮点数
    complex(x) # 转换成复数
    str(x)   # 转换成字符串
    list(x)  # 转换成列表
    tuple(x) # 转换成元组
     
    进制相互转换
     r= bin(10) #二进制
     r= int(10) #十进制

     r = oct(10) #八进制
     r = hex(10) #十六进制
     i= int("11",base=10)#进制间的相互转换base后跟 2/8/10/16
     print(i)
     
    chr(x)//返回x对应的字符,如chr(65)返回‘A'
    ord(x)//返回字符对应的ASC码数字编号,如ord('A')返回65
    abs(),all(),any(),bin(),bool(),bytes(),chr(),dict()dir(),divmod(),enumerate(),eval(),filter(),float(),gloabls(),help(),hex(),id(),input(),int(),isinstance(),len(),list(),locals(),map(),max(),min(),oct(),open(),ord(),pow(),print(),range(),round(),set(),type(),sorted(),str(),sum(),tuple()

33. filter、map、reduce的作用?

  filter:对于序列中的元素进行筛选,最终获取符合条件的序列
  map:遍历序列,对序列中每个元素进行操作,最终获取新的序列
  reduce:对于序列内所有元素进行累计操作

34. 一行代码实现9乘9乘法表


  print("\n".join("\t".join(["%s*%s=%s" %(x,y,x*y) for y in range(1, x+1)]) for x in range(1, 10)) )

35. 如何安装第三方模块?以及用过哪些第三方模块?

  - pip包管理器
  - 源码安装
      - 下载->解压->cd 到对应路径
      - python setup.py build
      - python setup.py install 

36. 常用模块都有哪些?


  - re/json/logging/os/sys/requests/beautifulsoup4

37. re的match和search区别?

  match和search的区别

  re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;
  re.search匹配整个字符串,直到找到一个匹配。

38. 什么是正则的贪婪匹配?

  贪婪和非贪婪
  正则表达式通常用于在文本中查找匹配的字符串。Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;非贪婪则相反,总是尝试匹配尽可能少的字符。在"*","?","+","{m,n}"后面加上?,使贪婪变成非贪婪。

39. 求结果:a. [ i % 2 for i in range(10) ] b. ( i % 2 for i in range(10) )

  [ i % 2 for i in range(10) ]  # [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
  ( i % 2 for i in range(10) )  # <generator object <genexpr> at 0x0000000003180FC0>

40. 求结果:a. 1 or 2 b. 1 and 2 c. 1 < (2==2) d. 1 < 2 == 2

  1
  2
  False
  True

41. def func(a,b=[]) 这种写法有什么坑?

  def func(a, b=[]):
      b.append(a)
      return b
   
   
  s = func(1)
  print(s)  # [1]
  s = func(1)
  print(s)  # [1, 1]
   
  # 第二次调用的时候 b的初始值是[1]了

42. 如何实现 “1,2,3” 变成 [‘1’,’2’,’3’] ?


  list("1,2,3".split(','))

43. 如何实现[‘1’,’2’,’3’]变成[1,2,3] ?


  [int(x) for x in ['1','2','3']]

44. 比较: a = [1,2,3] 和 b = [(1),(2),(3) ] 以及 b = [(1,),(2,),(3,) ] 的区别?

  前两个列表内是int
  最后一个列表内是元组

45. 如何用一行代码生成[1,4,9,16,25,36,49,64,81,100] ?


  i*i for i in range(1,11)]

46. 一行代码实现删除列表中重复的值 ?


  list(set([1, 2, 3, 4, 45, 1, 2, 343, 2, 2]))

47. 如何在函数中设置一个全局变量 ?


  在函数中定义的局部变量如果和全局变量同名,则它会隐藏该全局变量。如果想在函数中使用全局变量,则需要使用global进行声明。

48. logging模块的作用?以及应用场景?

  logging模块是Python内置的标准模块,主要用于输出运行日志,可以设置输出日志的等级、日志保存路径、日志文件回滚等;相比print,具备如下优点:

    可以通过设置不同的日志等级,在release版本中只输出重要信息,而不必显示大量的调试信息;

    print将所有信息都输出到标准输出中,严重影响开发者从标准输出中查看其它数据;logging则可以由开发者决定将信息输出到什么地方,以及怎么输出。
    https://www.cnblogs.com/testdjt/p/7834856.html

49. 请用代码简单实现一个栈。

  # 后进先出
  class Stack():
      def __init__(self, size):
          self.size = size
          self.stack = []
          self.top = -1

      # 入栈之前检查栈是否已满
      def push(self, x):
          if self.isfull():
              raise exception("stack is full")
          else:
              self.stack.append(x)
              self.top = self.top + 1

      # 出栈之前检查栈是否为空
      def pop(self):
          if self.isempty():
              raise exception("stack is empty")
          else:
              self.top = self.top - 1
              self.stack.pop()

      def isfull(self):
          return self.top + 1 == self.size

      def isempty(self):
          return self.top == '-1'

      def showStack(self):
          print(self.stack)


  s = Stack(10)
  for i in range(6):
      s.push(i)  # 入栈
  s.showStack()  # [0, 1, 2, 3, 4, 5]

  for i in range(2):
      s.pop()  # 出栈
  s.showStack()  # [0, 1, 2, 3]

50. 常用字符串格式化哪几种?


  Python的字符串格式化有两种方式:%格式符方式,format方式

51. 简述 生成器、迭代器、可迭代对象 以及应用场景?

  如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration)刚才说过,很多容器都是可迭代对象,此外还有更多的对象同样也是可迭代对象,比如处于打开状态的files,sockets等等。但凡是可以返回一个 迭代器 的对象都可称之为可迭代对象
  那么什么迭代器呢?它是一个带状态的对象,他能在你调用 next() 方法的时候返回容器中的下一个值,任何实现了 __next__() (python2中实现 next() )方法的对象都是迭代器
  生成器算得上是Python语言中最吸引人的特性之一,生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅。生成器(yield)不需要再像上面的类一样写 __iter__() 和 __next__() 方法了,只需要一个 yiled 关键字。 生成器有如下特征是它一定也是迭代器(反之不成立),因此任何生成器也是以一种懒加载的模式生成值。
  http://www.cnblogs.com/yuanchenqi/articles/5769491.html

52. 用Python实现一个二分查找的函数。

  def bin_search_rec(data_set, value, low, high):
      if low <= high:
          mid = (low + high) // 2
          if data_set[mid] == value:
              return mid
          elif data_set[mid] > value:
              return bin_search_rec(data_set, value, low, mid - 1)
          else:
              return bin_search_rec(data_set, value, mid + 1, high)
      else:
          return

53. 谈谈你对闭包的理解?


  https://www.cnblogs.com/Lin-Yi/p/7305364.html

54. os和sys模块的作用?

  os就是一个普通的python库,用来向Python程序提供运行环境,特别是在文件系统、创建新进程、获取操作系统本身的一些信息(比如uname),并屏蔽各种不同操作系统之间的细节差异。
  sys模块则是python程序用来请求解释器行为的接口。比如关于调试类的(trace, frames,except)等,profiling类(stats, getsizeof),运行时环境类(python path, stderr, stdout),解释器本身(如version)。inspect某种程度上可以看成是在sys提供的功能上的一个包装。

55. 如何生成一个随机数?


  random.randint(a,b)

56. 如何使用python删除一个文件?

  删除子目录
  os.rmdir( path )   # path: "要删除的子目录"

  产生异常的可能原因:
  (1) path 不存在
  (2) path 子目录中有文件或下级子目录
  (3) 没有操作权限或只读

  删除文件
  os.remove(   filename )   # filename: "要删除的文件名"

  产生异常的可能原因:
  (1)   filename 不存在
  (2) 对filename文件, 没有操作权限或只读。

57. 谈谈你对面向对象的理解?

  从三大特性说起:继承、封装、多态
  
  封装:
      起始就是将很多数据封装到一个对象中,类似于把很多东西放到一个箱子中,
      如:一个函数如果好多参数,起始就可以把参数封装到一个对象再传递。
      
      在哪里用过:
        - django rest framework中的request对象。
        - flask中:ctx_context/app_context对象
  继承:
      如果多个类中都有共同的方法,那么为了避免反复编写,就可以将方法提取到基类中实现,
      让所有派生类去继承即可。
      
      在哪里用过?
        - 视图
        - 版本、认证、分页
  多态:
      python本身就是多态的,崇尚鸭子模型,只要会呱呱叫的就是鸭子。
      def func(arg):
        arg.send()
  https://www.cnblogs.com/iyouyue/p/8535796.html

58. Python面向对象中的继承有什么特点?

  Python3的继承机制
    子类在调用某个方法或变量的时候,首先在自己内部查找,如果没有找到,则开始根据继承机制在父类里查找。
    根据父类定义中的顺序,以深度优先的方式逐一查找父类!
    继承参数的书写有先后顺序,写在前面的被优先继承。

59. 面向对象深度优先和广度优先是什么?

  继承顺序
  http://www.liujiangblog.com/course/python/44

60. 面向对象中super的作用?

  我们都知道,在子类中如果有与父类同名的成员,那就会覆盖掉父类里的成员。那如果你想强制调用父类的成员呢?使用super()函数!这是一个非常重要的函数,最常见的就是通过super调用父类的实例化方法__init__!

  语法:super(子类名, self).方法名(),需要传入的是子类名和self,调用的是父类里的方法,按父类的方法需要传入参数。
  class A:
      def __init__(self, name):
          self.name = name
          print("父类的__init__方法被执行了!")
      def show(self):
          print("父类的show方法被执行了!")

  class B(A):
      def __init__(self, name, age):
          super(B, self).__init__(name=name)
          self.age = age

      def show(self):
          super(B, self).show()

  obj = B("jack", 18)
  obj.show()

61. 是否使用过functools中的函数?其作用是什么?

  1.functools.partial
  官网文档说的真是不好理解,就当作是把一个函数,绑定部分或者全部参数后生成一个新版本的函数
  2.functools.partialwrap
  文档说的比较详细,如果不使用这个wraps,那么原始函数的__name__和__doc__都会丢失
  https://blog.csdn.net/secretx/article/details/51700361

62. 列举面向对象中带双下划线的特殊方法,如:newinit

  __init__ :      构造函数,在生成对象时调用
  __del__ :       析构函数,释放对象时使用
  __repr__ :      打印,转换
  __setitem__ :   按照索引赋值
  __getitem__:    按照索引获取值
  __len__:        获得长度
  __cmp__:        比较运算
  __call__:       调用
  __add__:        加运算
  __sub__:        减运算
  __mul__:        乘运算
  __div__:        除运算
  __mod__:        求余运算
  __pow__:        幂
  https://ltoddy.github.io/essay/2018/05/27/python-magic-methods.html

63. 如何判断是函数还是方法?

  print(isinstance(obj.func, FunctionType))   # False
  print(isinstance(obj.func, MethodType))    # True

  示例:
  class Foo(object):
      def __init__(self):
          self.name = 'lcg'
   
      def func(self):
          print(self.name)
   
   
  obj = Foo()
  print(obj.func)  # <bound method Foo.func of <__main__.Foo object at 0x000001ABC0F15F98>>
   
  print(Foo.func)  # <function Foo.func at 0x000001ABC1F45BF8>
   
  # ------------------------FunctionType, MethodType------------#
   
   
  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
   
  # ------------------------------------------------------------#
  obj = Foo()
  Foo.func(obj)  # lcg
   
  obj = Foo()
  obj.func()  # lcg
   
  """
  注意:
      方法,无需传入self参数
      函数,必须手动传入self参数
  """

64. 静态方法和类方法区别?

  classmethod 必须有一个指向类对象的引用作为第一个参数,而 staticmethod 可以没有任何参数

  class Num:
      # 普通方法:能用Num调用而不能用实例化对象调用   
      def one():  
          print ('1')
   
      # 实例方法:能用实例化对象调用而不能用Num调用
      def two(self):
          print ('2')
   
      # 静态方法:能用Num和实例化对象调用
      @staticmethod 
      def three():  
          print ('3')
   
      # 类方法:第一个参数cls长什么样不重要,都是指Num类本身,调用时将Num类作为对象隐式地传入方法   
      @classmethod 
      def go(cls): 
          cls.three() 
   
  Num.one()          #1
  #Num.two()         #TypeError: two() missing 1 required positional argument: 'self'
  Num.three()        #3
  Num.go()           #3
   
  i=Num()                
  #i.one()           #TypeError: one() takes 0 positional arguments but 1 was given         
  i.two()            #2      
  i.three()          #3
  i.go()             #3 

65. 列举面向对象中的特殊成员以及应用场景


  http://www.cnblogs.com/bainianminguo/p/8076329.html

66. 1、2、3、4、5 能组成多少个互不相同且无重复的三位数

  i = 0
  for x in range(1, 6):
      for y in range(1, 6):
          for z in range(1, 6):
              if (x != y) and (y != z) and (z != x):
                  i += 1
                  if i % 4:
                      print("%d%d%d" % (x, y, z), end=" | ")
                  else:
                      print("%d%d%d" % (x, y, z))
  print(i)

67. 什么是反射?以及应用场景?

  反射就是通过字符串的形式,导入模块;通过字符串的形式,去模块寻找指定函数,并执行。利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员,一种基于字符串的事件驱动!
  https://www.cnblogs.com/vipchenwei/p/6991209.html

68. metaclass作用?以及应用场景?

  metaclass用来指定类是由谁创建的。

  类的metaclass 默认是type。我们也可以指定类的metaclass值。
  http://www.cnblogs.com/0bug/p/8578747.html

69. 用尽量多的方法实现单例模式。

  http://python.jobbole.com/87294/
  http://www.cnblogs.com/0bug/p/8576802.html
  常用方式:
      使用模块
      使用 __new__
      使用装饰器(decorator)
      使用元类(metaclass)

70. 装饰器的写法以及应用场景。

  装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景。
  def outer(func):
      def inner(*args,**kwargs):
          print("认证成功!")
          result = func(*args,**kwargs)
          print("日志添加成功")
          return result
      return inner

  @outer
  def f1(name,age):
      print("%s 正在连接业务部门1数据接口......"%name)

  # 调用方法
  f1("jack",18)
  http://www.cnblogs.com/iyouyue/p/8934547.html

71. 异常处理写法以及如何主动跑出异常(应用场景)

  while True:
    try:
        x = int(input("Please enter a number: "))
        break
    except ValueError:
        print("Oops!  That was no valid number.  Try again   ")


  raise主动抛出一个异常
  http://www.runoob.com/python3/python3-errors-execptions.html

72. 什么是面向对象的mro

  mro就是方法解析顺序。
  方法解析顺序Method Resolution Order
  参考:http://www.cnblogs.com/0bug/p/8728570.html#_label8

73. isinstance作用以及应用场景?

  用于判断一个对象是否是一个类或者其子类的实例。
  class A:
      pass
   
   
  class b(A):
      pass
   
   
  class c(b):
      pass
   
   
  bb = b()
   
  print(isinstance(bb, A))  # True
  print(isinstance(bb, b))  # True
  print(isinstance(bb, c))  # False

74. 写代码并实现LeetCode两数之和:

  ## 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]


  class Solution:  
    def twoSum(self,nums, target):  
        """ 
        :type nums: List[int] 
        :type target: int 
        :rtype: List[int] 
        """  
        #用len()方法取得nums列表长度  
        n = len(nums)  
        #x从0到n取值(不包括n)  
        for x in range(n):  
            a = target - nums[x]  
            #用in关键字查询nums列表中是否有a  
            if a in nums:  
                #用index函数取得a的值在nums列表中的索引  
                y = nums.index(a)  
                #假如x=y,那么就跳过,否则返回x,y  
                if x == y:  
                    continue  
                else:  
                    return x,y  
                    break  
            else :  
                continue  
  https://blog.csdn.net/linfeng886/article/details/79772348

75. json序列化时,可以处理的数据类型有哪些?如何定制支持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(json.dumps(d,cls=ComplexEncoder))
  # {"name": "alex", "data": "2018-05-18 19:52:05"}

  https://www.cnblogs.com/tkqasn/p/6005025.html

76. json序列化时,默认遇到中文会转换成unicode,如果想要保留中文怎么办?


  在序列化时,中文汉字总是被转换为unicode码,在dumps函数中添加参数ensure_ascii=False即可解决。

77. 什么是断言?应用场景?

  python assert断言是声明其布尔值必须为真的判定,如果发生异常就说明表达示为假

  比如我想测试 a==1。就可以用断言。如果我的猜想错误就会抛出异常,可以用于测试一段表达式是否成立。

78. 有用过with statement吗?它的好处是什么?


  with语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等。

79. 使用代码实现查看列举目录下的所有文件。

  # 方法一:(不使用os.walk)
  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)
              
  # 方法二:(使用os.walk)
  def print_directory_contents(sPath):
      import os
      for root, _, filenames in os.walk(sPath):
          for filename in filenames:
              print(os.path.abspath(os.path.join(root, filename)))


  print_directory_contents('已知路径')

  sPath-- 是你所要便利的目录的地址, 返回的是一个三元组(root,dirs,files)。
      root 所指的是当前正在遍历的这个文件夹的本身的地址
      _ 是一个 list ,内容是该文件夹中所有的目录的名字(不包括子目录)
      filenames 同样是 list , 内容是该文件夹中所有的文件(不包括子目录)   

80. 简述 yield和yield from关键字。


  https://blog.csdn.net/chenbin520/article/details/78111399?locationNum=7&fps=1

===============第二部分 网络编程和并发(34题)===============

1. 简述 OSI 七层协议。

  a) 四层协议:应用层、传输层、网络层、网络接口层

  b) 五层协议:

  应用层:用户使用的应用程序都归属于应用层,作用为规定应用程序的数据格式。

  传输层:网络层帮我们找到主机,但是区分应用层的应用就是靠端口,所以传输层就是建立端口到端口的通信。(端口范围0-65535,0-1023为系统占用端口)

  网络层:区分不同的广播域或者子网(否则发送一条数据全世界都会受到,是灾难)。

  数据链路层:定义电信号的分组方式。

  物理层:基于电器特性发送高低点电压(电信号),高电压对应数字1,低电压对应数字0。

  c)七层协议:(应用层、表示层、会话层)、传输层、网络层、(数据链路层、物理层)

2. 什么是C/S和B/S架构?

  1.什么是C/S结构
  C/S (Client/Server)结构,即客户机和服务器结构。它是软件系统体系结构,通过它可以充分利用两端硬件环境的优势,将任务合理分配到Client端和Server端来实现,降低了系统的通讯开销。
  C/S结构可以看做是胖客户端架构。客户端实现绝大多数的业务逻辑处理和界面展示,作为客户端的部分需要承受很大的压力,从分利用客户端的资源,对客户机的要求较高。
  其实现可以是客户端包含一个或多个在用户的电脑上运行的程序,而服务器端有两种,一种是数据库服务器端,客户端通过数据库连接访问服务器端的数据;另一种是Socket服务器端,服务器端的程序通过Socket与客户端的程序通信。
  目前大多数应用软件系统都是Client/Server形式的两层结构,由于现在的软件应用系统正在向分布式的Web应用发展,Web和Client/Server 应用都可以进行同样的业务处理,应用不同的模块共享逻辑组件;因此,内部的和外部的用户都可以访问新的和现有的应用系统,通过现有应用系统中的逻辑可以扩展出新的应用系统。这也就是目前应用系统的发展方向。
  传统的C/S体系结构虽然采用的是开放模式,但这只是系统开发一级的开放性,在特定的应用中无论是Client端还是Server端都还需要特定的软件支持。由于没能提供用户真正期望的开放环境,C/S结构的软件需要针对不同的操作系统系统开发不同版本的软件,加之产品的更新换代十分快,已经很难适应百台电脑以上局域网用户同时使用。而且代价高, 效率低。

  2.什么是B/S结构
  B/S(Browser/Server)结构即浏览器和服务器结构。它是随着Internet技术的兴起,对C/S结构的一种变化或者改进的结构。在这种结构下,用户工作界面是通过WWW浏览器来实现,极少部分事务逻辑在前端(Browser)实现,但是主要事务逻辑在服务器端(Server)实现,形成所谓三层3-tier结构。这样就大大简化了客户端电脑载荷,减轻了系统维护与升级的成本和工作量,降低了用户的总体成本(TCO)。
  B/S结构可以看作是瘦客户端,只是把显示的较少的逻辑交给了Web浏览器,事务逻辑数据处理在放在了Server端,这样就避免了庞大的胖客户端,减少了客户端的压力。B/S结构的系统无须特别安装,只有Web浏览器即可。当然AJAX\Flex等等的普遍使用也有富客户端的发展方向。
  以目前的技术看,局域网建立B/S结构的网络应用,并通过Internet/Intranet模式下数据库应用,相对易于把握、成本也是较低的。它是一次性到位的开发,能实现不同的人员,从不同的地点,以不同的接入方式(比如LAN, WAN, Internet/Intranet等)访问和操作共同的数据库;它能有效地保护数据平台和管理访问权限,服务器数据库也很安全 。特别是在JAVA这样的跨平台语言出现之后,B/S架构管理软件更是方便、快捷、高效。
  https://blog.csdn.net/sinat_35111396/article/details/51535784

3. 简述 三次握手、四次挥手的流程。

  1 三次握手
  客户端通过向服务器端发送一个SYN来创建一个主动打开,作为三次握手的一部分。客户端把这段连接的序号设定为随机数 A。
  服务器端应当为一个合法的SYN回送一个SYN/ACK。ACK 的确认码应为 A+1,SYN/ACK 包本身又有一个随机序号 B。
  最后,客户端再发送一个ACK。当服务端受到这个ACK的时候,就完成了三路握手,并进入了连接创建状态。此时包序号被设定为收到的确认号 A+1,而响应则为 B+1。
  2 四次挥手
  注意: 中断连接端可以是客户端,也可以是服务器端. 下面仅以客户端断开连接举例, 反之亦然.

  客户端发送一个数据分段, 其中的 FIN 标记设置为1. 客户端进入 FIN-WAIT 状态. 该状态下客户端只接收数据, 不再发送数据.
  服务器接收到带有 FIN = 1 的数据分段, 发送带有 ACK = 1 的剩余数据分段, 确认收到客户端发来的 FIN 信息.
  服务器等到所有数据传输结束, 向客户端发送一个带有 FIN = 1 的数据分段, 并进入 CLOSE-WAIT 状态, 等待客户端发来带有 ACK = 1 的确认报文.
  客户端收到服务器发来带有 FIN = 1 的报文, 返回 ACK = 1 的报文确认, 为了防止服务器端未收到需要重发, 进入 TIME-WAIT 状态. 服务器接收到报文后关闭连接. 客户端等待 2MSL 后未收到回复, 则认为服务器成功关闭, 客户端关闭连接.
  图解: http://blog.csdn.net/whuslei/article/details/6667471

4. 什么是arp协议?

  ARP协议,全称“Address Resolution Protocol”,中文名是地址解析协议,使用ARP协议可实现通过IP地址获得对应主机的物理地址(MAC地址)。
  https://www.cnblogs.com/luchuangao/articles/6053742.html

5. TCP和UDP的区别?

  TCP 
  收发两端(客户端和服务器端)都要有成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小、数据量小的数据,合并成一个大的数据块,然后进行封包。这样接收端就难于分辨,必须提供拆包机制。
  如果利用TCP每次发送数据,就与对方建立连接,然后双方发送完一段数据后,就关闭连接,这样就不会出现粘包问题(因为只有一种包结构,类似于http协议)。关闭连接主要要双方都发送close连接。
  如果发送数据无结构,如文件传输,这样发送方只管发送,接收方只管接收存储即可,也不用考虑粘包
  如果双方建立连接,需要在连接后一段时间内发送不同结构数据,就需要考虑粘包问题。所以一般可能会在头加一个数据长度之类的包,以确保接收。
  UDP
  对于UDP,不会使用块的合并优化算法。实际上目前认为,是由于UDP支持的是一对多的模式(注意区分不是并发模式),所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中有消息头(消息来源地址,端口等信息),这样对于接收端来说,就容易进行区分处理了,所以UDP不会出现粘包问题。

6. 什么是局域网和广域网?

  一、局域网 
  局域网(Local Area Network),简称LAN,是指在某一区域内由多台计算机互联成的计算机组。“某一区域”指的是同一办公室、同一建筑物、同一公司和同一学校等,一般是方圆几千米以内。局域网可以实现文件管理、应用软件共享、打印机共享、扫描仪共享、工作组内的日程安排、电子邮件和传真通信服务等功能。局域网是封闭型的,可以由办公室内的两台计算机组成,也可以由一个公司内的上千台计算机组成。 
  二、广域网 
  广域网(Wide Area Network),简称WAN,是一种跨越大的、地域性的计算机网络的集合。通常跨越省、市,甚至一个国家。广域网包括大大小小不同的子网,子网可以是局域网,也可以是小型的广域网。 
  三、局域网和广域网的区别 
  局域网是在某一区域内的,而广域网要跨越较大的地域,那么如何来界定这个区域呢?例如,一家大型公司的总公司位于北京,而分公司遍布全国各地,如果该公司将所有的分公司都通过网络联接在一起,那么一个分公司就是一个局域网,而整个总公司网络就是一个广域网。

7. 为何基于tcp协议的通信比基于udp协议的通信更可靠?

  tcp:可靠 对方给了确认收到信息,才发下一个,如果没收到确认信息就重发
  udp:不可靠 一直发数据,不需要对方回应

8. 什么是socket?简述基于tcp协议的套接字通信流程。

  Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部。

  服务端:创建socket对象,绑定ip端口bind(),  设置最大链接数listen(),  accept()与客户端的connect()创建双向管道, send(), recv(),close()

  客户端:创建socket对象,connect()与服务端accept()创建双向管道 ,  send(), recv(),close()

9. 什么是粘包? socket 中造成粘包的原因是什么?

  粘包:数据粘在一起,主要因为:接收方不知道消息之间的界限,不知道一次性提取多少字节的数据造成的
  数据量比较小,时间间隔比较短,就合并成了一个包,这是底层的一个优化算法(Nagle算法)

10. IO多路复用的作用?

  I/O multiplexing就是所谓的select,poll,epoll,也称这种I/O方式为事件驱动I/O(event driven I/O)。
    select/epoll的好处就在于单个进程就可以同时处理多个网络连接的I/O。  它的基本原理就是select/poll/epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。
  I/O 多路复用的特点是通过一种机制使一个进程能同时等待多个文件描述符,而这些文件描述符(套接字描述符)其中的任意一个进入读就绪状态,select()函数就可以返回。

  多道技术的实现就是为了解决多个程序竞争或者共享同一个资源(比如cpu)的有序调度问题,解决方式即是多路复用。多路复用分为时间上的复用和空间上的复用,空间上的多路复用是指将内存分为几部分,每一部分放一个程序,这样同一时间内存中就有多道程序,前提保证内存是分割;时间上的多路复用是指多个程序需要在一个cpu上运行,不同的程序轮流使用cpu,当某个程序运行的时间过长或者遇到I/O阻塞,操作系统会把cpu分配给下一个程序,保证cpu处于高使用率,实现伪并发。

11. 什么是防火墙以及作用?


  http://www.cnblogs.com/loneywang/archive/2007/09/30/912029.html

12. select、poll、epoll 模型的区别?


  https://www.cnblogs.com/Anker/p/3265058.html

13. 简述 进程、线程、协程的区别 以及应用场景?

  什么是进程
  进程(有时称为重量级进程)是一个执行中的程序。每个进程都拥有自己的地址空间、内存、数据栈以及其他用于跟踪执行的辅助数据。同一个程序执行两次,属于是两个不同进程。
  什么是线程
    线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。
    就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机; 运行状态是指线程占有处理机正在运行;
    阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。
  什么是协程
    协程是“微线程”,并非实际存在;是由程序员人为创造出来并控制程序:先执行某段代码、再跳到某处执行某段代码。
  如果遇到非IO请求来回切换:性能更低。
  如果遇到IO(耗时)请求来回切换:性能高、实现并发(本质上利用IO等待的过程,再去干一些其他的事)

  进程池与线程池
  基于多进程或多线程实现并发的套接字通信,然而这种方式的缺陷是:服务的开启的进程数或线程数都会随着并发的客户端数目地增多而增多,这对服务端主机带来巨大的压力,于是必须对服务端开启的进程数或线程数加以控制,让机器在一个自己可以承受的范围内运行,这就是进程池或线程池的用途,例如进程池,就是用来存放进程的池子,本质还是基于多进程,只不过是对开启进程的数目加上了限制。

  1、进程和线程的区别?

  答:进程拥有一个完整的虚拟地址空间,不依赖于线程而独立存在;反之,线程是进程的一部分,没有自己的地址空间,与进程内的其他线程一起共享分配给该进程的所有资源。

  比如:开个QQ,开了一个进程;开了迅雷,开了一个进程。在QQ的这个进程里,传输文字开一个线程、传输语音开了一个线程、弹出对话框又开了一个线程。所以运行某个软件,相当于开了一个进程。在这个软件运行的过程里(在这个进程里),多个工作支撑的完成QQ的运行,那么这“多个工作”分别有一个线程。所以一个进程管着多个线程。通俗的讲:“进程是爹妈,管着众多的线程儿子”。

  参考自:https://www.zhihu.com/question/25532384

  2、为什么说python的线程是伪线程?

  答:在python的原始解释器CPython中存在着GIL(Global Interpreter Lock,全局解释器锁),因此在解释执行python代码时,会产生互斥锁来限制线程对共享资源的访问,直到解释器遇到I/O操作或者操作次数达到一定数目时才会释放GIL。

  所以,虽然CPython的线程库直接封装了系统的原生线程,但CPython整体作为一个进程,同一时间只会有一个线程在跑,其他线程则处于等待状态。这就造成了即使在多核CPU中,多线程也只是做着分时切换而已。

  参考自:https://www.zhihu.com/question/23474039

  3、python的append和extend有什么区别?

  答:extend()接受一个列表参数,把参数列表的元素添加到列表的尾部,append()接受一个对象参数,把对象添加到列表的尾部。

14. GIL锁是什么鬼?

  线程全局锁(Global Interpreter Lock),即Python为了保证线程安全而采取的独立线程运行的限制,说白了就是一个核只能在同一时间运行一个线程.对于io密集型任务,python的多线程起到作用,但对于cpu密集型任务,python的多线程几乎占不到任何优势,还有可能因为争夺资源而变慢。

  解决办法就是多进程和下面的协程(协程也只是单CPU,但是能减小切换代价提升性能).

15. Python中如何使用线程池和进程池?

  进程池:就是在一个进程内控制一定个数的线程
  基于concurent.future模块的进程池和线程池 (他们的同步执行和异步执行是一样的)
  http://www.cnblogs.com/haiyan123/p/7461294.html

16. 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()

17. 进程之间如何进行通信?

  进程间通信主要包括管道, 系统IPC(包括消息队列,信号,共享存储), 套接字(SOCKET).
  管道包括三种:
    1)普通管道PIPE, 通常有两种限制,一是单工,只能单向传输;二是只能在父子或者兄弟进程间使用.
    2)流管道s_pipe: 去除了第一种限制,为半双工,可以双向传输.
    3)命名管道:name_pipe, 去除了第二种限制,可以在许多并不相关的进程之间进行通讯.

18. 什么是并发和并行?

  如果某个系统支持两个或者多个动作(Action)同时存在,那么这个系统就是一个并发系统。如果某个系统支持两个或者多个动作同时执行,那么这个系统就是一个并行系统。并发系统与并行系统这两个定义之间的关键差异在于“存在”这个词。
  在并发程序中可以同时拥有两个或者多个线程。这意味着,如果程序在单核处理器上运行,那么这两个线程将交替地换入或者换出内存。这些线程是同时“存在”的——每个线程都处于执行过程中的某个状态。如果程序能够并行执行,那么就一定是运行在多核处理器上。此时,程序中的每个线程都将分配到一个独立的处理器核上,因此可以同时运行。
  我相信你已经能够得出结论——“并行”概念是“并发”概念的一个子集。也就是说,你可以编写一个拥有多个线程或者进程的并发程序,但如果没有多核处理器来执行这个程序,那么就不能以并行方式来运行代码。因此,凡是在求解单个问题时涉及多个执行流程的编程模式或者执行行为,都属于并发编程的范畴。

  摘自:《并发的艺术》 — 〔美〕布雷谢斯

19. 进程锁和线程锁的作用?

  线程锁:大家都不陌生,主要用来给方法、代码块加锁。当某个方法或者代码块使用锁时,那么在同一时刻至多仅有有一个线程在执行该段代码。当有多个线程访问同一对象的加锁方法/代码块时,同一时间只有一个线程在执行,其余线程必须要等待当前线程执行完之后才能执行该代码段。但是,其余线程是可以访问该对象中的非加锁代码块的。

  进程锁:也是为了控制同一操作系统中多个进程访问一个共享资源,只是因为程序的独立性,各个进程是无法控制其他进程对资源的访问的,但是可以使用本地系统的信号量控制(操作系统基本知识)。

  分布式锁:当多个进程不在同一个系统之中时,使用分布式锁控制多个进程对资源的访问。

  http://www.cnblogs.com/intsmaze/p/6384105.html

20. 解释什么是异步非阻塞?

  同步异步指的是在客户端
  同步意味着客户端提出了一个请求以后,在回应之前只能等待
  异步意味着 客户端提出一个请求以后,还可以继续提其他请求阻塞

  非阻塞 指的是服务器端
  阻塞意味着服务器接受一个请求后,在返回结果以前不能接受其他请求
  非阻塞意味着服务器接受一个请求后,尽管没有返回结果,还是可以继续接受其他请求

21. 路由器和交换机的区别?

  交换机工作于数据链路层,用来隔离冲突域,连接的所有设备同属于一个广播域(子网),负责子网内部通信。

  路由器工作于网络层,用来隔离广播域(子网),连接的设备分属不同子网,工作范围是多个子网之间,负责网络与网络之间通信。
  https://www.zhihu.com/question/20465477

22. 什么是域名解析?


  域名解析是把域名指向网站空间IP,让人们通过注册的域名可以方便地访问到网站的一种服务。IP地址是网络上标识站点的数字地址,为了方便记忆,采用域名来代替IP地址标识站点地址。域名解析就是域名到IP地址的转换过程。域名的解析工作由DNS服务器完成。

23. 如何修改本地hosts文件?

  1)hosts文件的位置:C:\windows\system32\drivers\etc,文件夹中找到Hosts文件并用记事本打开。

  2)按照 ip地址  域名 的格式添加单独的一行记录。例如
  112.124.39.29 www.server110.com
  注意,IP地址前面不要有空格,ip地址和域名之间,要有至少1个空格。
  修改后,一定要记得保存文件。

  3)如何知道域名的IP地址已经生效?
  在您的电脑上请按如下步骤操作:开始-->运行-->输入cmd-->ping 域名-->回车查看结果
  显示结果类似 Reply from 220.181.31.183: bytes=32 time=79ms TTL=53
  中间的  220.181.31.183 就是域名的IP地址

  * 注意:有些浏览器会保存DNS缓存,比如Chrome。多按几次F5刷新即可。
  https://www.cnblogs.com/cl-blogs/p/4160483.html

24. 生产者消费者模型应用场景及优势?

  生产者消费者模型

  在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。

    为什么要使用生产者和消费者模式

  在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。

    什么是生产者消费者模式

  生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

  http://www.cnblogs.com/huchong/p/7454756.html

25. 什么是CDN?

  CDN主要功能是在不同的地点缓存内容,通过负载均衡技术,将用户的请求定向到最合适的缓存服务器上去获取内容,比如说,是北京的用户,我们让他访问北京的节点,深圳的用户,我们让他访问深圳的节点。通过就近访问,加速用户对网站的访问。解决Internet网络拥堵状况,提高用户访问网络的响应速度。
  CDN的全称是Content Delivery Network,即内容分发网络。其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。其目的是使用户可就近取得所需内容,解决 Internet网络拥挤的状况,提高用户访问网站的响应速度。

26. LVS是什么及作用?

  LVS 是 Linux  Virtual Server ,Linux 虚拟服务器;是一个虚拟的服务器集群【多台机器 LB IP】。LVS 集群分为三层结构:

  1) 负载调度器(load balancer):它是整个LVS 集群对外的前端机器,负责将client请求发送到一组服务器[多台LB IP]上执行,而client端认为是返回来一个同一个IP【通常把这个IP 称为虚拟IP/VIP】
  2) 服务器池(server pool):一组真正执行client 请求的服务器,一般是我们的web服务器;除了web,还有FTP,MAIL,DNS
  3) 共享存储(shared stored):它为 server pool 提供了一个共享的存储区,很容易让服务器池拥有相同的内容,提供相同的服务[不是很理解]

  https://blog.csdn.net/caoshuming_500/article/details/8291940

27. Nginx是什么及作用?

  Nginx是一个轻量级、高性能、稳定性高、并发性好的HTTP和反向代理服务器。
  https://blog.csdn.net/b9x__/article/details/80400697
  https://www.cnblogs.com/xiohao/p/6433401.html

28. keepalived是什么及作用?


  https://baike.baidu.com/item/Keepalived/10346758?fr=aladdin

29. haproxy是什么以及作用?


  https://baike.baidu.com/item/haproxy/5825820

30. 什么是负载均衡?

  负载均衡 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。
  负载均衡,英文名称为Load Balance,其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。
  https://baike.baidu.com/item/%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1

31.什么是RPC及应用场景?

  RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
  RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。

32.简述 asynio模块的作用和应用场景。


  https://www.cnblogs.com/zhaof/p/8490045.html

33.简述 gevent模块的作用和应用场景。


  https://www.cnblogs.com/zcqdream/p/6196040.html

34.twisted框架的使用和应用?


  http://www.cnblogs.com/zhiyong-ITNote/p/7360442.html

===============第三部分 数据库和缓存(46题)===============

1. 列举常见的关系型数据库和非关系型都有哪些?

  MySQL/SqlServer  MongoDB/Redis
  https://db-engines.com/en/ranking

2. MySQL常见数据库引擎及比较?

  MyISAM 适合于一些需要大量查询的应用,但其对于有大量写操作并不是很好。甚至你只是需要update一个字段,整个表都会被锁起来,而别的进程,就算是读进程都无法操作直到读操作完成。另外,MyISAM 对于 SELECT COUNT(*) 这类的计算是超快无比的。

  InnoDB 的趋势会是一个非常复杂的存储引擎,对于一些小的应用,它会比 MyISAM 还慢。他是它支持“行锁” ,于是在写操作比较多的时候,会更优秀。并且,他还支持更多的高级应用,比如:事务。

  mysql 数据库引擎: http://www.cnblogs.com/0201zcr/p/5296843.html
  MySQL存储引擎--MyISAM与InnoDB区别: https://segmentfault.com/a/1190000008227211

3. 简述数据三大范式?

  第一范式:确保每列的原子性.
      如果每列(或者每个属性)都是不可再分的最小数据单元(也称为最小的原子单元),则满足第一范式.
      例如:顾客表(姓名、编号、地址、……)其中"地址"列还可以细分为国家、省、市、区等。
  第二范式:在第一范式的基础上更进一层,目标是确保表中的每列都和主键相关.
      如果一个关系满足第一范式,并且除了主键以外的其它列,都依赖于该主键,则满足第二范式.
      例如:订单表(订单编号、产品编号、定购日期、价格、……),"订单编号"为主键,"产品编号"和主键列没有直接的关系,即"产品编号"列不依赖于主键列,应删除该列。
  第三范式:在第二范式的基础上更进一层,目标是确保每列都和主键列直接相关,而不是间接相关.
      如果一个关系满足第二范式,并且除了主键以外的其它列都不依赖于主键列,则满足第三范式.
      为了理解第三范式,需要根据Armstrong公里之一定义传递依赖。假设A、B和C是关系R的三个属性,如果A-〉B且B-〉C,则从这些函数依赖中,可以得出A-〉C,如上所述,依赖A-〉C是传递依赖。
      例如:订单表(订单编号,定购日期,顾客编号,顾客姓名,……),初看该表没有问题,满足第二范式,每列都和主键列"订单编号"相关,再细看你会发现"顾客姓名"和"顾客编号"相关,"顾客编号"和"订单编号"又相关,最后经过传递依赖,"顾客姓名"也和"订单编号"相关。为了满足第三范式,应去掉"顾客姓名"列,放入客户表中。  

4. 什么是事务?MySQL如何支持事务?

  数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。
  彻底理解数据库事务: http://www.hollischuang.com/archives/898

5. 简述数据库设计中一对多和多对多的应用场景?

  一对一关系示例:
    一个学生对应一个学生档案材料,或者每个人都有唯一的身份证编号。
  一对多关系示例:(下拉单选)
    一个学生只属于一个班,但是一个班级有多名学生。
  多对多关系示例:(下拉多选)
    一个学生可以选择多门课,一门课也有多名学生。

6. 如何基于数据库实现商城商品计数器?


  http://www.cnblogs.com/phpcoder/p/4665850.html

7. 常见SQL(必备)


  ## 详见武沛齐博客:https://www.cnblogs.com/wupeiqi/articles/5729934.html

8. 简述触发器、函数、视图、存储过程?

  1)存储过程?
    一组为了完成特定功能的SQL 语句集,经编译后存储在数据库。用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程在创建时即在服务器上进行编译,所以执行起来比单个SQL语句快,因为调用存储过程比直接向服务端发送大量SQL语句在执行速度快。
  对于存储过程,可以接收参数,其参数有三类:
   in          仅用于传入参数用
   out        仅用于返回值用
   inout     既可以传入又可以当作返回值
  2)函数?
    封装一段sql代码,完成一种特定的功能,必须返回结果。其余特性基本跟存储过程相同
  3)函数与存储过程的区别?
    3.1) 函数有且只有一个返回值,而存储过程不能有返回值。
    3.2) 存储过程可以实现很复杂的业务逻辑,函数有很多限制。不能在函数中使用insert,update,delete,create等语句
    3.3)存储过程可以调用函数。但函数不能调用存储过程。
    3.4)存储过程一般是作为一个独立的部分来调用。而函数可以作为查询语句的一个部分来调用。
  4)视图?
    视图是基于 SQL 语句的结果集的可视化虚拟表。
    视图中的字段来自一个或多个数据库中的真实表的字段。视图并不在数据库中以存储数据值集形式存在,而存在于实际引用的数据库表中,视图的构成可以是单表查询,多表联合查询,分组查询以及计算(表达式)查询等。行和列数据在引用视图时动态生成
  5)触发器?
    触发器(TRIGGER)与函数类似,需要声明、执行。但是触发器的执行不是由程序调用,而是由事件来触发从而实现执行。对某个表进行【增/删/改】操作的前后如果希望触发某个特定的行为时,可以使用触发器,触发器用于定制用户对表的行进行【增/删/改】前后的行为

9. MySQL索引种类

  MySQL目前主要有以下几种索引类型:
  1.普通索引
  2.唯一索引
  3.主键索引
  4.组合索引
  5.全文索引
  https://www.cnblogs.com/luyucheng/p/6289714.html

10. 索引在什么情况下遵循最左前缀的规则?


  https://www.cnblogs.com/jamesbd/p/4333901.html

11. 主键和外键的区别?

  1.主键是能确定一条记录的唯一标识,比如,一条记录包括身份正号,姓名,年龄。身份证号是唯一能确定你这个人的,其他都可能有重复,所以,身份证号是主键。 
  2.外键用于与另一张表的关联。是能确定另一张表记录的字段,用于保持数据的一致性。一个表可以有多个外键。

12. MySQL常见的函数?


  https://blog.csdn.net/sugang_ximi/article/details/6664748

13. 列举 创建索引但是无法命中索引的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 = 'seven@live.com';
      特别的:当or条件中有未建立索引的列才失效,以下会走索引
              select * from tb1 where nid = 1 or name = 'seven';
              select * from tb1 where nid = 1 or email = 'seven@live.com' 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;

  https://www.cnblogs.com/iyouyue/p/9004018.html#_label34

14. 如何开启慢日志查询?


  https://www.jianshu.com/p/9f9c9326f8f4

15. 数据库导入导出命令(结构+数据)?

  - 导出现有数据库数据:
          mysqldump -u用户名 -p密码 数据库名称 >导出文件路径         # 结构+数据
          mysqldump -u用户名 -p密码 -d 数据库名称 >导出文件路径     # 结构 
  - 导入现有数据库数据:
          mysqldump -uroot -p密码 数据库名称 < 文件路径

16. 数据库优化方案?

  1. 避免全表扫描,首先应考虑在 where 及 orderby 涉及的列上建立索引。
  2. 避免在 where 子句中对字段进行 null 值判断,导致引擎放弃使用索引而进行全表扫描 
  3. 避免在 where 子句中使用 != 或>操作符,引擎将放弃使用索引而进行全表扫描。
  4. 避免在 where 子句中使用or 来连接条件
  5. 慎用in 和 not, 可以用 exists 代替 in
  6. 慎用 like 'XXX%',要提高效率,可以全文检索。
  7. 应尽量避免在 where 子句中对字段进行表达式操作,如:
  select id from t where num/2=100
  应改为select id from t where num=100*2
  8. 避免在where子句中对字段进行函数操作
  select id from t where substring(name,1,3)='abc' 
  改为:
  select id from t where name like 'abc%'
  9. 在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。(索引的最左前缀原则) 
  10. 并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。
  11. 索引不是越多越好,索引可以提高select 的效率,同时也降低 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引。
  12. 任何地方都不要使用 select * from t ,用具体的字段列表代替“*”
  13. 避免频繁创建和删除临时表,以减少系统表资源的消耗。
  14. 在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。
  15. 尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。
  数据库中的数据在未进行分库分表的情况下,随着时间和业务的发展,库中的表会越来越多,表中的数据量也会越来越大,相应地,数据操作,增删改查的开销也会越来越大
  16. 读写分离。通过数据库配置设置, mysql复制时,产生了多个数据副本(备库),为减少服务器压力,备库用于处理读操作,主库可同时处理读写。备库的复制是异步的,无法实时同步,读写分离的主要难点也在于备库上的脏数据。通常如果使用备库进行读,一般对数据的实时性要求不能太高。
  17. 分库、分表。
  分库:当数据库中的表太多,可以考虑将表分到不同的数据库
  分表
    水平分表:将一些列分到另一张表
    垂直分表:将历史信息分到另一张表中,很久之前的记录少有查询
  18. 利用缓存存储经常被查询的数据。利用redis、memcache

17. 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字节

18. 简述MySQL的执行计划?

  EXPLAIN命令是查看优化器如何决定执行查询的主要方法。可以帮助我们深入了解MySQL的基于开销的优化器,还可以获得很多可能被优化器考虑到的访问策略的细节,以及当运行SQL语句时哪种策略预计会被优化器采用。
  http://www.cnblogs.com/clsn/p/8087501.html#auto_id_20

19. 在对name做了唯一索引前提下,简述limit 1 作用

  select * from tb where name = ‘Oldboy-Wupeiqi’ 
  select * from tb where name = ‘Oldboy-Wupeiqi’ 
  是这样的的,用where条件过滤出符合条件的数据的同时,进行计数,比如limit 1,那么在where过滤出第1条数据后,他就会直接把结果select出来返回给你,整个过程就结束了。

20. 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 )

21. 什么是索引合并?

  1、索引合并是把几个索引的范围扫描合并成一个索引。
  2、索引合并的时候,会对索引进行并集,交集或者先交集再并集操作,以便合并成一个索引。
  3、这些需要合并的索引只能是一个表的。不能对多表进行索引合并。

  简单的说,索引合并,让一条sql可以使用多个索引。对这些索引取交集,并集,或者先取交集再取并集。从而减少从数据表中取数据的次数,提高查询效率。

22. 什么是覆盖索引?


  http://www.cnblogs.com/chenpingzhao/p/4776981.html

23. 简述数据库读写分离?

 读写分离,基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。
 https://blog.csdn.net/xybelieve1990/article/details/50830908

24. 简述数据库分库分表?(水平、垂直)

23问题链接
  https://blog.csdn.net/xlgen157387/article/details/53976153

25. 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。

26. redis中数据库默认是多少个db 及作用?

  Redis默认支持16个数据库(可以通过配置文件支持更多,无上限),可以通过配置databases来修改这一数字。客户端与Redis建立连接后会自动选择0号数据库,不过可以随时使用SELECT命令更换数据库
  Redis支持多个数据库,并且每个数据库的数据是隔离的不能共享,并且基于单机才有,如果是集群就没有数据库的概念。

27. python操作redis的模块?


  https://www.cnblogs.com/Eva-J/p/5152841.html

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)

29. redis如何实现主从复制?以及数据同步机制?


  https://blog.csdn.net/zhangguanghui002/article/details/78524533

30. redis中的sentinel的作用?

    帮助我们自动在主从之间进行切换
    检测主从中 主是否挂掉,且超过一半的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中默认有多少个哈希槽?


  16384

33. 简述redis的有哪几种持久化策略及比较?

    RDB:每隔一段时间对redis进行一次持久化。
         - 缺点:数据不完整
         - 优点:速度快
    AOF:把所有命令保存起来,如果想到重新生成到redis,那么就要把命令重新执行一次。
         - 缺点:速度慢,文件比较大
         - 优点:数据完整

34. 列举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(驱逐):禁止驱逐数据

35. MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 redis 中都是热点数据?

  相关知识: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 scrapy.utils.reqser import request_to_dict, request_from_dict

  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去做消息队列,这不是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及作用?


  是 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的实现机制。

  在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段。 有很多三方库和文章描述如何用Redis实现一个分布式锁管理器,但是这些库实现的方式差别很大,而且很多简单的实现其实只需采用稍微增加一点复杂的设计就可以获得更好的可靠性。 这篇文章的目的就是尝试提出一种官方权威的用Redis实现分布式锁管理器的算法,我们把这个算法称为RedLock。
  https://www.cnblogs.com/ironPhoenix/p/6048467.html
  https://blog.csdn.net/junli_chen/article/details/79228282

45. 什么是一致性哈希?Python中是否有相应模块?


  Python模块--hash_ring,即Python中的一致性hash

46. 如何高效的找到redis中所有以aaa开头的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题)===============

1. 谈谈你对http协议的认识。

  流程:
      1.域名解析
      域名解析检查顺序为:浏览器自身DNS缓存---》OS自身的DNS缓存--》读取host文件--》本地域名服务器--》权限域名服务器--》根域名服务器。如果有且没有过期,则结束本次域名解析。域名解析成功之后,进行后续操作
      2.tcp3次握手建立连接
      3.建立连接后,发起http请求
      4.服务器端响应http请求,浏览器得到到http请求的内容
      5.浏览器解析html代码,并请求html代码中的资源
      6.浏览器对页面进行渲染,展现在用户面前

2. 谈谈你对websocket协议的认识。

  WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。依靠这种技术可以实现客户端和服务器端的长连接,双向实时通信。
  特点:
  事件驱动
  异步
  使用ws或者wss协议的客户端socket

  能够实现真正意义上的推送功能

  缺点:
  少部分浏览器不支持,浏览器支持的程度与方式有区别。
  http://www.cnblogs.com/best/p/5695570.html#_label1

3. 什么是magic string ?

  魔法
  字符串

4. 如何创建响应式布局?

  @media (min-width: 768px){
      .pg-header{
          background-color: green;
      }
  }
  @media (min-width: 992px){
      .pg-header{
          background-color: pink;
      }
  }

5. 你曾经使用过哪些前端框架?

  跳
  过

6. 什么是ajax请求?并使用jQuery和XMLHttpRequest对象实现一个ajax请求。

  <script>
        function JqSendRequest(){
            $.ajax({
                url: "http://c2.com:8000/test/",
                type: 'GET',
                dataType: 'text',
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data);
                }
            })
        }
    </script>
    http://www.cnblogs.com/wupeiqi/articles/5703697.html

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中的路由的拦截器的作用?


  vue-resource的interceptors拦截器的作用正是解决此需求的妙方。在每次http的请求响应之后,如果设置了拦截器如下,会优先执行拦截器函数,获取响应体,然后才会决定是否把response返回给then进行接收

11. axios的作用?


  https://blog.csdn.net/qq_27626333/article/details/76254888

12. 列举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事件。

13. 简述JSONP及实现原理?

  JSONP是json用来跨域的一个东西。原理是通过script标签的跨域特性来绕过同源策略。(创建一个回调函数,然后在远程服务上调用这个函数并且将json数据形式作为参数传递,完成回调)。
  http://www.cnblogs.com/huchong/p/8469053.html

14. 是什么CORS ?

  跨域资源共享(CORS,Cross-Origin Resource Sharing),其本质是设置响应头,使得浏览器允许跨域请求。
  http://www.cnblogs.com/huchong/p/8469063.html

15. 列举Http请求中常见的请求方式?

  请求方法有8种,分别为:
    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请求中常见的请求头?

  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的信息去服务器上验证并通过后会判定你是合法用户,从而允许查看相应网页。

18. 看图写结果:JS,略

19. 看图写结果:JS,略

20. 看图写结果:JS,略

21. 看图写结果:JS,略

22. 看图写结果:JS,略

23. 看图写结果:JS,略

24. django、flask、tornado框架的比较?

  d:大而全
  f:微型灵活
  t:异步非阻塞

25. 什么是wsgi?

  Python Web服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)是Python应用程序或框架和Web服务器之间的一种接口,已经被广泛接受, 它已基本达成它的可移植性方面的目标。
  http://python.jobbole.com/88653/

26. django请求的生命周期?

  a. wsgi, 创建socket服务端,用于接收用户请求并对请求进行初次封装。
  b. 中间件,对所有请求到来之前,响应之前定制一些操作。
  c. 路由匹配,在url和视图函数对应关系中,根据当前请求url找到相应的函数。
  d. 执行视图函数,业务处理【通过ORM去数据库中获取数据,再去拿到模板,然后将数据和模板进行渲染】
  e. 再经过所有中间件。
  f. 通过wsgi将响应返回给用户。 

27. 列举django的内置组件?


  form/modelform/admin

28. 列举django中间件的5个方法?以及django中间件的应用场景?

  中间件中方法?5个方法,分别是:
      process_request(self,request)
      process_view(self, request, callback, callback_args, callback_kwargs)
      process_template_response(self,request,response)
      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自己做判断进行区分。

  http://www.cnblogs.com/renpingsheng/p/7534897.html

30. django的request对象是在什么时候创建的?

  当请求一个页面时, Django会建立一个包含请求元数据的 HttpRequest 对象. 当Django 加载对应的视图时, HttpRequest对象将作为视图函数的第一个参数. 每个视图会返回一个HttpResponse对象.
  https://blog.csdn.net/mbl114/article/details/78090773

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对象的所有方法)

 返回QuerySet对象的方法有:
      all()
      filter()
      exclude()
      order_by()
      reverse()
      distinct()
  特殊的QuerySet:
      values()       返回一个可迭代的字典序列
      values_list() 返回一个可迭代的元组序列
  返回具体对象的:
      get()
      first()
      last()
  返回布尔值的方法有:
      exists()
  返回数字的方法有:
      count()

33. 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')

34. select_related和prefetch_related的区别?

 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的区别?

  def filter(self, *args, **kwargs)
      # 条件查询(符合条件)
      # 条件可以是:参数,字典,Q

  def exclude(self, *args, **kwargs)
      # 条件查询(排除条件)
      # 条件可以是:参数,字典,Q

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)
  https://www.cnblogs.com/413xiaol/p/6504856.html

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:
  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()       返回一个可迭代的字典序列
    values_list() 返回一个可迭代的元组序列

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%}标签
  https://blog.csdn.net/u012556900/article/details/57412707

45. django如何实现websocket?


  https://www.cnblogs.com/huguodong/p/6611602.html

46. 基于django使用ajax发送post请求时,都可以使用哪种方法携带csrf token?

  三种方式:
    https://www.cnblogs.com/wxp5257/p/7834090.html

47. 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

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" %}
      <h3>缓存时间:{{ t }}</h3>
      {% 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",
  },
  }

50. django路由系统中name的作用?

    简单说,name 可以用于在 templates, models, views ……中得到对应的网址,相当于“给网址取了个名字”,只要这个名字不变,网址变了也能通过名字获取到。
    https://blog.csdn.net/liweiblog/article/details/77599604

51. django的模板中filter和simple_tag的区别?

  simple_tag 
    -参数任意,但是不能作为if条件判断的条件
  filter 
    -参数最多只能有两个,但是可以作为if条件判断的条件。
  http://www.cnblogs.com/cerofang/p/8367588.html

52. django-debug-toolbar的作用?

  django_debug_toolbar 是django的第三方工具包,给django扩展了调试功能。 
  包括查看执行的sql语句,db查询次数,request,headers,调试概览等。 
  https://blog.csdn.net/weixin_39198406/article/details/78821677

53. django中如何实现单元测试?


  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

 MTV和MVC?
        
  MVC: model view controller          
  MTV: model tempalte view    

58. django的contenttype组件的作用?

  contenttype是django的一个组件(app),为我们找到django程序中所有app中的所有表并添加到记录中。
        
        可以使用他再加上表中的两个字段实现:一张表和N张表创建FK关系。
            - 字段:表名称
            - 字段:数据行ID
            
        应用:路飞表结构优惠券和专题课和学位课关联。
        http://www.cnblogs.com/iyouyue/p/8810464.html

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.oldboy.com
        - www.oldboy.com/api
    - 版本:
        - www.oldboy.com/api/v1

    - URL资源,名词
        - www.oldboy.com/api/v1/student

    - 请求方式:
        - GET/POST/PUT/DELETE/PATCH/OPTIONS/HEADERS/TRACE
    - 返回值:
        - www.oldboy.com/api/v1/student/    -> 结果集
        - www.oldboy.com/api/v1/student/1/  -> 单个对象
    - URL添加条件
        - www.oldboy.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依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。
  https://www.cnblogs.com/wqhwe/p/5407468.html

63. 为什么要使用django rest framework框架?

    1.客户端-服务端分离

     优点:提高用户界面的便携性,通过简化服务器提高可伸缩性....

    2.无状态(Stateless):从客户端的每个请求要包含服务器所需要的所有信息

      优点:提高可见性(可以单独考虑每个请求),提高了可靠性(更容易从局部故障中修复),提高可扩展性(降低了服务器资源使用)

    3.缓存(Cachable):服务器返回信息必须被标记是否可以缓存,如果缓存,客户端可能会重用之前的信息发送请求

     优点:减少交互次数,减少交互的平均延迟

    4.统一接口

     优点:提高交互的可见性,鼓励单独改善组件

    5.支持按需代码(Code-On-Demand 可选)

    优点:提高可扩展性
  https://www.cnblogs.com/vipchenwei/p/7867028.html

64. 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 
                - 请求头 
    - 认证 
        - 问题:认证流程?

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

    - 访问频率的控制
        - 匿名用户可以真正的防止?无法做到真正的访问频率控制,只能把小白拒之门外。
          如果要封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
  http://www.cnblogs.com/iyouyue/p/8798572.html#_label3

66. 简述 django rest framework框架的认证流程。

  - 如何编写?写类并实现authticate
  - 方法中可以定义三种返回值:
      - (user,auth),认证成功
      - None , 匿名用户
      - 异常 ,认证失败
  - 流程:
      - dispatch 
      - 再去request中进行认证处理
  https://www.cnblogs.com/haiyan123/p/8419872.html

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',
    },
  }
  https://www.cnblogs.com/vipchenwei/p/7867028.html

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 会先创建当前线程或者进程需要处理的两个重要上下文对象,把它们保存到隔离的栈里面,这样视图函数进行处理的时候就能直接从栈上获取这些信息。
  参考链接:http://python.jobbole.com/87398/

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请求过程中 定制一些用户行为执行。

  在请求前后,模板渲染前后,上下文前后,异常 的时候
  http://www.cnblogs.com/big-handsome-guy/p/8551973.html

82. SQLAlchemy中的 session和scoped_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

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 ;')

  https://www.cnblogs.com/franknihao/p/7268752.html

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 创建指定数量的连接在连接池,当线程访问的时候去取,如果不够了线程排队,直到有人释放。平时建议使用这种!
  https://www.cnblogs.com/ArmoredTitan/p/Flask.html

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. SQLAlchemy中如何为表设置引擎和字符编码?


  sqlalchemy设置编码字符集一定要在数据库访问的URL上增加charset=utf8,否则数据库的连接就不是utf8的编码格式
  eng = create_engine('mysql://root:root@localhost:3306/test2?charset=utf8',echo=True)

88. SQLAlchemy中如何设置联合唯一索引?

    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中静态文件是如何处理的?

  如: <link href="{{static_url("commons.css")}}" rel="stylesheet" />
  处理方法:
  static_path = os.path.join(os.paht.dirname(__file__), "static") #这里增加设置了静态路径
  另外一个修改就是在实例化 tornado.web.Application() 的时候,在参数中,出了有静态路径参数 static_path ,还有一个参数设置 debug=True

  https://blog.csdn.net/hqzxsc2006/article/details/72833012

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命令同步代码到生产环境。

  http://blog.jobbole.com/110304/

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)
  http://www.cnblogs.com/linhaifeng/articles/7811861.html

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中如何实现限速?


  http://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 

  http://www.cnblogs.com/wupeiqi/articles/6229292.html

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的调度器如何实现任务的深度优先和广度优先?


  http://www.cnblogs.com/wupeiqi/articles/6912807.html

135. 简述 vitualenv 及应用场景?

  virtualenv就是用来为一个应用创建一套“隔离”的Python运行环境。
  https://www.cnblogs.com/technologylife/p/6635631.html

136. 简述 pipreqs 及应用场景?

  查找python项目依赖并生成requirements.txt
  https://www.cnblogs.com/bonelee/p/8183038.html

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://www.cnblogs.com/Liqiongyu/p/5911613.html
  http://www.cnblogs.com/feixuelove1009/p/6143539.html

141. 请列举常见查找并通过代码实现任意三种。

  无序查找/二分查找/插值查找
  http://www.cnblogs.com/feixuelove1009/p/6148357.html

142. 请列举你熟悉的设计模式?

  工厂模式/单例模式等
  https://www.cnblogs.com/Liqiongyu/p/5916710.html

143. 有没有刷过leetcode?

  刷过刷过刷过
  https://leetcode-cn.com/problemset/all/

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协议等。
  https://www.jianshu.com/p/679dee0a4193

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 协议可以有效防止远程管理过程中的信息泄露问题。
  https://www.jianshu.com/p/33461b619d53
 

 

155. 是否了解过领域驱动模型?

  Domain-Driven Design
  https://www.cnblogs.com/netfocus/archive/2011/10/10/2204949.html


所属网站分类: 技术文章 > 博客

作者:乐天派

链接:https://www.pythonheidong.com/blog/article/925/a5ea33d47363e2853d46/

来源:python黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

1 0
收藏该文
已收藏

评论内容:(最多支持255个字符)