315个面试题

 

1.  为什么学习Python?

  Python是一门面向对象的,解释性动态弱类型计算编程语言

  Python有大量的第三方库,为Python提供了接口

  Python开发效率高,同样的任务,大约是java的10倍,c++的10-20倍;

  Python在科研上有大量的应用,大数据计算,模拟计算,科学计算都有很多的包;

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

  通过在线教育和自学。咨询同学

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

  相同点:C、C++、C#:都是编译性语言,需要事先进行编译

  Java:具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于个人PC、数据中心、科学超级计算机、移动电话和互联网

  C:

     优点:简洁紧凑、灵活方便;运算符丰富;数据类型丰富;表达方式灵活实用;允许直接访问物理地址,对硬件进行操作;生成目标代码质量高,程序执行效率高;可移植性好;表达力强;

        缺点:C语言的缺点主要表现在数据的封装性上,这一点使得C在数据的安全性上有很大缺陷,这也是C和C++的一大区别。 C语言的语法限制不太严格,对变量的类型约束不严格,影响程序的安全性,对数组下标越界不作检查等。从应用的角度,C语言比其他高级语言较难掌握。也就是说,对用C语言的人,要求对程序设计更熟练一些。

  C#:用C# 开发应用软件可以大大缩短开发周期,同时可以利用原来除用户界面代码之外的C++代码

  Python:是一种面向对象、直译式计算机程序设计语言,Python语法简洁而清晰,具有丰富和强大的类库。

      在Python中,一切皆对象,函数、模块、数字、字符串都是对象。

      完美支持继承、派生、多继承

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

计算机是不能理解高级语言的,更不能直接执行高级语言,它只能直接理解机器语言,所以使用任何高级语言编写的程序若想被计算机运行,都必须将其转换成计算机语言,也就是机器码。由此高级语言也分为编译型语言和解释型语言

而这种转换的方式有两种:

1)编译:

  特点:

    在编译型语言写的程序执行之前,需要一个专门的编译过程,把源代码编译成机器语言的文件,因为只需编译一次,以后运行时不需要编译,所以编译型语言执行效率高。  

    因为一次性全部编译,所以程序运行效率极高

    程序在编译阶段就会报错

2)解释:解释型语言不需要事先编译,在程序执行的时候逐行解释,解释一行就读取一行

  特点:因此程序会在执行的阶段报错

     程序执行的效率没有编译型语言高

 

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

  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解释器

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

  另外:对于Python的编译,除了可以采用以上解释器进行编译外,还可自行编写Python解释器,但这需要高超的技术。

 

6. 位和字节的关系?

 

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

  略

 

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

  缩进:每级缩进用4个空格,(垂直隐式缩进)对准左括号

  空格还是tab:空格是首选的缩进方法,tab仅仅是在已经使用tab缩进的代码中我了保持一致性而使用

 

  空行:两行空行分割顶层函数和类的定义。

     类的方法定义用单个空行分割。

     额外的空行可以必要的时候用于分割不同的函数组,但是要尽量节约使用。

     额外的空行可以必要的时候在函数中用于分割不同的逻辑块,但是要尽量节约使用。

  最大行宽:限制所有行的最大行宽为79个字符

 

9.通过代码实现如下转换:

  二进制转换成十进制:v = “0b1111011”


    print(int(v),base=2)) 


  十进制转换成二进制:v = 18
 

    print(bin(v))


  八进制转换成十进制:v = “011”
 

    print(int(v),base=8)
  十进制转换成八进制:v = 30
 

    print(oct(v))


  十六进制转换成十进制:v = “0x12”
 

    print(int(v),base=16)
  十进制转换成十六进制:v = 87

      print(hex(19))

 

 

 

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递归的最大层数?

 

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   Flase

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

  ascii:初期密码本,只包含数字、字母,特殊符号。只有8位

  unicode:万国码

    初期:16位,2个字节表示一个字符

      但是随着国家的增多和扩充,逐渐的不够用了

      例如中国的汉字就只能存储2*16==65536,不能显示全部的汉字。

    中期:32位,4个字节表示一个字符

      缺点:造成资源的浪费

 

  在ASCII和Unicode的基础之上,升级的utf-8出来了

  UTF-8:

    英文:8位,1个字节表示一个字符。

    欧洲 拉丁文:16位,2个字节表示一个字符。

    亚洲 中国:24位,3个字节表示一个字符

  gbk国标:只包含中文、英文。

    英文:8位,1个字节表示一个字符

    中文:16位,两个字节表示一个字符。


 

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

  机器码(machine code):学名机器语言指令,有时也被称为原生码(Native Code),是电脑的CPU可直接解读的数据。运行速度最快,但是非常晦涩难懂,也比较难编写,一般从业人员接触不到

  字节码:本质上是一种二进制文件。字节码是一种中间码,它比机器码更抽象,需要直译器转译后才能成为机器码的中间代码。

 

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

   三元运算符是if-else的一种简写:a if a > b else b

 

 

16.列举 Python2和Python3的区别?

源码:
python3:源码规范,崇尚优美,清晰,简单
python2:源码混乱,重复代码较多,冗余

print输出:
python3 print("内容")

python2 print '内容'

编码:
python3 :utf-8

python2: 默认编码:ascii
解决办法:在首行加上: # -*- ending:utf-8-*-

用户交互:
input
python2: raw-input()
python3:input ()

Tab键:
python2x :默认2个字节表示一个字符

python3x:默认是4个字节表示一个字符

nonlocal:
python2x:没有nonlocal

python3x:有


object类:
python2 中的经典类 遍历方法是以深度优先 新式类是以广度优先

python3 中不存在经典类 所有的类都是新式类 所以Python3中都是广度优先

 

 

17.用一行代码实现数值交换:
     
 a = 1
 
     b = 2

   答案:a,b = b,a

 

 

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

  python2:  有非浮点数准备的int和long类型

  在python3:  ,只有一种整数类型int,

 

 

19. xrange和range的区别?

  range(start,end,sep):包含起点,但不包含终点,返回等差数列,可以设置步长。

    注:当终点为负值时,步长只能为负数==》即:倒叙

  xrange(start,end,sep):与range相似,只是返回的是一个"xrange object"对象,而非数组list

   区别:.range返回的是一个list对象,而xrange返回的是一个生成器对象(xrange object)

 

 

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

  xreadlines:返回一个生成器

  readlines:返回一个list

  区别:二者返回类型不同。但使用时相同

 

 

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

‘’ None 0 [] () {}

 

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

   

 

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

lambda:匿名函数

lambda x : x + 2
lambda *args : sum(args)
lambda **kwargs : 1
使用场景:内部含所有lambda方法的函数,函数式编程(map, reduce filter sorted),闭包,

 

 

24. pass的作用?

1、空语句,什么都不做
2、保证格式完整性
3、语义完整

 

25. *arg和**kwarg作用

  在函数定义时:代表聚合,*arg会把多出来的位置参数转化为tuple;**kwarg会把关键字参数转化为dict

  在函数调用时:代表打散

 

26. is和==的区别

  is判断id地址是否相等

  ==判断数值是否相等

 

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

深拷贝:开辟两块新的内存地址,两者完全不相干,一方的变动不会影响到到另一方

浅拷贝:第一层开辟了新的内存地址,从第二层开始,用同一个内存地址     

赋值运算:使用同一个内存地址

 

 

28. Python垃圾回收机制?

专注于两件事:
1. 找到内存中无用的垃圾资源
2. 清除这些垃圾并把内存让出来给其他对象使用。

垃圾回收机制包括:
  引用计数:该对象被引用时,引用计数+1,但对象的循环引用会导致内存泄露。
  标记清除:它分为两个阶段:
    第一阶段:是标记阶段,把所有的『活动对象』打上标记,
    第二阶段:是把那些没有标记的对象『非活动对象』进行回收
  分代收集/回收:分代回收是一种以空间换时间的操作方式。
Python将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代。年轻代(第0代)、中年代(第1代)、老年代(第2代),
他们对应的是3个链表,它们的垃圾收集频率与对象的存活时间的增大而减小。
新创建的对象都会分配在年轻代,年轻代链表的总数达到上限时,Python垃圾收集机制就会被触发,把那些可以被回收的对象回收掉,
而那些不会回收的对象就会被移到中年代去,依此类推,老年代中的对象是存活时间最久的对象,甚至是存活于整个系统的生命周期内。


简单解释:
1,当一个对象的引用计数归零时,它将被垃圾收集机制处理掉。

2,当两个对象a和b相互引用时,del语句可以减少a和b的引用计数,并销毁用于引用底层对象的名称。
然而由于每个对象都包含一个对其他对象的应用,因此引用计数不会归零,对象也不会销毁。(从而导致内存泄露)。
为解决这一问题,解释器会定期执行一个循环检测器,搜索不可访问对象的循环并删除它们。

 

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

可变类型:list,dict,set,可变集合
不可变类型:string,int,float,tuple,不可变集合

30. 求结果:

   v = dict.fromkeys(['k1','k2'],[])
 
   v[‘k1’].append(666)

   print(v)

   v[‘k1’] = 777

   print(v)

31. 求结果:

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

len()
count()
print()
max()
min()
dir()
list()
eval()
open()
str()
isinstance()
format()
type()
tuple()
iter()
input()
int()
set()
frozenset()
hash()
help()
callable()
dir()
bin()
oct()
hex()
abs()
divmod()
round()
pow()



 

 

33. filter、map、reduce的作用?

 filter:

  如果用filter的话,说明匿名函数lambda给出的是个筛选条件,从1到19中筛选出奇数来,但这里如果用map的话,就好像变成了它判断对错的条件,只打印true和false。

map:

  一般的用法:参数有一个函数一个序列,将右边的序列经过左边的函数变换,生成新的序列

reduce:

  累加函数,并不是很常用,在python3中已将其从全局空间移除,现被放置在functools的模块里,用之前需要引入  from functools import reduce

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

 print([['%s*%s=%s' % (j, i, i * j) for j in range(1,i+1)]for i in range(1,10)])

 print("\n".join([" ".join(['%s*%s=%s' % (j, i, i * j) for j in range(1,i+1)]) for i in range(1,10)]))

 

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

  1.File=》settings=》Project=》ProjectInterpreter页面右上角的"+"号手动添加模块

  2.cmd终端输入:pip install

  使用过的第三方模块:requests、pymysql、DBUtils,mongodb,Twisted,bs4,gevent,geventlet,pipreqs,xpath,redis,pillow,wheel,scrapy,scrapy-redis,Flask,Django,Flask-scrapy,Flask-sqlalchemyflask-migrate,

 

 

36. 至少列举8个常用模块都有那些?

 collections,logging,configparser,hashlib,time,random,datetime,OS,sys,json,pickle,shelve,re,functools,requests,socket,gevent,greenlet,math,

 

37. re的match和search区别?

 match:正则表达式需要匹配开头,即“^”

search:正则表达式只要匹配到就行

 

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

 

 

39. 求结果:


  a. [ i % 2 for i in range(10) ]


  b. ( i % 2 for i in range(10) )

  结果:

    a:列表表达式,[0, 1, 0, 1, 0, 1, 0, 1, 0, 1]

    b:生成器  <generator object <genexpr> at xxxx>

 

 

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=[]) 这种写法有什么坑?

 坑:默认参数是可变数据类型时,会修改默认参数,形成了列表陷阱

 

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

 字符串的split()用法

 

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

字符串的join用法

print(type("".join( ["1","2","3"])))

 

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

a = [1, 2, 3]
b = [(1), (2), (3)]
c = [(1,),(2,),(3,) ]
print(type(a),type(b),type(c))  # <class 'list'> <class 'list'> <class 'list'>

 区别:

   表面上看ABC都是列表,但是列表里面的数据类型不同

 

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

 

print([i**2 for i in range(1,11)])

 

 

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

list(set()):使用集合去重

 

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

 global

 

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

 作用:用于输出与日志相关的各种信息和配置

 

49. 请用代码简答实现stack 。

class Node(object):
    def __init__(self, val):  # 定位的点的值和一个指向
        self.val = val  # 指向元素的值,原队列第二元素
        self.next = None  # 指向的指针


class Stack(object):
    def __init__(self):
        self.top = None  # 初始化最开始的位置

    def top(self):  # 获取栈顶的元素
        if self.top != None:  # 如果栈顶不为空
            return self.top.val  # 返回栈顶元素的值
        else:
            return None

    def push(self, n):  # 添加到栈中
        n = Node(n)  # 实例化节点
        n.next = self.top  # 顶端元素传值给一个指针
        self.top = n
        return n.val

    def pop(self):  # 退出栈
        if self.top == None:
            return None
        else:
            tmp = self.top.val
            self.top = self.top.next  # 下移一位,进行
            return tmp


if __name__ == "__main__":
    s = Stack()
    s.push(1)
    s.push(2)
    s.push(3)

    print(s.pop())
    print(s.pop())
    print(s.pop())

 

 

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

第一种:%r,%s,%d,

第二种:字典键值对

第三种:.format()

 

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

# 迭代器和生成器之间的区别:
# 在理解这个概念之前,先要理解;容器
#     容器:容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in, not in关键字判断元素是否包含在容器中。
# 可迭代对象:
#     内部实现了__iter__方法的对象
# 迭代器:它是一个带状态的对象,他能在你调用next()方法的时候返回容器中的下一个值,
#     任何实现了__iter__和__next__()(python2中实现next())方法的对象都是迭代器,
#     __iter__返回迭代器自身,__next__返回容器中的下一个值,
#     如果容器中没有更多元素了,则抛出StopIteration异常,至于它们到底是如何实现的这并不重要
# 生成器:
#   它不需要再像上面的类一样写__iter__()和__next__()方法了,只需要一个yiled关键字。
#   生成器一定是迭代器(反之不成立),因此任何生成器也是以一种懒加载的模式生成值
#   特点:函数中没有return关键,函数的返回值是一个生成器对象。
#       函数遇到yield时,返回的是一个生成器对象,只有显示或隐示地调用next的时候才会真正执行里面的代码。

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

 下面代码不仅实现了二分查找,并且使用装饰器计算对比Python系统和手写的二分查找的效率

def cal_time(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        result = func(*args, **kwargs)
        t2 = time.time()
        print("%s running time: %s secs." % (func.__name__, t2-t1))
        return result
    return wrapper

@cal_time
def binary_search(li,val):
    """
    手写的二分查询的时间
    :param li:
    :param val:
    :return:
    """
    left = 0
    right = len(li)-1
    while left <= right:
        mid = (left + right) // 2
        if li[mid] == val:
            return mid
        elif li[mid] < val:
            left = mid + 1
        elif li[mid] > val:
            right = mid - 1
    return None

@cal_time
def sys_search(li, val):
    """
    系统查询时间
    :param li:
    :param val:
    :return:
    """
    try:
        return li.index(val)
    except:
        return None

li = list(range(0,2000000,2))
sys_search(li, 2000009)
binary_search(li, 2000009)

 

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

 简单解释:闭包是内层函数对外层函数但是非全局变量的引用,但是闭包中是不能修改外部作用域的局部变量的

作用:当闭包执行完后,闭包不会立即关闭,仍然能够保持住当前的运行环境

  解释:外部函数执行结束时发现自己有临时变量将来会在内部函数被用到,就会把这个临时变量绑定给内部函数,然后自己再结束

 

54. os和sys模块的作用?

OS:对于操作系统接别的

sys:这个模块可供访问由python解释器使用或维护的变量和与解释器进行交互的函数。

 附:os 和sys的基本用法

# os模块
# os模块和sys模块的区别:
#     os:提供一种方便的使用操作系统函数的方法
#     sys:提供访问由解释器使用或维护的变量和在与解释器交互使用到的函数。
#     因此, sys 模块区别于 os 模块,sys 模块提供了一系列的函数和变量,用于操控
# python 的运行时环境, 而 os 提供了访问操作系统底层的接口.



import os
# (一)与当前执行的python文件的工作目录相关的工作路径
# print(os.getcwd())   # 获取当前文件所在的路径
# os.chdir("dirname")  # 改变当前脚本工作目录;相当于shell下cd
# print(os.curdir)  # 返回当前目录:('.')一个点
# print(os.pardir)         #  返回当前目录的父级目录:('..')两个点
#(二)和文件相关的各种操作
# 1、和文件夹相关的各种操作
# os.makedirs('dirname1/dirname2')  # 在当前文件夹下面生成多层递归目录
# os.removedirs('dirname1/dirname2') # 删除多层递归空目录,并递归到上一级目录,如若也为空,则删除,依此类推
# os.mkdir('dirname/son_dir')     # 生成单级空目录,
# os.rmdir('dirname1/dirname2') # 删除单级空目录,若目录不为空则无法删除并报错
# print(os.listdir('D:\python11\新建文件夹\讲课笔记'))# 列表方式打印出指定目录下的所有文件和子目录,包括隐藏文件
# 2、和文件相关的各种操作
# os.remove(r'D:\python11\新建文件夹\讲课笔记\day28\__init__.py')   # 删除一个文件
# os.rename('oldname','newname') # 重命名一个文件/目录
# print(os.stat(r'D:\python11\新建文件夹\讲课笔记\day29'))  # 获取文件/目录的各种状态信息:os.stat('path/filename')
# (三)和操作系统差异相关的各种操作
# print(os.name)  # 输出字符串并指出当前使用平台
# os.sep  # 操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
# os.linesep  # 输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
# os.pathsep  # 输出用于分割文件路径的字符串 win下为";",Linux下为":"
# (四)和执行系统命令相关的
# os.system('base command') # 运行shell命令,直接显示
# os.popen("bash command).read()  运行shell命令,获取执行结果
# (五)和环境变量相关的
# print(os.environ)


# (六)path系列
import sys
# print(os.path.abspath('2.os.模块'))    # 返回path规范化过的xx文件/目录的绝对路径  # D:\python11\新建文件夹\讲课笔记\day28\2.os.模块

# print(sys.path[0])  # 当前文件夹路径==》D:\python11\新建文件夹\讲课笔记\day28
# print(sys.argv)# ['D:/python11/新建文件夹/讲课笔记/day28/2.os模块.py']
# 2、os.path.split(path) # 将path分割成目录和文件名并以元组的形式返回
# print(os.path.split(os.path.abspath('userinfo')))   # ('D:\\python11\\新建文件夹\\讲课笔记\\day28', 'userinfo')
# 3、print(os.path.dirname(os.path.abspath('userinfo')))#返回path的目录。其实就是os.path.split(path)的第一个元素
# print(os.path.dirname(os.path.abspath('userinfo'))) # 以绝对路径返回文件的文件夹名
# print(os.path.basename(os.path.abspath('userinfo')))# 返回path最后的文件名。其实就是os.path.split(path)的第二个元素。如果path以/或\结尾,那么就会返回空值。
# 5、print(os.path.exists(r'D:\python11\day28\userinfo2'))# 如果path存在,返回True;如果path不存在,返回False
# print(os.path.isabs(r'userinfo2')) # 如果path是绝对路径,返回True
# print(os.path.isfile(r'userinfo')) # 如果path是一个存在的文件,返回True。否则返回False
# print(os.path.isdir(r'dirname1')) # 如果path是一个存在的目录,则返回True。否则返回False
# print(os.path.join((path1,[path2[, ...]]) # 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
# print(os.path.join(os.path.dirname('userinfo')),os.path.basename(os.path.abspath('userinfo')))
# os.path.getatime(path)  # 返回path所指向的文件或者目录的最后访问时间
# os.path.getmtime(r'D:\python11\新建文件夹\讲课笔记\day28\userinfo')  # 返回path所指向的文件或者目录的最后修改时间
# print(os.path.getmtime(r'D:\python11\新建文件夹\讲课笔记\day28\userinfo'))  # 返回path所指向的文件或者目录的最后修改时间
# print(os.path.getsize(r'D:\python11'))    #返回path的大小
# print(os.path.getsize(r'D:\python11\新建文件夹\讲课笔记\day28\1.复习.py'))


# print(os.path.abspath('userinfo'))
# print(os.path.split(os.path.abspath('userinfo')))
# print(os.path.dirname(os.path.abspath('userinfo')))
# print(os.path.basename(os.path.abspath('userinfo')))
# print(os.path.exists(r'D:\python11\day28\userinfo2'))
# print(os.path.isabs(r'userinfo2'))
# print(os.path.isfile(r'userinfo'))
# print(os.path.isdir(r'dirname1'))
# print(os.path.join('D:\\python11\\day28','userinfo'))# 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
# print(os.path.getsize(r'D:\python11'))
# print(os.path.getsize(r'D:\python11期视频笔记\录制_2018_04_08_15_46_07_104.mp4'))
# 计算文件夹中所所有文件的大小

# '\\nex\\table'
# r'\nex\table'
# 用递归计算列表里面所有数字的和
# li = [1,2,3,[4,5,6,[7,8],[9,10]]]
# def calculate_sum(lis):
#     sum1 = 0
#     for i in lis:
#         if type(i) is int:
#             sum1 += + i
#         else:
#             sum1 += calculate_sum(i)
#     return sum1
# print(calculate_sum(li))
# def get_size(dir):
#     sum_size=0
#     for item in os.listdir(dir):
#         path = os.path.join(dir,item)# dir文件下面的文件或文件夹目录
#         if os.path.isfile(path):
#             sum_size += os.path.getsize(path)
#         else:
#             sum_size += get_size(path)
#     return sum_size
# ret = get_size('D:\飞Q')
# print(ret)
import os
# #获取当前目录
# print (os.getcwd())
# 获取上级目录 ret
# ret = os.pardir
# #切换到上级目录
# os.chdir(ret)
# print (os.getcwd())

# print (os.getcwd())
# os.chdir('..')
# print (os.getcwd())

 

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

 调用random模块

 

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

 os.remove(“文件路径”)

 

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

# 封装:
   # 其实就是将很多数据封装到一个对象中,类似于把很多东西放到一个箱子中,
   # 如:一个函数如果好多参数,起始就可以把参数封装到一个对象再传递。
# 继承:如果多个类中都有共同的方法,那么为了避免反复编写,就可以将方法提取到基类中实现,让所有派生类去继承即可。
   # 面向对象中的继承就是继承的类直接拥有被继承类的属性,其中被继承的类叫做父类、基类,继承的类叫做派生类、子类。
   # 在python3中如果不指定继承哪个类,默认就会继承Object类,而继承了Object类的类就叫做新式类,
   # 而在python2中如果不指定继承哪个类也不会默认去继承Object类,而没有继承Object类的类就叫做经典类。
   # 经典类和新式类的不同就在于对方法的搜索顺序不同,
   #     经典类:是深度优先
   #     新式类:是广度优先。可以通过类名.mro()方法查看新式类的继承顺序
# 多态:
   # 指基类的同一个方法在不同的派生类中有着不同的功能,而Python天生自带多态。

 

 

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

 参考第57题

 

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

 参考第57题

 

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

 super()方法:调用父类的方法和属性

 

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

 functools.wraper():显示被装饰器装饰的函数的原信息

functools.partical():偏函数,可以给函数传默认值

 functools.reduce():参考第33题

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

__call__

__dir__

__eq__

__le__

__lt__

__hash__

__repr__

__str__

__format__

__setattr__

__delattr__

__doc__  显式类的描述信息

 

 

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

from types import MethodType,FunctionType

 1:判断是否是通过类对象调用的

  是:method,类对象调用的是方法

  否:function,类直接调用的是函数

2:isinstance()

 

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

静态方法:

  装饰器定义下属于函数

  不用加括弧,无需传入参数直接通过对象调用

类方法:

  装饰器定义下属于方法

  不需要传入self参数,但是需要传入cls,

# 静态方法装饰器下定义的方法属于函数(function);
# 类方法装饰器下定义的方法属于方法(method);
# 静态方法无需传入任何参数;
# 类方法传入的第一个参数必须是class本身cls;
# 静态方法与类方法一旦被调用,内存地址即确定。通过类调用和通过实例化对象调用的结果完全一样。

 

 

 

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

__doc__     # 类的描述性信息
__module__  # 表示当前操作的对象在哪个模块
__class__   # 表示当前操作的对象的类是什么
__init__    # 构造方法,通过类创建对象时,自动触发执行
__del__     # 析构方法,当对象在内存中被释放时,自动触发执行。
__call__    # 对象后面加括号,触发执行。==>调用该对象时触发
__dict__    # 显示类或对象中的所有成员
__str__     # 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
__getitem____setitem____delitem__     用于索引操作,如字典。以上分别表示获取、设置、删除数据
__getslice____setslice____delslice__  该三个方法用于分片操作,如:列表      slice  : 切片 切割
__iter__    用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__
__new__       # 此方法用于__init__之前
__metaclass__     # 原类信息

 

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

# import itertools
# permutation:排列,通俗地讲,就是返回可迭代对象的所有数学全排列方式。

# print(len(list(itertools.permutations('12345',3))))  # 60

# count:创建一个无限的迭代器,打印出自然数序列
# ns = itertools.count(1)
# for n in ns:
#    print(n)

# cycle:会把传入的一个序列无限重复下去
# ns = itertools.cycle("ABC")
# for n in ns:
#    print(n)

# repeat:默认把一个元素无限重复下去,可以限定重复次数
# ns = itertools.repeat("ABC",10)
# for n in ns:
#    print(n)

# chain:可以把一组迭代对象串联起来,形成一个更大的迭代器
# print([i for i in itertools.chain("ABC","123")])

#  groupby:把迭代器中相邻的重复元素挑出来放在一起:
# for key, group in itertools.groupby('AAACAAABBBC'):
#     print(key,list(group))

# imap
# imap和map的区别:imap()可以作用于无穷序列,并且,如果两个序列的长度不一致,以短的那个为准。
# 注意:Python3中没有这个使用方法
# for x in itertools.imap(lambda x, y: x * y, [10, 20, 30], itertools.count(1)):
#     print(x)

 

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

反射就是以字符串的方式导入模块,以字符串的方式执行函数
# 应用场景:
   rest framework里面的CBV

 

 

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

 metaclass?元类?通俗的就是说,元类就是创建类的类,一个类的创建工厂。用它指定用哪个类去创建类

 

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

'''单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。
通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。
如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。'''

"""

# 单例模式
'''单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。
通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。
如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。'''
# 1、使用__new__方法
    class Singleton(object):
        def __new__(cls, *args, **kw):
            if not hasattr(cls, '_instance'):
                orig = super(Singleton, cls)
                cls._instance = orig.__new__(cls, *args, **kw)
            return cls._instance
    class MyClass(Singleton):
    a = 1
# 2、共享属性
# 创建实例时把所有实例的__dict__指向同一个字典,这样它们具有相同的属性和方法.
    class Borg(object):
        _state = {}
        def __new__(cls, *args, **kw):
            ob = super(Borg, cls).__new__(cls, *args, **kw)
            ob.__dict__ = cls._state
            return ob
    class MyClass2(Borg):
        a = 1
# 3、装饰器版本
    def singleton(cls, *args, **kw):
        instances = {}
        def getinstance():
            if cls not in instances:
                instances[cls] = cls(*args, **kw)
            return instances[cls]
        return getinstance
    @singleton
    class MyClass:
    ...
# 4、import方法
# 作为python的模块是天然的单例模式
    # mysingleton.py
    class My_Singleton(object):
        def foo(self):
            pass
    my_singleton = My_Singleton()
    # to use
    from mysingleton import my_singleton
    my_singleton.foo()

"""

 

 

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

 略

 

 

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

while True:
   try:
      x = int(input("Please enter a number: "))
      break
   except ValueError:
      print("Oops!  That was no valid number.  Try again   ")
# raise主动抛出一个异常

 

 

72. 什么是面向对象的mro

 在多继承的条件下,查看类的继承顺序

 

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

 判断对象和类是否具有血缘关系==》判断该对象是否是类的实例化

还可用于判断该对象是哪个类的实例化对象

74. 写代码并实现:
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  

 

 

75. json序列化时,可以处理的数据类型有哪些?如何定制支持datetime类型?

字典,列表,字符串,数字,元祖(元祖序列化之后会变成列表,即使反序列化之后也不会回来)

strftime():字符串格式化
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"}

 

 

 

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

# json.dumps({"xxx":"XXXX"},ensure_ascii=False)

 

 

 

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

#  什么是断言?应用场景?
# 条件成立则继续往下,否则抛出异常;
# 一般用于:满足某个条件之后,才能执行,否则应该抛出异常。
#  '应用场景':rest framework中,如果要继承GenericAPIView类,那么就必须要设置queryset,否则断言错误

 

 

 

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

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

 

 

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

# path = os.listdir('.') # 查看当前目录下的所有文件。
# path = os.listdir(os.getcwd())  # 查看指定目录下的所有文件。
# print(path)

 

 

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

注:yield和send的区别:

#1 yiled可以保存状态,yield的状态保存与操作系统的保存线程状态很像,但是yield是代码级别控制的,更轻量级
#2 send可以把一个函数的结果传给另外一个函数,以此实现单线程内程序之间的切换

 

yield在函数中遇到yield,那么这就不是一个函数,而是一个生成器,生成器只有在函数调用时才会生成数据,这样可以节省内存。生成器方法调用时,不会立即执行,需要调用next()或者使用for循环来执行

yield from:为了让生成器(带yield函数),能简易的在其他函数中直接调用,就产生了yield from

# yield 和yield from
# yield:在函数中遇到yield,那么这就不是一个函数,而是一个生成器,生成器只有在函数调用时才会生成数据,这样可以节省内存。生成器方法调用时,不会立即执行,需要调用next()或者使用for循环来执行
# yield from:为了让生成器(带yield函数),能简易的在其他函数中直接调用,就产生了yield from
def htest():
    i = 1
    while i < 4:
        n = yield i
        if i == 3:
            return 100
        i += 1


def itest():
    val = yield from htest()    # 使用生成器直接调用其它函数
    print(val)

t = itest()
t.send(None)
j = 0
while j < 3:
    j += 1
    try:
        t.send(j)
    except StopIteration as e:
        print('异常了')

  第二部分:网络编程

1. 简述 OSI 七层协议。

1、七层模型:
应用层        提供OSI用户服务,例如事务处理程序、文件传送协
表示层        提供两进程之间建立、维护和结束会话连接的功能;提供交互会话的管理功能
会话层        建立或解除与其他接点的联系
传输层        提供端对端的接口
网络层        为数据包选择路由
数据链路层    传输有地址的帧,错误检测
物理层        以二进制的数据传输形式在物理媒体上传输设备

2、普通5层模型、每层对应的协议、每层对应的物理设备
osi层:           协议:                物理设备:
应用层         http,DNS,FTP,Telnet      各种软件
传输层         tcp/udp                   四层路由器、四层交换机
网络层         ip                        路由器、三层交换机
数据链路层     arp                       交换机、网卡、网桥:用于连接不同的网端
物理层         暂无                      双绞线、集线器、中继器

 

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

# C/S 架构 :
#      client端与server端的服务架构,几乎包含了所有网络开发的架构形态
# B/S 架构:也是C/S架构,隶属于C/S架构,
#      Broswer端(网页端)与server端;B/S 构中的client即:browser浏览器
#      优势:统一了所有应用的入口,方便、轻量级 —— 趋势

 

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

"""
三次握手,四次挥手
三次握手:
   1.客户端(Client)向服务端(Server)发送一次请求
   2.服务端确认并回复客户端
   3.客户端检验确认请求,建立连接
四次挥手:
   1.客户端向服务端发一次请求
   2.服务端回复客户端(断开客户端-->服务端)
   3.服务端再次向客户端发请求(告诉客户端可以断开了)
   4.客户端确认请求,连接断开
"""

 

4. 什么是arp协议?

"""
什么是ARP协议?
ARP:地址解析协议,是根据IP地址获取物理地址的一个TCP/IP协议,其主要用作将IP地址翻译为以太网的MAC地址
在局域网中,网络中实际传输的是“帧”,帧里面是有目标主机的MAC地址的。
在以太网中,一个主机要和另一个主机进行直接通信,必须要知道目标主机的MAC地址。
所谓“地址解析”就是主机在发送帧前将目标IP地址转换成目标MAC地址的过程。
ARP协议的基本功能就是通过目标设备的IP、地址,查询目标设备的MAC地址,以保证通信的顺利进行。
"""

 

5. TCP和UDP的区别?

1、TCP协议:
优点:可靠的、面向连接的、全双工的连接,通讯的双方随时可以进行通讯并获取到对方的回复
缺点:传输速率低,容易占用大量的网络通讯资源,影响到其它程序正常的通讯
    表现:三次握手 和 四次挥手
        三次握手:
           1.客户端(Client)向服务端(Server)发送一次请求
           2.服务端确认并回复客户端
           3.客户端检验确认请求,建立连接
        四次挥手:
           1.客户端向服务端发一次请求
           2.服务端回复客户端(断开客户端-->服务端)
           3.服务端再次向客户端发请求(告诉客户端可以断开了)
           4.客户端确认请求,连接断开
2、UDP协议:
优点:面向数据包、传输速度快、且不会长期占用系统的连接资源
缺点:不可靠,数据容易丢失,且接收方可能会接收不到信息
    数据包:包packet,是TCP/IP协议通信传输中的数据单位,上一层的内容由下一层的内容来传输,所以在局域网中,“包”是包含在“帧”里的。
    网络上传输的数据数量庞大容易丢失,所以需要‘打包’,以免丢失

 

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

# 局域网和广域网
# 局域网 :局域网(Local Area Network),简称LAN,
  是指在某一区域内由多台计算机互联成的计算机组。局域网是封闭型的,甚至可以一间由办公室内的两台计算机组成,也可以由一个公司内的上千台计算机组成。
# 广域网:广域网(Wide Area Network),简称WAN,
  是一种跨越大的、地域性的计算机网络的集合。通常跨越省、市,甚至一个国家。广域网包括大大小小不同的子网,子网可以是局域网,也可以是小型的广域网。

 

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

原因:参考第3题,三次握手和四次

 

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

"""
# 是模块 是和应用层直接交互,
        # 向下封装了,应用层之下的相关协议的一组网络通信的接口
# 流程: #服务端: 创建套接字 绑定IP和端口 监听 accept等待连接 通信(收recv、发send) #客户端: 创建套接字 绑定IP和端口 链接服务器 通信(收revc、发send)
"""

 

服务器端:

import socket
# 基于tcp协议的一次通信
sk = socket.socket()   # 买手机
# sk.bind(('192.168.11.53',9999))    # 装一张电话卡
sk.bind(('127.0.0.1',9999))    # 装一张电话卡
# 8000 - 10000
sk.listen()   # 开机

conn,addr = sk.accept()   # 等着 接电话  我们两个的连接,对方的地址
print(addr)
conn.send('你好'.encode('utf-8'))
ret = conn.recv(1024)   #1024  表示接受1024个字节
print(ret.decode('utf-8'))

conn.close()   # 挂电话
sk.close()     # 关手机

# 计算机的回环地址  127.0.0.1

 

 

客户端:

import socket

sk = socket.socket()   # 买个手机
sk.connect(('127.0.0.1',9999))   # 打电话

ret = sk.recv(1024)
print(ret.decode('utf-8'))
sk.send('你也好'.encode('utf-8'))

sk.close()    # 关机

 

9. 什么是粘包? socket 中造成粘包的原因是什么? 哪些情况会发生粘包现象?

"""
什么是黏包?
粘包:当两次提交的数据都比较大,刚好第一次尾与第二次的首同一时间待在了stream里,被接收到了,这就是黏包,
    主要因为:接收方不知道发送的两次消息如何接受和断句,不知道一次性提取多少字节的数据造成的。
    当数据量比小大且发送时间间隔比较短,一个数据流来不及发送出去下一个数据流就发送过来了,就合并成了一个包,这是底层的一个优化算法(Nagle算法)
    黏包最本质的原因就是接收方不知道接收的包有多大
Nagle算法:
    Nagle算法主要是避免发送小的数据包,要求TCP连接上最多只能有一个未被确认的小分组,在该分组的确认到达之前不能发送其他的小分组。
    相反,TCP收集这些少量的小分组,并在确认到来时以一个分组的方式发出去。
"""

 

10. IO多路复用的作用?

# IO多路复用的作用?
# I/O多路复用实际上就是用select, poll, epoll监听多个io对象,当io对象有变化(有数据)的时候就通知用户进程。好处就是单个进程可以处理多个socket
# IO多路复用分为时间上的复用和空间上的复用,
# 空间上的复用是指将内存分为几部分,每一部分放一个程序,这样同一时间内存中就有多道程序;
# 时间上的复用是指多个程序需要在一个cpu上运行,不同的程序轮流使用cpu,
# 当某个程序运行的时间过长或者遇到I/O阻塞,操作系统会把cpu分配给下一个程序,
# 保证cpu处于高使用率,实现伪并发。

 

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

# 什么是防火墙?
防火墙也称防护墙,是一个分离器,一个限制器,也是一个分析器,
有效地监控了内部网和外网之间的任何活动,保证了内部网络的安全。
# 作用
防火墙可通过监测、限制、更改跨越防火墙的数据流,
对外:尽可能地屏蔽网络内部的信息、结构和运行状况,以此来实现网络的安全保护。

 

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

参考连接:https://www.cnblogs.com/jeakeven/p/5435916.html

参考博客:https://www.cnblogs.com/maociping/p/5129858.html

"""
select本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理。这样所带来的缺点是:   
    # 注:fd,文件描述符:file descriptor
    1.fd的限制:单个进程可监视的fd最大数量被限制,最大是1024,且由于select采用轮询的方式扫描文件描述符,
        文件描述符数量越多,性能越差
    2.占用空间:内核 / 用户空间内存拷贝问题,select需要复制大量的句柄数据结构,产生巨大的开销,
        这样会使得用户空间和内核空间在传递该结构时复制开销大
    3.费时:select返回的是包含整个句柄的数组,应用程序需要遍历整个数组才能发现哪些句柄发生了事件
    4.对socket的重复扫描:对socket进行扫描时是线性扫描,即采用轮询的方法,重复且效率低下
poll:本质上和select没有区别,它将用户传入的数组拷贝到内核空间
    优点:它没有最大连接数的限制,原因是它是基于链表来存储的,但是同样有一个缺点:
    缺点:
        1. 大量复制:大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。
        2. 重复报告:poll还有一个特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd
epoll支持水平触发和边缘触发,最大的特点在于边缘触发,它只告诉进程哪些fd刚刚变为就绪状态,并且只会通知一次。
    优点:
        1. 没有最大并发连接的限制:能打开的fd的上限远大于1024(1G的内存上能监听约10万个端口)。
        2. 效率提升:不使用轮询的方式,不会随着fd数目的增加效率下降。
        3. 减低内存消耗:epoll使用mmap()减少复制开销
      mmap():实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系
        参考博客:https://www.cnblogs.com/huxiao-tee/p/4660352.html
"""

 

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

"""
进程:
    是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
    拥有自己独立的堆 栈,既不共享堆,亦不共享栈,进程由操作系统调度。
    狭义定义:进程是正在运行的程序的实例
    广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。
    特性:
        动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。
        并发性:任何进程都可以同其他进程一起并发执行
        独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;
        异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进
        结构特征:进程由程序、数据和进程控制块三部分组成。
        多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结果;但是执行过程中,程序不能发生改变。
线程:
    cup调度的最小单位,线程是进程中的一个实体,是被系统独立调度和分配的基本单位
    特性:
        轻型实体
        能够独立调动和分配的基本单位
        共享进程资源。
        并发执行
    拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度
    

协程:
    是一种用户态的轻量级线程,即协程是由用户程序自己控制并调度的。
    优点:
        1. 协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级
        2. 单线程内就可以实现并发的效果,最大限度地利用cpu
    缺点:
        1. 协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程
        2. 协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程
    特点:
        1. 必须在只有一个单线程里实现并发
        2. 修改共享数据不需加锁
        3. 用户程序里自己保存多个控制流的上下文栈
        4. 附加:一个协程遇到IO操作自动切换到其它协程(如何实现检测IO,yield、greenlet都无法实现,就用到了gevent模块(select机制)

协程和线程的区别:
  协程避免了无意义的调度,由此可以提高性能;但同时协程也失去了线程使用多CPU的能力

 

"""

 

14. GIL锁是什么鬼?

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

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

 

注:引入锁的原因

"""
# 锁 Lock
# acquire release
# 锁是一个同步控制的工具
# 如果同一时刻有多个进程同时执行一段代码,
# 那么在内存中的数据是不会发生冲突的
# 但是,如果涉及到文件,数据库就会发生资源冲突的问题
# 我们就需要用锁来把这段代码锁起来
# 任意一个进程执行了acquire之后,
# 其他所有的进程都会在这里阻塞,等待一个release
"""

 

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

进程池:

import os
import time
import random
from multiprocessing import Pool

def func(i):
    print('func%s' % i,os.getpid())# 获取当前进程id
    # time.sleep(random.randint(1,3))
    return i
if __name__ == '__main__':
    p = Pool(5)
    ret_l = []
    for i in range(20):
        # p.apply(func=func,args=(i,))    # 同步调用
        ret = p.apply_async(func=func,args=(i,))# 异步调用,apply_async是apply的异步版本。
        ret_l.append(ret)
    for ret in ret_l : print(ret.get()) #主进程和所有的子进程异步了

 

线程池:

# 线程池:
import time
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
    # concurrent a.并发的,同时的      Executor n.执行者/人
# concurrent.futures高度封装了模块--》内置模块
def func(i):
    print(i*'*')
    time.sleep(5)
    return i**2

def callb(args):
    print(args.result()*'-') # arg.result()获取回调函数的结果

if __name__ == '__main__':
    # thread_pool = ThreadPoolExecutor(5)
    thread_pool = ThreadPoolExecutor(5)
    # ret_lst = []
    for i in range(20):
        thread_pool.submit(func,i).add_done_callback(callb)   # 相当于apply_async  # add_done_callback()回调函数
        # ret = thread_pool.submit(func,i).add_done_callback(callable)   # 相当于apply_async
        # ret_lst.append(ret)
    thread_pool.shutdown()           # shutdown()方法等于==》close()+join()
    # for ret in ret_lst:
    #     print(ret.result())
    print('wahaha')

 

参考博客:http://www.cnblogs.com/haiyan123/p/7461294.html

 

16. threading.local的作用?

"""
16. threading.local的作用:

a.threading.local
作用:为每个线程开辟一块空间进行数据存储。用来保存一个全局变量,但是这个全局变量只有在当前线程才能访问,
问题:自己通过字典创建一个类似于threading.local的东西。
storage = {
   4740: {val: 0},
   4732: {val: 1},
   4731: {val: 3},
}

b.自定义Local对象
作用:为每个线程(协程)开辟一块空间进行数据存储。
import threading
# 创建全局ThreadLocal对象:
localVal = threading.local()
localVal.val = "Main-Thread"
def process_student():
    print '%s (in %s)' % (localVal.val, threading.current_thread().name)
def process_thread(name):
    #赋值
    localVal.val = name
    process_student()
t1 = threading.Thread(target= process_thread, args=('One',), name='Thread-A')
t2 = threading.Thread(target= process_thread, args
"""

 

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

进程间通讯有多种方式,包括信号,管道,消息队列,信号量,共享内存,socket等

18. 什么是并发和并行?

# 并发:同一时刻只能处理一个任务,但一个时段内可以对多个任务进行交替处理(一个处理器同时处理多个任务)
# 并行:同一时刻可以处理多个任务(多个处理器或者是多核的处理器同时处理多个不同的任务)
# 类比:并发是一个人同时吃三个馒头,而并行是三个人同时吃三个馒头。

 

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

"""
进程锁、线程锁
进程锁:也是为了控制同一操作系统中多个进程访问一个共享资源,只是因为程序的独立性,各个进程是无法控制其他进程对资源的访问的,
但是可以使用本地系统的信号量Semaphore控制(操作系统基本知识)
    Semaphore信号量:同一时间只能有指定个数的进程执行同一段代码
    Semaphore = 锁+计数器 线程锁:虽然线程自带GIL,但是这种计算完毕之后重新赋值的情况,可能还会发生信息不安全或者结果和我们预期的不一样,因此还是锁Lock比较安全
"""

 

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

"""
异步:多个任务一起执行  客户端
非阻塞:遇到IO操作阻塞不等待  服务端

"""

 

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

"""
'交换机'
用于在同一网络内数据快速传输转发,工作在数据链路层;
通过MAC寻址,不能动态划分子网;
只能在一条网络通路中运行,不能动态分配。

'路由器'
是一个网关设备,内部局域网到公网的一个关卡;
工作在网络层;
通过IP寻址,可以划分子网;
可以在多条网络通道中运行,可以动态分配IP地址。

'简单说'
交换机就是把一根网线变成多根网线;
路由器就是把一个网络变成多个网络;
如果不上外网,只是局域网,交换机即可;
如果上外网,并且给网络划分不同网段,就必须用路由器。
"""

 

22. 什么是域名解析?

因为ip地址很难记住,在用户体验上极差,所以就出现了域名,

而ARP域名解析就是 将域名转换为ip地址的这样一种行为。

 

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

"""
'hosts':
Hosts就是将一些常用的网址域名与其对应的IP地址建立一个关联“数据库”
可以用来屏蔽一些网站,或者指定一些网站(修改hostsFQ)
'修改':
    # windows:
        位置:C:\Windows\System32\drivers\etc
        也可以通过第三方软件,我用的火绒,可以直接进行编辑hosts
    # linux:
        位置:/etc/hosts
        修改:vi /etc/hosts

"""

 

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

生产者消费者模型:生产者只负责生产,生产完毕之后交给缓冲区或消息队列(例如:rabbit-mq)而不管消费;消费者只需要从缓冲队列里拿到消息进行处理而不管如何生产

应用场景:处理数据比较消耗时间,线程独占,生产数据不需要即时的反馈等

优势

  1. 解耦,即降低生产者和消费者之间的依赖关系。

  2. 支持并发,即生产者和消费者可以是两个独立的并发主体,互不干扰的运行。 

  3. 处理忙闲不均

25. 什么是cdn?

cdn:content divery network,内容分发网络

CDN的基本原理是广泛采用各种缓存服务器,将这些缓存服务器分布到用户访问相对集中的地区或网络中,在用户访问网站时,利用全局负载技术将用户的访问指向距离最近的工作正常的缓存服务器上,由缓存服务器直接响应用户请求。

# 用户获取数据时,不需要直接从源站获取,通过CDN对于数据的分发,
# 用户可以从一个较优的服务器获取数据,从而达到快速访问,并减少源站负载压力的目的。

 

26. LVS是什么及作用?

# LVS即Linux虚拟服务器,是一个虚拟的四层交换器集群系统,
# 根据目标地址和目标端口实现用户请求的转发,本身不产生流量,只做用户请求转发。

 

27. Nginx是什么及作用?

Nginx是一个轻量级、高性能、稳定性高、并发性好的HTTP和反向代理服务器。也是由于其的特性,其应用非常广

作用:

"""

1. 反向代理:
    区别正反向代理:
        正向代理:某些情况下,代理我们用户去访问服务器,需要用户手动的设置代理服务器的ip和端口号。
        反向代理:是用来代理服务器的,代理我们要访问的目标服务器。代理服务器接受请求,然后将请求转发给内部网络的服务器(集群化),
      并将从服务器上得到的结果返回给客户端,此时代理服务器对外就表现为一个服务器。 Nginx在反向代理上,提供灵活的功能,可以根据不同的正则采用不同的转发策略,如图设置好后不同的请求就可以走不同的服务器。 2. web-server:虚拟主机:当一台部署单个应用的web服务器资源过剩时,可以在该服务器上部署多个应用, 3. cache server,缓存服务,充当HTTP静态服务器,用于缓存图片,文件等静态资源。 4. 负载均衡:七层负载均衡,可以感知后端应用服务器的可用性
"""

 

28. keepalived是什么及作用?

"""
keepalived及作用
    Keepalived是基于vrrp协议的一款高可用软件。
        VRRP(Virtual Router Redundancy Protocol,虚拟路由器冗余协议),VRRP是为了解决静态路由的高可用而定制出来的协议
    Keepailived有一台主服务器和多台备份服务器,在主服务器和备份服务器上面部署相同的服务配置,使用一个虚拟IP地址对外提供服务,
    当主服务器出现故障时,虚拟IP地址会自动漂移到备份服务器
"""

 

29.haproxy是什么以及作用?

"""
haproxe是什么及作用:
    HAProxy提供高可用性、负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机。
    HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。HAProxy运行在当前的硬件上,完全可以支持数以万计的并发连接。
  并且它的运行模式使得它可以很简单安全的整合进您当前的架中,同时可以保护你的web服务器不被暴露到网络上。
"""

 

30. 什么是负载均衡?

"""
负载均衡有两方面的含义:
    首先,大量的并发访问或数据流量分担到多台节点设备上分别处理,减少用户等待响应的时间;
    其次,单个重负载的运算分担到多台节点设备上做并行处理,每个节点设备处理结束后,
     将结果汇总,返回给用户,系统处理能力得到大幅度提高。
"""

 

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

"""
RPC:Remote Procedure Call:远程过程调用协议,是一种进程间通信方式。
    它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。
    即程序员无论是调用本地的还是远程的,本质上编写的调用代码基本相同。
"""

 

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

asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。
asyncio的异步操作,需要在coroutine中通过yield from完成。

 

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

gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程
from gevent import monkey;monkey.patch_all()
    # monkey,它会把下面导入的所有的模块中的IO操作都打成一个包,gevent就能够认识这些IO了

 

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

"""
Twisted框架
    Twisted是一个事件驱动型的网络模型。事件驱动模型编程是一种范式,这里程序的执行流由外部决定。
    组成:Protocol, ProtocolFactory, Transport
        Protocol:Protocol对象实现协议内容,即通信的内容协议
        ProtocolFactory: 是工厂模式的体现,在这里面生成协议
        Transport: 是用来收发数据,服务器端与客户端的数据收发与处理都是基于这个模块
    特点是:包含一个事件循环,当外部事件发生时,使用回调机制来触发相应的处理。
"""

 

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

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

"""
列举常见的关系型数据库和非关系型都有那些?
关系型:
    sqllite、DB2、Oracle、access、SQLserver、MySQL
    注意:sql语句通用,关系型数据库需要有表结构
非关系型:
    mongodb、redis、memcache
    非关系型数据库是key-value存储的,没有表结构。
"""

 

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

"""
MySQL常见数据库引擎及比较
Innodb:
    支持事务,面向联机事务处理。
    其特点是行锁设计、支持外键,自动从灾难中恢复。并支持类似 Oracle 的非锁定读,即默认读取操作不会产生锁。
MyISAM:
    不支持事务、外键、表锁设计、支持全文索引,访问速度快,对事务完整性没有要求。它的缓冲池只缓存(cache)索引文件,而不缓存数据文件
    每个MyISAM在磁盘上存储成3个文件,其中文件名和表名都相同,但是扩展名分别为:
        .frm(存储表定义)
        MYD(MYData,存储数据)
        MYI(MYIndex,存储索引)
NDB:
    NDB 存储引擎是一个集群存储引擎,是一种高可用、 高性能、 高可扩展性的数据库集群系统
MERORY:
    使用MySQL Memory存储引擎的出发点是速度, 是因为Memory 存储引擎默认使用哈希索引,而不是通常熟悉的 B+ 树索引。
    一般目标数据较小,而且被非常频繁地访问时使用该存储引擎 
BLACKHOLE:
    blackhole表中没有任何数据,任何写入到此引擎的数据均会被丢弃掉,不做实际存储;Select语句的内容永远是空。
    优点:分发主库时使用该表,可以支持更多的备库。
    缺点:该表存在Bug, 例如在某些情况下会忘记将自增ID写入到二进制日志里面。所以要小心使用blackhole表
"""

 

3. 简述数据三大范式?

"""
数据库三大范式和五大约束:
【数据库三大范式】
1.第一范式(确保每列保持原子性)
    第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库表满足了第一范式。
2.第二范式(确保表中的每列都和主键相关)
    第二范式(2NF):满足1NF后,要求表中的所有列,都必须依赖于主键,而不能有任何一列与主键没有关系,也就是说一个表只描述一件事情;
3. 第三范式(3NF):必须先满足第二范式(2NF),要求:表中的每一列只与主键直接相关而不是间接相关,(表中的每一列只能依赖于主键)
【数据库五大约束】 1.primary KEY:设置主键约束; 2.UNIQUE:设置唯一性约束,不能有重复值; 3.DEFAULT 默认值约束,height DOUBLE(3,2)DEFAULT 1.2 height不输入是默认为1,2 4.NOT NULL:设置非空约束,该字段不能为空; 5.FOREIGN key :设置外键约束。
"""

 

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

"""
什么是事务?MySQL如何支持事务?
事务:
    事务由一个或多个sql语句组成一个整体;
    在事务中的操作,要么都执行修改,要么都不执行,
    只有在该事务中所有的语句都执行成功才会将修改加入到数据库中,否则回滚到上一步。
    事务的四大特性:
        原子性(A):事务是最小单位,不可再分  atomic
        一致性(C):事务要求所有的DML语句操作的时候,必须保证同时成功或者同时失败  consistency
        隔离性(I):事务A和事务B之间具有隔离性                   isolation
        持久性(D):是事务的保证,事务终结的标志(内存的数据持久到硬盘文件中)    persistence
MySQL支持事务:
    InnoDB支持事务,MyISAM不支持
    # 启动事务:
        # start transaction;
        # update from account set money=money-100 where name='a';
        # update from account set money=money+100 where name='b';
        # commit;
        'start transaction 手动开启事务,commit 手动关闭事务'
开启事务:Start Transaction 事务结束:End Transaction 提交事务:Commit Transaction 回滚事务:Rollback Transaction
"""

 

5.数据库五大约束 

略:见第3题

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

基于角色的crm项目:

多对多:用户表和角色表;角色和权限表

一对多:权限表和菜单表

一对一:用户表和用户详细信息表:

    

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

聚合函数sum()和count()

 

8. 常见SQL(必备)
  详见武沛齐博客:https://www.cnblogs.com/wupeiqi/articles/5729934.html

 

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

触发器:

  对函数进行增查改删之后进行一些自定义的操作

函数:

  在sql语句中使用聚合函数    参考博客:https://blog.csdn.net/qq_33730348/article/details/79865553 

"""
函数:在sql语句中使用聚合函数
  数学函数:
        ABS(x)   返回x的绝对值
        BIN(x)   返回x的二进制(OCT返回八进制,HEX返回十六进制)
        CEILING(x)   返回大于x的最小整数值
        EXP(x)   返回值e(自然对数的底)的x次方
        FLOOR(x)   返回小于x的最大整数值
        GREATEST(x1,x2,...,xn)返回集合中最大的值
        LEAST(x1,x2,...,xn)      返回集合中最小的值
        LN(x)                    返回x的自然对数
        LOG(x,y)返回x的以y为底的对数
        MOD(x,y)                 返回x/y的模(余数)
        PI()返回pi的值(圆周率)
        RAND()返回0到1内的随机值,可以通过提供一个参数(种子)使RAND()随机数生成器生成一个指定的值。
        ROUND(x,y)返回参数x的四舍五入的有y位小数的值
        SIGN(x) 返回代表数字x的符号的值
        SQRT(x) 返回一个数的平方根
        TRUNCATE(x,y)            返回数字x截短为y位小数的结果

  聚合函数:
        AVG(col)返回指定列的平均值
        COUNT(col)返回指定列中非NULL值的个数
        MIN(col)返回指定列的最小值
        MAX(col)返回指定列的最大值
        SUM(col)返回指定列的所有值之和
        GROUP_CONCAT(col) 返回由属于一组的列值连接组合而成的结果

  三、字符串函数
        ASCII(char)返回字符的ASCII码值
        BIT_LENGTH(str)返回字符串的比特长度
        CONCAT(s1,s2...,sn)将s1,s2...,sn连接成字符串
        CONCAT_WS(sep,s1,s2...,sn)将s1,s2...,sn连接成字符串,并用sep字符间隔
        INSERT(str,x,y,instr) 将字符串str从第x位置开始,y个字符长的子串替换为字符串instr,返回结果
        FIND_IN_SET(str,list)分析逗号分隔的list列表,如果发现str,返回str在list中的位置
        LCASE(str)或LOWER(str) 返回将字符串str中所有字符改变为小写后的结果
        LEFT(str,x)返回字符串str中最左边的x个字符
        LENGTH(s)返回字符串str中的字符数
        LTRIM(str) 从字符串str中切掉开头的空格
        POSITION(substr,str) 返回子串substr在字符串str中第一次出现的位置
        QUOTE(str) 用反斜杠转义str中的单引号
        REPEAT(str,srchstr,rplcstr)返回字符串str重复x次的结果
        REVERSE(str) 返回颠倒字符串str的结果
        RIGHT(str,x) 返回字符串str中最右边的x个字符
        RTRIM(str) 返回字符串str尾部的空格
        STRCMP(s1,s2)比较字符串s1和s2
        TRIM(str)去除字符串首部和尾部的所有空格
        UCASE(str)或UPPER(str) 返回将字符串str中所有字符转变为大写后的结果

    四、日期和时间函数
        CURDATE()或CURRENT_DATE() 返回当前的日期
        CURTIME()或CURRENT_TIME() 返回当前的时间
        DATE_ADD(date,INTERVAL int keyword)返回日期date加上间隔时间int的结果(int必须按照关键字进行格式化),如:SELECTDATE_ADD(CURRENT_DATE,INTERVAL 6 MONTH);
        DATE_FORMAT(date,fmt)  依照指定的fmt格式格式化日期date值
        DATE_SUB(date,INTERVAL int keyword)返回日期date加上间隔时间int的结果(int必须按照关键字进行格式化),如:SELECTDATE_SUB(CURRENT_DATE,INTERVAL 6 MONTH);
        DAYOFWEEK(date)   返回date所代表的一星期中的第几天(1~7)
        DAYOFMONTH(date)  返回date是一个月的第几天(1~31)
        DAYOFYEAR(date)   返回date是一年的第几天(1~366)
        DAYNAME(date)   返回date的星期名,如:SELECT DAYNAME(CURRENT_DATE);
        FROM_UNIXTIME(ts,fmt)  根据指定的fmt格式,格式化UNIX时间戳ts
        HOUR(time)   返回time的小时值(0~23)
        MINUTE(time)   返回time的分钟值(0~59)
        MONTH(date)   返回date的月份值(1~12)
        MONTHNAME(date)   返回date的月份名,如:SELECT MONTHNAME(CURRENT_DATE);
        NOW()    返回当前的日期和时间
        QUARTER(date)   返回date在一年中的季度(1~4),如SELECT QUARTER(CURRENT_DATE);
        WEEK(date)   返回日期date为一年中第几周(0~53)
        YEAR(date)   返回日期date的年份(1000~9999)
    五、格式化函数
        DATE_FORMAT(date,fmt)  依照字符串fmt格式化日期date值
        FORMAT(x,y)   把x格式化为以逗号隔开的数字序列,y是结果的小数位数
        INET_ATON(ip)   返回IP地址的数字表示
        INET_NTOA(num)   返回数字所代表的IP地址
        TIME_FORMAT(time,fmt)  依照字符串fmt格式化时间time值
        其中最简单的是FORMAT()函数,它可以把大的数值格式化为以逗号间隔的易读的序列。
        示例:
        SELECT FORMAT(34234.34323432,3);
        SELECT DATE_FORMAT(NOW(),'%W,%D %M %Y %r');
        SELECT DATE_FORMAT(NOW(),'%Y-%m-%d');
        SELECT DATE_FORMAT(19990330,'%Y-%m-%d');
        SELECT DATE_FORMAT(NOW(),'%h:%i %p');
        SELECT INET_ATON('10.122.89.47');
        SELECT INET_NTOA(175790383);
"""
函数

 

视图:

  对某些表进行SQL语句查询,将结果实时显示出来(是虚拟表),只能查询不能更新

存储过程:

 将提前定义好的SQL语句保存到数据库中并命名;以后在代码中调用时直接通过名称即可

参数类型:in、out、inout

 

10. MySQL索引种类

"""
MySQL的索引种类:
'主键索引(单列)':
    primary key
    加速查找+约束:不能重复unique、不能为空not null 
'普通索引(单列)':
    加速查找
'唯一索引(单列)':
    unique
    加速查找+约束:不能重复
'联合索引(多列)':
    查询时根据多列进行查询(遵循最左前缀原则)
     最左前缀匹配的原则,即最左优先,在检索数据时从联合索引的最左边开始匹配
'联合唯一索引(多列)': 遵循最左前缀规则(命中索引) # 其他词语 1、索引合并:利用多个单列索引查询 2、覆盖索引:在索引表中就能将想要的数据查询到
"""

 

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

联合索引时遵循最左前缀原则

 

12. 主键和外键的区别?

"""
主键和外键的区别:
主键
    唯一标识一条记录
    用来保证数据的完整性
    主键只能有一个
外键
    表的外键是另一个表的主键,外键可以有重复的,可以是空值
    用来和其他表建立联系用的
    一个表可以有多个外键
索引
    该字段没有重复值,但可以有一个空值
    提高查询速度
    一个表可以有多个唯一索引

 

13. MySQL常见的函数?

略:见第9题

14. 列举 创建索引但是无法命中索引的8种情况。

"""
使用'like ‘%xx’'
    select * from tb1 where name like '%cn';
使用'函数'
    select * from tb1 where reverse(name)='zgc';
使用'or'
    select * from tb1 where nid=1 or  email='zgc@gmial.com';
    特别的:当or条件中有未建立索引的列才失效,一下会走索引
            # select * from tb1 where nid=1 or name='zgc';
            # select * from tb1 where nid=1 or email='zgc@gmial.com' and name='zgc';
类型不一致:
    如果列是字符串类型,传入条件是必须用引号引起来,不然则可能会无法命中
    select * from tb1 where name=666;
含有'!= '
    select * from tb1 where name != 'zgc';
    特别的:如果是主键,还是会走索引
            # select * from tb1 where nid != 123;
含有'>'
    select * from tb1 where name > 'zgc';
    特别的:如果是主键或者索引是整数类型,则还是会走索引
            # select * from tb1 where nid > 123;
            # select * from tb1 where name > 123;
含有'order by'
    select email from tb1 order by name desc;
    当根据索引排序时,选择的映射如果不是索引,则不走索引
    特别的:如果对主键排序,则还是走索引:
            # select * from tb1 order by nid desc;

组合索引最左前缀
    如果组合索引为:(name,email)
    name and email #使用索引
    name           #使用索引
    email          #不使用索引
"""
View Code

 

 

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

可以通过修改配置文件开启

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

"""
MySQL数据库导入导出命令:
    window下
        1.导出整个数据库
            mysqldump -u 用户名 -p 数据库名 > 导出的文件名
            mysqldump -u dbuser -p dbname > dbname.sql
            
        2.导出一个表
            mysqldump -u 用户名 -p 数据库名 表名> 导出的文件名
            mysqldump -u dbuser -p dbname users> dbname_users.sql
        
        3.导出一个数据库结构
            mysqldump -u dbuser -p -d --add-drop-table dbname >d:/dbname_db.sql
            -d 没有数据 --add-drop-table 在每个create语句之前增加一个drop table
        
        4.导入数据库
            常用source 命令
            进入mysql数据库控制台,如
            mysql -u root -p
"""
View Code
 

17. 数据库优化方案?

"""
数据库优化方案:
1、创建数据表时把固定长度的放在前面
2、将固定数据放入内存:choice字段(django中用到,1,2,3对应相应内容)
3、char不可变,varchar可变
4、联合索引遵循最左前缀(从最左侧开始检索)
5、避免使用 select *
6、读写分离:
    #利用数据库的主从分离:主,用于删除、修改、更新;从,用于查
    #实现:两台服务器同步数据
    \原生SQL:select * from db.tb
    \ORM:model.User.object.all().using('default')
    \路由:db router
7、分库
    # 当数据库中的表太多,将某些表分到不同数据库,例如:1W张表时
    # 代价:连表查询跨数据库,代码变多
8、分表
    # 水平分表:将某些列拆分到另一张表,例如:博客+博客详情
    # 垂直分表:将某些历史信息,分到另外一张表中,例如:支付宝账单
9、加缓存
    # 利用redis、memcache(常用数据放到缓存里,提高取数据速度)
    # 缓存不够可能会造成雪崩现象
10、如果只想获取一条数据,使用limit 
    select * from tb where name = 'zgc' limit 1;
11、 创建合理的表结构
"""

 

18. char和varchar的区别?

char:定长。

 varchar:变长

"""
char:定长
    特点:
        存入字符长度大于设置长度时报错;
        存入字符串长度小于设置长度时,用空格填充以达到设置字符串长度;
    缺点:
        简单粗暴,浪费空间
    优点:存取速度快。
    用于:以时间换空间
varchar:变长
    特点:
        存储数据真实内容,不使用空格填充;
        会在真实数据前加1-2Bytes的前缀,用来表示真实数据的bytes字节数;
    优点:变长、精准、节省空间
    优点:存取速度慢。
    用于:以空间效率为首位  
"""

 

19. 简述MySQL的执行计划?

"""
MySQL的执行计划:
所谓执行计划就是:
    使用explain命令查看query语句的性能:
    explain select * from 表名; #查看执行计划中的sql的性能
    即:explain + SQL语句
    执行计划也就是SQL在数据库中执行时的表现情况,通常用于SQL性能分析,优化等场景。
"""

 

20. 在对name做了唯一索引前提下,简述以下区别:
 
        select * from tb where name = ‘Oldboy-Wupeiqi’ 
 
        select * from tb where name = ‘Oldboy-Wupeiqi’ limit 1

"""
没做唯一索引的话,前者查询会全表扫描,效率低些

limit 1,只要找到对应一条数据,就不继续往下扫描.

然而 name 字段添加唯一索引了,加不加limit 1,意义都不大;
"""

 

21. 1000w条数据,使用limit offset 分页时,为什么越往后翻越慢?如何解决?

"""
limit n m,和limit m offset n 
    都表示:取 n 后面的 m 条数据
    但是当一个数据库表过于庞大,limit offset, length中的offset值过大,则SQL查询语句会非常缓慢

# 例如:
#limit 100000,20; 从第十万条开始往后取二十条,
#limit 20 offset 100000; limit后面是取20条数据,offset后面是从第10W条数据开始读
--------------------------------------------------------------------------
'优化一'
先查看主键,再分页:
select * from tb where id in (select id from tb where limit 10 offset 30)
--------------------------------------------------------------------------
'优化二'
记录当前页,数据、ID、最大值和最小值(用于where查询)
在翻页时,根据条件进行筛选,筛选完毕后,再根据 limit offset 查询
select * from(select * from tb where id > 2222) as B limit 10 offset 0;
\如果用户自己修改页码,也可能导致变慢,此时可以对 url 页码进行加密,例如rest framework
--------------------------------------------------------------------------
'优化三'
可以按照当前业务需求,看是否可以设置只允许看前200页;
一般情况下,没人会咔咔看个几十上百页的;
"""

 

22. 什么是索引合并?

参考第 10题索引的种类的答案:联合/组合索引

"""
索引合并?
    索引合并访问方法可以在查询中对一个表使用多个索引,对它们同时扫描,并且合并结果。
        1、索引合并是把几个索引的范围扫描合并成一个索引。
        2、索引合并的时候,会对索引进行并集,交集或者先交集再并集操作,以便合并成一个索引。
        3、这些需要合并的索引只能是一个表的。不能对多表进行索引合并。
    怎么确定使用了索引合并
        在使用explain对sql语句进行操作时,如果使用了索引合并,那么在输出内容的type列会显示 index_merge,key列会显示出所有使用的索引
            例如:
                type:index_merge   
                key: key1,key2
"""

 

23. 什么是覆盖索引?

"""
覆盖索引:
# 解释一:
  就是select的数据列只用从索引中就能够取得,不必从数据表中读取,换句话说查询列要被所使用的索引覆盖。
# 解释二:
  索引是高效找到行的一个方法,当能通过检索索引就可以读取想要的数据,那就不需要再到数据表中读取行了。
# 解释三:索引包含了查询正在查找的所有数据如果一个索引包含了(或覆盖了)满足查询语句中字段与条件的数据就叫做覆盖索引。
# 注意:MySQL只能使用B-Tree索引做覆盖索引
"""

 

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

见第17题 读写分离

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

"""
分库分表
# 1、分库
    当数据库中的表太多,将某些表分到不同数据库,例如:1W张表时
    代价:连表查询跨数据库,代码变多
# 2、分表
    水平分表:将某些列拆分到另一张表,例如:博客+博客详情
    垂直分表:将某些历史信息,分到另外一张表中,例如:支付宝账单
"""

 

26. redis和memcached比较?

"""
redis 和 memcached的比较?
1. 数据存放:
    Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其他东西,例如图片、视频等等;   
2.存储容量:
    memcached超过内存比例会抹掉前面的数据,而redis会存储在磁盘
3. 过期策略:
    memcache在set时就指定,例如set key1 0 0 8,即永不过期。
    Redis可以通过例如expire 设定,例如expire name 10;
4.支持的数据类型:
    memcached只支持string;
    redis支持更多;如:hash、list、集合、有序集合、string
5.分布式:都可以做一主多从
    memcache设定memcache集群,利用magent做一主多从;
    redis可以做一主多从。
6. 存储数据安全:
    memcache挂掉后,数据没了;
    redis可以定期保存到磁盘(持久化);
7、灾难恢复:
    memcache挂掉后,数据不可恢复
8、数据备份:
    Redis支持数据的备份,即master-slave模式的数据备份;
9、应用场景:
    Redis出来作为NoSQL数据库使用外,还能用做消息队列、数据堆栈和数据缓存等;
    Memcached适合于缓存SQL语句、数据集、用户临时性数据、延迟查询数据和session等
"""

 

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

"""
redis中的数据库默认是多少个以及作用?
redis默认有16个db,db0~db15(可以通过配置文件支持更多,无上限)
并且每个数据库的数据是隔离的不能共享
可以随时使用SELECT命令更换数据库:redis> SELECT 1
注意:
      多个数据库之间并不是完全隔离的
      比如FLUSHALL命令可以清空一个Redis实例中所有数据库中的数据。
"""

 

28. python操作redis的模块?

参考博客:https://www.cnblogs.com/wang-yc/p/5693288.html

29. 如果redis中的某个列表中的数据量非常大,如果实现循环显示每一个值?

"""
如果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)
"""

 

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

"""
# 实现主从复制
redis如何实现主从复制?以及数据同步机制?
1. 配置文件目录创建两个配置文件:
    /etc/redis-6379.conf
        port 6379       
    /etc/redis-6380.conf
        port 6380
    6379为默认配置文件,作为Master服务配置;
    6380为默认配置文件,作为Slave服务配置;
2. 启动
    redis-server   /etc/redis-6379.conf
    redis-server   /etc/redis-6380.conf

    此时6379和6380无任何关系

3. 一条命令创建主从关系 或 一个配置创建主从关系
    如果想要让:
            redis-server   /etc/redis-6379.conf【主】
            redis-server   /etc/redis-6380.conf【从】
    在从中执行命令 或 添加一行配置文件:
        slaveof 主IP 端口
            例如:slaveof 127.0.0.1 6379

4. 主从时
    主:读、写
    从:读

5. 读写分离优势

    一起分担读压力
    
# 数据同步步骤:
    (1)Slave服务器连接到Master服务器.
    (2)Slave服务器发送同步(SYCN)命令.
    (3)Master服务器备份数据库到文件.
    (4)Master服务器把备份文件传输给Slave服务器.
    (5)Slave服务器把备份文件数据导入到数据库中.

"""

 

31. redis中的sentinel的作用?

"""
redis中的sentinel的作用?
sentinel,哨兵,帮助我们在主从之间进行切换,检测主从之中的主是否挂掉,且超过一半的sentinel检测到主挂掉了之后才能进行切换
此外,如果主修复好了,再次被启动的时候,会变成从
"""

 

 

32. 如何实现redis集群?

"""
如何实现redis集群?
#基于【分片】来完成。
    - 集群是将你的数据拆分到多个Redis实例的过程
    - 可以使用很多电脑的内存总和来支持更大的数据库。
    - 没有分片,你就被局限于单机能支持的内存容量。
#redis将所有能放置数据的地方创建了 16384 个哈希槽。    # 16384 = 2**14
#如果设置集群的话,就可以为每个实例分配哈希槽:
    - 192.168.1.20【0-5000】
    - 192.168.1.21【5001-10000】
    - 192.168.1.22【10001-16384】
#以后想要在redis中写值时:set k1 123 
    - 将k1通过crc16的算法转换成一个数字,然后再将该数字和16384求余,
    - 如果得到的余数 3000,那么就将该值写入到 192.168.1.20 实例中。
#集群方案:
    - redis-cluster:官方提供的集群方案。
    - codis:豌豆荚技术团队。
    - tweproxy:Twiter技术团队。
"""

 

33. redis中默认有多少个哈希槽?

见上一题

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

"""
redis的持久化策略及比较
#RDB:全量写入==》快照持久化,redis默认的持久化设置
    每隔一段时间对redis都会进行一次持久化。
     - 缺点:如果服务器宕机了,那么会导致没有写完的数据不完整
     - 优点:速度快
#AOF:增量写入
    把所有命令保存起来,如果想重新生成到redis,那么就要把命令重新执行一次。
     - 缺点:如果文件比较大,那么速度慢,
     - 优点:数据完整
    
RDB和AOF搭配着使用,先去RDB里面有没有数据,如果没有就是用AOF持久化
"""

 

35. 列举redis支持的过期策略。

"""
redis支持的过期策略:
全名:redis过期键删除策略
    Redis key过期的方式有三种:
        被动删除:当读/写一个已经过期的key时,会触发惰性删除策略,直接删除掉这个过期key
            惰性删除策略:只有key被操作时(如GET),REDIS才会被动检查该key是否过期,如果过期则删除之并且返回NIL
        主动删除:由于惰性删除策略无法保证冷数据被及时删掉,所以Redis会定期主动淘汰一批已过期的key
            当前已用内存超过maxmemory限定时,触发主动清理策略
以下是主动删除策略: # 数据集(server.db[i].expires) a、voltile-lru: #从已设置过期时间的数据集中,挑选最近频率最少数据淘汰 b、volatile-ttl: #从已设置过期时间的数据集中,挑选将要过期的数据淘汰 c、volatile-random:#从已设置过期时间的数据集中,任意选择数据淘汰 d、allkeys-lru: #从数据集中,挑选最近最少使用的数据淘汰 e、allkeys-random: #从数据集中,任意选择数据淘汰 f、no-enviction(驱逐):#禁止驱逐数据
"""

 

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

"""
MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 redis 中都是热点数据?
    1. 先限定Redis占用的内存,根据自身数据淘汰策略,淘汰冷数据,把热数据加载到内存。
    2. 再计算一下 20W 数据大约占用的内存,然后设置一下Redis内存限制即可。
"""

 

37. 写代码,基于redis的列表实现 先进先出、后进先出队列、优先级队列。

"""
import redis

conn = redis.Redis(host='192.168.11.73',port=6379)

# ############################## 字符串操作 ################################
# conn.set('k1','v1',ex=3)
# val = conn.get('k1')
# print(val)

# ############################## 列表操作 ################################
conn.flushall()
# 先进先出(scrapy-redis调度器:queue)
# conn.lpush('n1','yuchao')
# conn.lpush('n1','hanhong')
# data = conn.rpop('n1')
# print(data)


# 后进先出
# conn.lpush('n1','yuchao')
# conn.lpush('n1','hanhong')
# data = conn.lpop('n1')

# 阻塞
# data = conn.blpop('n1',timeout=3)
# print(data)


# 需求:redis列表中 n1=对应300w条数据
# 实现原理:每次取100个数据
#
# def list_scan_iter(name,count=100):
#     start = 0
#     while True:
#         chunk_list = conn.lrange(name,start,start+count)
#         if not chunk_list:
#             return
#         start += count
#         for ele in chunk_list: # 100
#             yield ele
#
# obj = list_scan_iter('n1',100)
# for i in obj:
#     print(i)

# ############################## 字典操作 ################################
# conn.hset()

# ############################## 集合操作 ################################
# 在scrapy-redis中去重规则中使用。


# ############################## 有序操作 ################################
conn.zadd('zzzzzzz', 'n1', 1, 'n2', 2)
# conn.zadd('zzzzzzz', n1=11, n2=22)
# scrapy-redis中使用:优先级队列中使用。

"""
View Code

 

38. 如何基于redis实现消息队列?

基于redis实现消息队列
Redis提供了两种方式来作消息队列:
    一个是使用生产者消费模式模式,另外一个方法就是发布订阅者模式。

方式一:生产者消费者模式

"""
import time
import redis


pool=redis.ConnectionPool(host='localhost', port=6379,db=1,decode_responses=True)
r=redis.Redis(connection_pool=pool)


def product(i):


    length=r.llen("goods2")
    print(length)
    if length>5000:
        print("长度过大睡一会")
        time.sleep(1)
        product(i)
    else:
        #生产者
        r.lpush("goods2", "good1"+str(i))
        print("加入一个值睡一会")
         # time.sleep(5)



if __name__ == '__main__':
    # 此处表示循环10000次,往redis里面放10000次数据
    for i in range(10000):
        product(i)
        
"""

 

 

原生/基于queue队列的  生产者消费者模式:

"""
原生/基于queue队列的  生产者消费者模式:
import random
import time
from Queue import Queue
from threading import Thread
 
queue = Queue(10)
 
class Producer(Thread):
    def run(self):
        while True:
            elem = random.randrange(9)
            queue.put(elem)
            print "厨师 {} 做了 {} 饭 --- 还剩 {} 饭没卖完".format(self.name, elem, queue.qsize())
            time.sleep(random.random())
 
class Consumer(Thread):
    def run(self):
        while True:
            elem = queue.get()
            print "吃货{} 吃了 {} 饭 --- 还有 {} 饭可以吃".format(self.name, elem, queue.qsize())
            time.sleep(random.random())
 
def main():
    for i in range(3):
        p = Producer()
        p.start()
    for i in range(2):
        c = Consumer()
        c.start()
 
if __name__ == '__main__':
    main()
"""

 

 

 

方式二:发布订阅模式:

"""
# 通过发布订阅模式的PUB、SUB实现消息队列
# 发布者发布消息到频道了,频道就是一个消息队列。
# 发布者:
import redis
conn = redis.Redis(host='127.0.0.1',port=6379)
conn.publish('104.9MH', "hahahahahaha")
# 订阅者:
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)
对了,redis 做消息队列不合适
业务上避免过度复用一个redis,用它做缓存、做计算,还做任务队列,压力太大,不
"""

 

消费者生产者模式和发布订阅模式两者的区别:

  前者会让一个或者多个客户端监听消息队列,一旦消息到达,消费者马上消费,谁先抢到算谁的,如果队列里没有消息,则消费者继续监听。
  后者也是一个或多个客户端订阅消息频道,只要发布者发布消息,所有订阅者都能收到消息,订阅者都是ping的。

39. 如何基于redis实现发布和订阅?以及发布订阅和消息队列的区别?

基于redis实现发布订阅:见上一题

区别:

  发布订阅:只要有消息,每个订阅者都能得到

  消息队列:谁抢到就算谁的

 

40. 什么是codis及作用?

"""
codis 及作用:
Codis:
    是豌豆荚公司开发的一个分布式 Redis 解决方案,用Go语言开发的。
    对于上层的应用来说,连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别 (不支持的命令列表),
    Codis 底层会处理请求的转发,进行不停机的数据迁移等工作。
    所有后边的一切事情,对于前面的客户端来说是透明的,可以简单的认为后边连接的是一个内存无限大的 Redis 服务。
组成:
    Codis Proxy (codis-proxy),处理客户端请求,支持Redis协议,因此客户端访问Codis Proxy跟访问原生Redis没有什么区别;
    Codis Dashboard (codis-config),Codis 的管理工具,支持添加/删除 Redis 节点、添加/删除 Proxy 节点,发起数据迁移等操作
    Codis Redis (codis-server)
    ZooKeeper/Etcd
作用:
    数据迁移
        迁移的过程对于上层业务来说是安全且透明的,数据不会丢失,上层不会中止服务。
    自动再平衡
        Codis 支持动态的根据实例内存,自动对slot进行迁移,以均衡数据分布
    高可用
"""

 

41. 什么是twemproxy及作用?

"""
什么是Twemproxy ?
是Twtter开源的一个 Redis 和 Memcache 代理服务器,主要用于管理 Redis 和 Memcached 集群,减少与Cache服务器直接连接的数量。
他的后端是多台REDIS 或memcached,所以也可以被称为分布式中间件。
特性:
    轻量级、快速
    保持长连接
    减少了直接与缓存服务器连接的连接数量
    使用 pipelining 处理请求和响应
    支持代理到多台服务器上
    同时支持多个服务器池
    自动分片数据到多个服务器上
    实现完整的 memcached 的 ASCII 和再分配协议
    通过 yaml 文件配置服务器池
    支持多个哈希模式,包括一致性哈希和分布
    能够配置删除故障节点
    可以通过端口监控状态
    支持 linux, *bsd,os x 和 solaris
功能:
    通过代理的方式减少缓存服务器的连接数。
    自动在多台缓存服务器间共享数据。
    通过不同的策略与散列函数支持一致性散列。
    通过配置的方式禁用失败的结点。
    运行在多个实例上,客户端可以连接到首个可用的代理服务器。 
    支持请求的流式与批处理,因而能够降低来回的消耗。
缺点:
    不支持针对多个值的操作,比如取sets的子交并补等。
    不支持Redis的事务操作。
    错误消息、日志信息匮乏,排查问题困难。

"""

参考博客:https://blog.csdn.net/u010601183/article/details/54426289

 

42. 写代码实现redis事务操作。

"""
严格意义来讲,redis的事务和我们理解的传统数据库(如mysql)的事务是不一样的。
redis中的事务定义:Redis中的事务(transaction)是一组命令的集合。 事务同命令一样都是Redis的最小执行单位,一个事务中的命令要么都执行,要么都不执行。 事务的原理是先将属于一个事务的命令发送给Redis,然后再让Redis依次执行这些命令。 Redis保证一个事务中的所有命令要么都执行,要么都不执行。
  如果在发送execute命令前客户端断线了,则Redis会清空事务队列,事务中的所有命令都不会执行。
  而一旦客户端发送了execute命令,所有的命令就都会被执行,即使此后客户端断线也没关系,因为Redis中已经记录了所有要执行的命令。 除此之外,Redis的事务还能保证一个事务内的命令依次执行而不被其他命令插入。
  试想客户端A需要执行几条命令,同时客户端B发送了一条命令,如果不使用事务,则客户端B的命令可能会插入到客户端A的几条命令中执行。
  如果不希望发生这种情况,也可以使用事务。
"""

 

实现代码:

"""
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', 'zgc')
pipe.set('role', 'haha')
pipe.lpush('roless', 'haha')
# 提交
pipe.execute()
'注意':咨询是否当前分布式redis是否支持事务
"""

 

43. redis中的watch的命令的作用?

"""
# 用于监视一个或多个key
# 如果在事务执行之前这些key被其他命令改动,那么事务将被打断

"""

 

44. 基于redis如何实现商城商品数量计数器?

"""
基于redis实现商城商品数量计数器:
# redis提供了基于incr命令来操作一个整数型数值的原子递增,
#     假设如果redis没有这个incr命令,我们该怎么实现这个incr的操作呢===》watch
# '通过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()
数据库的锁 

"""

multi和pipeline:

  pipeline 只是把多个redis指令一起发出去,redis并没有保证这些指定的执行是原子的;

  multi相当于一个redis的transaction的,保证整个操作的原子性,避免由于中途出错而导致最后产生的数据不一致。

  pipeline方式执行效率要比其他方式高10倍左右的速度,启用multi写入要比没有开启慢一点。

45. 简述redis分布式锁和redlock的实现机制。

"""
# 不是单机操作,而是又多了一/多台机器
# redis内部是单进程、单线程,是数据安全的(只有自己的线程在操作数据)
----------------------------------------------------------------
#A、B、C,三个实例(主)
1、来了一个'隔壁老王'要操作,且不想让别人操作,so,加锁;
    加锁:'隔壁老王'自己生成一个随机字符串,设置到A、B、C里(xxx=666)
2、来了一个'邻居老李'要操作A、B、C,一读发现里面有字符串,擦,被加锁了,不能操作了,等着吧~
3、'隔壁老王'解决完问题,不用锁了,把A、B、C里的key:'xxx'删掉;完成解锁
4、'邻居老李'现在可以访问,可以加锁了
# 问题:
1、如果'隔壁老王'加锁后突然挂了,就没人解锁,就死锁了,其他人干看着没法用咋办?
2、如果'隔壁老王'去给A、B、C加锁的过程中,刚加到A,'邻居老李'就去操作C了,加锁成功or失败?
3、如果'隔壁老王'去给A、B、C加锁时,C突然挂了,这次加锁是成功还是失败?
4、如果'隔壁老王'去给A、B、C加锁时,超时时间为5秒,加一个锁耗时3秒,此次加锁能成功吗?
# 解决
1、安全起见,让'隔壁老王'加锁时设置超时时间,超时的话就会自动解锁(删除key:'xxx')
2、加锁程度达到(1/2)+1个就表示加锁成功,即使没有给全部实例加锁;
3、加锁程度达到(1/2)+1个就表示加锁成功,即使没有给全部实例加锁;
4、不能成功,锁还没加完就过期,没有意义了,应该合理设置过期时间
# 注意
    使用需要安装redlock-py
----------------------------------------------------------------
from redlock import Redlock
dlm = Redlock(
    [
        {"host": "localhost", "port": 6379, "db": 0},
        {"host": "localhost", "port": 6379, "db": 0},
        {"host": "localhost", "port": 6379, "db": 0},
    ]
)
# 加锁,acquire
my_lock = dlm.lock("my_resource_name",10000)
if  my_lock:
    # 进行操作
    # 解锁,release
    dlm.unlock(my_lock)
else:
    print('获取锁失败')
#通过sever.eval(self.unlock_script)执行一个lua脚本,用来删除加锁时的key
"""

 

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

"""
一致性哈希,Python中的对应模块
一致性哈希:一致性哈希可以有效地解决分布式存储结构下动态增加和删除节点所带来的问题
    目的:通过尽量少引起迁移的方式,解决增减服务器导致的数据散列问题,从而解决了分布式环境下负载均衡问题;
    如果存在热点数据,可以通过增添节点的方式,对热点区间进行划分,将压力分配至其他服务器,重新达到负载均衡的状态。
# 模块:hash_ring
"""

 

47. 如何高效的找到redis中所有以oldboy开头的key?

"""
如何高效的找到redis中所有的以oldboy开头的key?
1.keys pattern 命令–>获取key值 
在redis里,允许模糊查询key
有3个通配符 *, ? ,[] 
*: 通配任意多个字符 
?: 通配单个字符 
[]: 通配括号内的某1个字符

2.randomkey–>随机获取key值
    127.0.0.1:6379> randomkey"name

3.type keyname–>获取某个key中的存储的类型
    127.0.0.1:6379> type agestrin

4.exists keyname–>判断某个key是否存在
    127.0.0.1:6379> exists age

5.del keyname–>删除某个key值
    127.0.0.1:6379> del age
    (integer) 1

6.rename keyname newkeyname –>为key取新的名字
    127.0.0.1:6379> rename age usernameOK
"""

 

48.悲观锁和乐观锁的区别?

"""
# 悲观锁
    从数据开始更改时就将数据锁住,直到更改完成才释放;
    会造成访问数据库时间较长,并发性不好,特别是长事务。
# 乐观锁
    直到修改完成,准备提交修改到数据库时才会锁住数据,完成更改后释放;
    相对悲观锁,在现实中使用较多。
"""

 

第四部分 前端、框架和其他(155题)

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

"""
http协议:
超文本传输协议,是一种用于浏览器端和服务器端的互联网通信协议。
    无状态,短连接
    包含:请求首行,请求头,请求体
            相应首行,相应头,相应体
"""

 

 

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

"""
websocket原理:
    1.websocket是一个协议
    2.解决了一个问题:
        服务器端可以主动向客户端推送消息
    3.轮询和长轮询
    4.持久连接不断开==》通信机制:全双工通道
    5.内部使用的也是tcp/ip协议,在此基础上,需要先验证通讯双方是否支持websocket协议==》加密验证,之后收发信息。
        信息的收发也是需要加密和解密的
        
        信息的验证加密:先进行sha1加密,然后base64加密
            base64(sha1(key + magic string))
        收发数据加密:分为三个部分:描述信息+ masking key + 真正发送的数据
            <=125    masking-coke = 2位
            ==126    masking-code = 4位
            ==127    masking-code = 8位
# 注释:magic string==》“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”
"""

 

 

 

3. 什么是magic string ?

  magic string==》“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”

"""
使用websocket协议时:
# 客户端向服务端发送消息时,会有一个'sec-websocket-key'和'magic string'的随机字符串(魔法字符串) # 服务端接收到消息后会把他们连接成一个新的key串,进行编码、加密,确保信息的安全性 """

 

 

 

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

# a.可以通过引用Bootstrap实现
# b.通过看Bootstrap源码文件,可知其本质就是通过CSS实现的
 <style>
        /*浏览器窗口宽度大于768,背景色变为 green*/
        @media (min-width: 768px) {
            .pg-header{
                background-color: green;
            }
        }

        /*浏览器窗口宽度大于992,背景色变为 pink*/
        @media (min-width: 992px) {
            .pg-header{
                background-color: pink;
            }
        }
    </style>
</head>
<body>
<div class="pg-header"></div>
</body>

 

 

 

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

Jquery、Vue、Bootstrap,HBuilder、

 

 

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

ajax:异步、局部更新

 

 

7. 如何在前端实现轮训?

"""
# 轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP request,
# 然后由服务器返回最新的数据给客户端的浏览器。
var xhr = new XMLHttpRequest();
    setInterval(function(){
        xhr.open('GET','/user');
        xhr.onreadystatechange = function(){

        };
        xhr.send();
    },1000)

"""

 

 

 

8. 如何在前端实现长轮训?

"""
# ajax实现:在发送ajax后,服务器端会阻塞请求直到有数据传递或超时才返回。 
# 客户端JavaScript响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。
    function ajax(){
        var xhr = new XMLHttpRequest();
        xhr.open('GET','/user');
        xhr.onreadystatechange = function(){
              ajax();
        };
        xhr.send();
    }

"""

 

 

 

9. vuex的作用?

 

"""
什么是vuex及作用?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
    它采用集中式存储 管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化
作用:
    1.不同组件之间共享状态,可以进行状态的修改和读取。
    2.可以理解为是一个全局对象,所有页面都可以访问
    3.还有比较重要的单一状态树管理,让数据的修改脉络更加清晰,便于定位问题。
    # 比如用户做了一些加减的操作、三个页面都要用、可以用传参、但是很麻烦、这种时候用vuex就简单一些
"""

 

 

10. vue中的路由的拦截器的作用?

"""
vue中的路由的拦截器的作用
# 当统一处理所有http请求和响应时,可以用axios的拦截器。
# 可以用来做登录拦截验证:通过配置http response inteceptor,当后端接口返回401 Unauthorized(未授权),让用户重新登录。

"""

 

 

11. axios的作用?

"""
axios及作用
使用:
方法一:改写原型链:
import axios from 'axios'
# 这时候如果在其它的组件中,是无法使用 axios 命令的。但如果将 axios 改写为 Vue 的原型属性,就能解决这个问题

Vue.prototype.$ajax = axios
# 在 main.js 中添加了这两行代码之后,就能直接在组件的 methods 中使用 $ajax 命令

methods: {
  submitForm () {
    this.$ajax({
      method: 'post',
      url: '/user',
      data: {
        name: 'wise',
        info: 'wrong'
      }
   })
}
方案二:在 Vuex 中封装
# Vuex 的仓库是 store.js,将 axios 引入,并在 action 添加新的方法
// store.js
import Vue from 'Vue'
import Vuex from 'vuex'

// 引入 axios
import axios from 'axios'

Vue.use(Vuex)

const store = new Vuex.Store({
  // 定义状态
  state: {
    test01: {
      name: 'Wise Wrong'
    },
    test02: {
      tell: '12312345678'
    }
  },
  actions: {
    // 封装一个 ajax 方法
    saveForm (context) {
      axios({
        method: 'post',
        url: '/use
        
注意:即使已经在 main.js 中引入了 axios,并改写了原型链,也无法在 store.js 中直接使用 $ajax 命令

换言之,这两种方案是相互独立的

 

在组件中发送请求的时候,需要使用 this.$store.dispatch 来分发

methods: {
  submitForm () {
    this.$store.dispatch('saveForm')
  }
}
submitForm 是绑定在组件上的一个方法,将触发 saveForm,从而通过 axios 向服务器发送请求


# axios是vue-resource后出现的Vue请求数据的插件
# 可以做的事情:
    从浏览器中创建 XMLHttpRequest
    从 node.js 发出 http 请求
    支持 Promise API
    拦截请求和响应
    转换请求和响应数据
    取消请求
    自动转换JSON数据
    客户端支持防止 CSRF/XSRF

"""

 

 

 

12. 列举vue的常见指令。

"""
vue的常见指令
v-html
v-on
v-bind
v-for
v-if~~v-else
is,$emit,
router-link和router-view

"""

 

 

13. 简述jsonp及实现原理?

 

"""
jsonp及实现原理:
jsonp的产生(了解):
    1、一个众所周知的问题,Ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面、动态网页、web服务、WCF,只要是跨域请求,一律不准。
    
    2、不过我们又发现,Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有”src”这个属性的标签都拥有跨域的能力,比如<\script>、<\img>、<\iframe>)。
    
    3、于是可以判断,当前阶段如果想通过纯web端(ActiveX控件、服务端代理、属于未来的HTML5之Websocket等方式不算)跨域访问数据就只有一种可能,那就是在远程服务器上设法把数据装进js格式的文件里,供客户端调用和进一步处理。
    
    4、恰巧我们已经知道有一种叫做JSON的纯字符数据格式可以简洁的描述复杂数据,更妙的是JSON还被js原生支持,所以在客户端几乎可以随心所欲的处理这种格式的数据。
    
    5、这样子解决方案就呼之欲出了,web客户端通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件(一般以JSON为后缀),显而易见,服务器之所以要动态生成JSON文件,目的就在于把客户端需要的数据装入进去。
    
    6、客户端在对JSON文件调用成功之后,也就获得了自己所需的数据,剩下的就是按照自己需求进行处理和展现了,这种获取远程数据的方式看起来非常像AJAX,但其实并不一样。
    
    
jsonp是什么:为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,
    该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
# 原理:
  1、客户端注册一个callback, 然后把callback的名字传给服务器。 
  2、此时,服务器先生成 json 数据。 
  3、然后以 javascript 语法的方式,生成一个function , function 名字就是传递上来的参数 jsonp. 
  4、最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。

  客户端浏览器,解析script标签,并执行返回的 javascript 文档,此时数据作为参数,
  传入到了客户端预先定义好的 callback 函数里.(动态执行回调函数) 

# 注意
    # JSON 是一种数据格式
    # JSONP 是一种数据调用的方式
"""

 

 

14. 是什么cors ?

 

"""
CORS:跨域资源共享(Cross-Origin Resource Sharing)
    因为浏览器的同源策略,在你请求返回的时候会进行拦截
    其本质是设置响应头,使得浏览器允许跨域请求。

# 简单请求(一次请求):设置响应头
    1、请求方式:HEAD、GET、POST
    2、请求头信息:
        Accept
        Accept-Language
        Content-Language
        Last-Event-ID
        Content-Type 对应的值是以下三个中的任意一个
                                application/x-www-form-urlencoded
                                multipart/form-data
                                text/plain
                                
        设置响应头:response['Access-Control-Allow-Origin'] = 'http://localhost:8080'
复杂请求(两次请求)
复杂请求会在发送真正的请求之前,会先发送一个'options'请求,做'预检',预检成功后才发送真正的请求
    # 预检:
    如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过
        Access-Control-Request-Method = "PUT,DELETE"
    如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过
        Access-Control-Request-Headers = "Content-Type,xxxxx"
    或者在settings里面设置允许跨域的方法和请求头:
    response["Access-Control-Allow-Methods"] = settings.CORS_METHODS
    response["Access-Control-Allow-Headers"] = settings.CORS_HEADERS
        settings的设置:
            CORS_METHODS = "PUT,DELETE"
            CORS_HEADERS = "xxxxx,xxxxfsdf"
            
代码实现:
注:因为跨域是整个项目都会出现的问题,所以想要解决这个问题,需要重写中间件
class CorsMiddleware(MiddlewareMixin):

    def process_response(self,request,response):
        response['Access-Control-Allow-Origin'] = 'http://localhost:8080'
        if request.method == "OPTIONS":
            response["Access-Control-Allow-Methods"] = "PUT,DELETE"
            response["Access-Control-Allow-Headers"] = "Content-Type,xxxxx"
            # response["Access-Control-Allow-Methods"] = settings.CORS_METHODS
            # response["Access-Control-Allow-Headers"] = settings.CORS_HEADERS
        return response

"""

 

 

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

"""
CORS:跨域资源共享(Cross-Origin Resource Sharing)
    因为浏览器的同源策略,在你请求返回的时候会进行拦截
    其本质是设置响应头,使得浏览器允许跨域请求。

# 简单请求(一次请求):设置响应头
    1、请求方式:HEAD、GET、POST
    2、请求头信息:
        Accept
        Accept-Language
        Content-Language
        Last-Event-ID
        Content-Type 对应的值是以下三个中的任意一个
                                application/x-www-form-urlencoded
                                multipart/form-data
                                text/plain
                                
        设置响应头:response['Access-Control-Allow-Origin'] = 'http://localhost:8080'
复杂请求(两次请求)
复杂请求会在发送真正的请求之前,会先发送一个'options'请求,做'预检',预检成功后才发送真正的请求
    # 预检:
    如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过
        Access-Control-Request-Method = "PUT,DELETE"
    如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过
        Access-Control-Request-Headers = "Content-Type,xxxxx"
    或者在settings里面设置允许跨域的方法和请求头:
    response["Access-Control-Allow-Methods"] = settings.CORS_METHODS
    response["Access-Control-Allow-Headers"] = settings.CORS_HEADERS
        settings的设置:
            CORS_METHODS = "PUT,DELETE"
            CORS_HEADERS = "xxxxx,xxxxfsdf"
            
代码实现:
注:因为跨域是整个项目都会出现的问题,所以想要解决这个问题,需要重写中间件
class CorsMiddleware(MiddlewareMixin):

    def process_response(self,request,response):
        response['Access-Control-Allow-Origin'] = 'http://localhost:8080'
        if request.method == "OPTIONS":
            response["Access-Control-Allow-Methods"] = "PUT,DELETE"
            response["Access-Control-Allow-Headers"] = "Content-Type,xxxxx"
            # response["Access-Control-Allow-Methods"] = settings.CORS_METHODS
            # response["Access-Control-Allow-Headers"] = settings.CORS_HEADERS
        return response

"""

 

 

16. 列举Http请求中的状态码?

 

"""
列举http请求的状态码
# 2开头(成功)
    200    :成功状态码
    202:已经接受,但尚未处理
    204:请求成功,且不需要返回内容
# 3开头(重定向错误)    
    301 永久性重定向错误。
    302 临时性重定向错误。
    304:未修改状态
# 4开头(客户端错误)   
    400:请求的语义或是参数有错
    403 :Forbidden服务器拒绝了请求(csrf)
    404 :Not Found找不到页面(资源)
# 5开头(服务器错误)   
    500    :服务器遇到错误,无法完成请求
    502:网关错误,一般是服务器压力过大导致连接超时       
    503:服务器宕机
"""

 

 

17. 列举Http请求中常见的请求头?

"""
17、列举Http请求中常见的请求头?

# 常见请求头:
User-Agent、Referer、Host、Cookie、Connection、Accept
"""

 

 

18. 看图写结果:

李杰

 

 

看图写结果:

武佩奇

 

 

 

看图写结果:

老男孩

 

 

 

看图写结果:

undefined

 

 

 

看图写结果:

武佩奇

 

 

 

看图写结果:

武佩奇

 

 

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

"""
django、flask、tornado框架的比较?
flask框架和Django框架的区别:
    flask:
        1.优势与缺点
            优势:轻量级框架,短小精简,扩展性强,可以进行快速搭建,第三方组件
            缺点/应用场景:适用于中小型网站的搭建。
        2.特点:轻便快捷,本身没有库,依赖于第三方插件
    Django:内部组件特别多,自身功能强大,大而全。
    相同点:因为它们两个框架都没有写sockte,都是基于wsgi协议做的,在此之外,flask框架中的上下文管理较为耀眼。
    
flask上下文管理:
  简单来说,flask上下文管理可以分为三个阶段:
    1、请求进来时,调用对象的__call__方法,并将请求相关的数据放入上下文管理中
    2、在视图函数中,要去上下文管理中取值
    3、请求响应,要将上下文管理中的数据清除
  
  详细点来说:
        1、请求刚进来,将request,session封装在RequestContext类中,app对象,g封装在AppContext类中,并通过LocalStack将requestcontext和appcontext放入Local类中
        2、视图函数中,通过localproxy--->偏函数--->localstack--->local取值
        3、请求相应时,先执行save.session()再各自执行pop(),将local中的数据清除

tornado框架;异步非阻塞框架
    特点:自带socket,可以不用wsgi
            原生支持websocket协议
    支持:路由、视图、模板渲染,cookie    
    不支持:组件支持的少,不支持session,ORM,form,admin
    行业现状:
        瞎用:完全没有用到tornado的异步非阻塞的特点
        真用:生成器+装饰器+Future对象

"""

 

20. 什么是wsgi?

"""
wsgi及相关概念:
wsgi:web服务网关接口Web Server Gateway Interface
    wsgi不是服务器,只是一种规范,描述web server如何与web application通信的规范
    要实现wsgi协议,必须同时实现web server和web application,
        当前运行在WSGI协议之上的web框架有Torando,Flask,Django
uwsgi:与wsgi一样是一种通信协议,是uWSGI服务器的独占协议,用于定义传输信息的类型(type of information),
  每一个uwsgi packet前4byte为传输信息类型的描述,与WSGI协议是两种东西,据说该协议是fcgi协议的10倍快 uWSGI:是一个web服务器,实现了wsgi协议、uwsgi协议、http协议等。 wsgi协议主要包括server和application两部分: wsgi server负责从客户端接收请求,将request转发给application,将application返回的response返回给客户端; wsgi application接收由server转发的request,处理请求,并将处理结果返回给server。application中可以包括多个栈式的中间件(middlewares),
    这些中间件需要同时实现server与application,因此可以在WSGI服务器与WSGI应用之间起调节作用:对服务器来说,中间件扮演应用程序,对应用程序来说,中间件扮演服务器。
"""

 

21. django请求的生命周期?

"""
django请求的生命周期
浏览器端发出请求--》wsgiref解析socket--》中间件验证--》urls路由分配--》view视图函数--》
                            template模板或数据库进行ORM操作--》服务器拿到数据封装wsgiref--》原路返回给浏览器
"""

 

22. 列举django的内置组件?

"""
django的内置组件
session和cookies,ORM,form,admin,serializer、路由、视图、模板渲染
"""

 

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

"""
django中间件的5个方法
process_request:
    1. 是在视图执行前执行的
    2. 它的顺序是从上往下
    3. 返回值是None,继续往后执行
    4. 返回值是HttpResponse的对象,执行对应中间件的process_response方法
    ,接着往上,返回给浏览器

    
process_response:
    1. 是在视图执行后执行的
    2. 它的顺序是从下往上
    3. 返回必须是HttpResponse的对象,继续往上执行
    
process_view:
    1. 是在视图执行前执行的,process_request之后
    2. 它的顺序是从上往下
    3. 返回值是None,继续往后执行
    4. 返回值是HttpResponse的对象,执行最后一个中间件的process_response方法,接着往上,返回给浏览器,视图不走了
    
process_exception:
    1. 报错了才执行
    2. 在视图函数之后,process_response之前
    3. 它的顺序是从下往上
    4. 返回值是HttpResponse的对象,执行最后一个中间件的process_response方法
    ,接着往上,返回给浏览器


process_template_response:
    1. 视图返回的对象有render方法 才执行
    2. 在视图函数之后,process_response之前
    3. 它的顺序是从下往上
    4. 返回值是HttpResponse的对象。
    5. 执行完所有的中间件的process_template_response之后,
    才执行对象.render()得到一个新的HttpResponse的对象,执行往交给process_response继续
"""

 

24. 简述什么是FBV和CBV?

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

request对象是由wsgiref封装的,所以是在请求进入Django之初就创建的

26. 如何给CBV的程序添加装饰器?

27. 列举django orm 中所有的方法(QuerySet对象的所有方法)

"""

列举django orm 中所有的方法(QuerySet对象的所有方法)
一、普通操作
all()
    models.Book.objects.all()  # 获取到所有的书籍对象,结果是对象列表
    
get()
    models.Book.objects.get(条件)  # 获取符合条件的对象
    
filter()
    models.Book.objects.filter(条件)  # 筛选所有符合条件的,结果是对象列表 
    
exclude()
    models.Book.objects.exclude(条件)  # 筛选出所有不符合条件的,结果是对象列表
    
values()
    models.Book.objects.all().values( )  # 字典列表,[ {id:1,name:20} , {id:2,name:18} ]
    values(‘id’)括号内不指定时显示全部,如指定则只显示指定的,[ {id:1} , {id:2,} ]
    
values_list()
    models.Book.objects.all().values_list( )  # 元组列表,[ (1,20) , (2,18) ]同上,指定时显示指定内容
    
order_by()  # 备注:使用order_by排序时,在字段名前加"-"表示倒序,等同于reverse
    models.Book.objects.all().order_by(‘id’)  # 按照id升序就行排列
    models.Book.objects.all().order_by(‘-id’)  # 按照id降序就行排列
    models.Book.objects.all().order_by(‘age’ , ‘-id’)  # 先按age升序,age相同的按id进行降序排列
    
reverse()   
    models.Book.objects.all().order_by(‘id’).reverse()  # 对结果反转; 注意reverse前必须排序,
    否则reverse无效; 或在model.py文件中Book类中的Meta中指定ordering=(‘id’ , )注意逗号必须有
    
distinct()
    distinct():  # 去重,当获取到的结果Queryset列表中同一对象出现多次时去重,只留一个
    
count()
    models.Book.objects.all().count()  # 计数,可统计结果个数,如对Queryset内元素数进行统计.
    
first()
    models.Book.objects.all().first()  # 获取结果中的第一条,即使前面结果列表为空,也不会报错
    
last()
    models.Book.objects.filter().last()  # 获取结果中的最后一条
    
exists()
    models.Book.objects.filter().exists()  # 判断Queryset列表是否有东西,结果为True或False;
    
create()    增
    models.Book.objects.create(name='浙江出版社',addr="浙江.杭州")
delete()    删
update()    改
aggregate() 聚合函数  # # 聚合函数,获取字典类型聚合结果   
      result = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid'))
    # ===> {'k': 3, 'n': 4}
    
anotate()   分组函数  # # 用于实现聚合group by查询
    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))
    
update_or_create()    更新或增加:有则更新无则增加
    models.Book.objects.update_or_create(name='浙江出版社',addr="浙江.杭州")
    
create_or_deleter()   增加或删除:有则删除无则增加

二、进阶操作
1. extra():在QuerySet的基础上继续执行子语句
    参数:extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
        select和select_params是一组,where和params是一组,tables用来设置from哪个表
        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'])
        
2.defer和only
    defer():映射中排除某列数据
    only():仅取某个表中的数据
    defer()和only()查询方法的使用,defer()方法提供了延迟加载,也就是利用这个方法我们可以把不展示的字段添加进去。
    only()方法正好相反,提供我们要展示的字段信息。利用这两个方法可以很好的优化响应,提高查询的性能。
"""

 

 

 

 

28. only和defer的区别?

略,见上一题答案

29. select_related和prefetch_related的区别?

 

"""
select_related和prefetch_related的区别?
select_related:对于一对一字段(OneToOneField)和外键字段(ForeignKey),可以使用select_related 来对QuerySet进行优化
prefetch_related:对于多对多字段(ManyToManyField)和一对多字段,可以使用prefetch_related()来进行优化。
    prefetch使用的是 IN 语句实现的。这样,在QuerySet中的对象数量过多的时候,根据数据库特性的不同有可能造成性能问题。
    值得一提的是,链式prefetch_related操作会将这些查询添加起来

优势:使用 select_related() 和 prefetch_related() 可以很好的减少数据库请求的次数,从而提高性能。
select_related():   # 针对一对一的外键操作
    A.不带select_related()
    book = Book.objects.filter(pk=1).first  # 需要查询数据库 1
    # 结果
    n = book.name  # 需要查询数据库 2
    a = book.age  # 需要查询数据库 3
    # 总共向数据库发起三次查询。
    
    B. 带select_related
    book = Book.objects.select_related().filter(pk=1)  # 需要查询数据库 1
    n = book.name  # 直接从book对象中取
    a = book.age  # 直接从book对象中取
    # 总共向数据库发起一次查询。3
    
    
prefetch_related():  # 针对一对多和多对多的外键操作
    zhangs = Person.objects.prefetch_related('visitation__province').filter(firstname__iexact=u'张')
    for i in zhangs:
        for city in i.visitation.all():
            print(city.province)
    
   
"""

 

30. filter和exclude的区别?

31. 列举django orm中三种能写sql语句的方法。

pymysql模块使用游标执行sql语句;

extra()方法;

raw()方法;

 

32. django orm 中如何设置读写分离?

参见我的博客:点这里

33. F和Q的作用?

  F : 对数据本身的值进行比较和判断

  Q : 构造复杂的查询条件

34. values和values_list的区别?

略,见27题

35. 如何使用django orm批量创建数据?

使用bulk_create()方法

36. django的Form和ModeForm的作用?

Form : 构建form组件字符串,以及表单数据验证

ModeForm : 根据模型类来生成Form

37. django的Form组件中,如果字段中包含choices参数,请使用两种方式实现数据源实时更新。

"""
django的Form组件中,如果字段中包含choices参数,请使用两种方式实现数据源实时更新。
1.重写构造方法
from django.forms import Form
from django.forms import fields
class UserForm(Form):
    name = fields.CharField(label='用户名',max_length=32)
    email = fields.EmailField(label='邮箱')
    ut_id = fields.ChoiceField(
        choices=[]      # choices里面的参数格式是元祖
        # 例如,choices=[(1,'二笔用户'),(2,'闷骚')]
    )
  
    def __init__(self,*args,**kwargs):
        super(UserForm,self).__init__(*args,**kwargs)
  
        self.fields['ut_id'].choices = models.UserType.objects.all().values_list('id','title')
        
2.使用ModelChoiceField字段,但是渲染得结果要依赖于model的__str__方法的返回值
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()):
"""

 

38. django的Model中的ForeignKey字段中的on_delete参数有什么作用?

"""
django的Model中的ForeignKey字段中的on_delete参数有什么作用?
    设置外键删除时的参数:on_delete = model.参数     # 删除的时候指定的删除操作
        CASCADE:这就是默认的选项,级联删除,你无需显性指定它。
        PROTECT: 保护模式,如果采用该选项,删除的时候,会抛出ProtectedError错误。
        SET_NULL: 置空模式,删除的时候,外键字段被设置为空,前提就是blank=True, null=True,定义该字段的时候,允许为空。
        SET_DEFAULT: 置默认值,删除的时候,外键字段设置为默认值,所以定义外键的时候注意加上一个默认值。
        SET(): 自定义一个值,该值当然只能是对应的实体了

"""

 

39. django中csrf的实现机制?

"""
django中csrf的实现机制?
CSRF(Cross-site request forgery), 中文名称:跨站请求伪造,CSRF(Cross-site request forgery), 中文名称:跨站请求伪造.

服务端生成一个随机字符串   返回时放到form表单的一个隐藏input标签中,或者放到cookie中,

以后每次访问时都要带上这个随机字符串  才能正常访问。
"""

 

39. django如何实现websocket?

基于Python socket实现的WebSocket服务端或者channel插件   都需要前后端配合

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

  放到请求体data中

  请求头中

41. django中如何实现orm表中添加数据时创建一条日志记录。

42. django缓存如何设置?

"""
Django如何设置缓存?
# 全站缓存
MIDDLEWARE_CLASSES = (
    ‘django.middleware.cache.UpdateCacheMiddleware’, #第一
    'django.middleware.common.CommonMiddleware',
    ‘django.middleware.cache.FetchFromCacheMiddleware’, #最后
)
 
# 视图缓存
from django.views.decorators.cache import cache_page
import time
  
@cache_page(15)          #超时时间为15秒
def index(request):
 t=time.time()      #获取当前时间
 return render(request,"index.html",locals())
 
# 模板缓存
{% load cache %}
 <h3 style="color: green">不缓存:-----{{ t }}</h3>
  
{% cache 2 'name' %} # 存的key
 <h3>缓存:-----:{{ t }}</h3>
{% endcache %}
"""

 

43. django的缓存能使用redis吗?如果可以的话,如何配置?

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

  当url太长书写困难时,可以给每个url起别名name='别名'    

  用于反向解析url字符串    使书写变得简单

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

  filter : 类似管道,只能接受两个参数第一个参数是“|”前的数据

  simple_tag : 类似函数

46. django-debug-toolbar的作用?

它是一个功能强大的调试工具,

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

  例如:响应时间、sql语句执行时间等。

 

47. django中如何实现单元测试?
不会!

48. 解释orm中 db first 和 code first的含义?

DB First :数据库优先,数据库里优先创建数据库表结构,根据表结构生成类,再根据类操作数据库
Code First :代码优先,先写代码,执行代码时才创建数据库表结构

 

49. django中如何根据数据库表生成model中的类?

"""
Django中根据数据库生成model中的类?
    1. 根据model生成数据库表: 
    python manage.py syncdb 
    2. 根据数据库表生成model: 
    创建一个项目,修改seting文件,在setting里面设置你要连接的数据库类型和连接名称,地址之类,和创建新项目的时候一致 
    运行下面代码可以自动生成models模型文件 
        python manage.py inspectdb  # 注释:该命令在PyDev上运行失败,只能在命令行执行。
        这样就可以在命令行看到数据库的模型文件了
    把模型文件导入到app中 
    创建一个app 
    django-admin.py startapp app 
    python manage.py inspectdb > app/models.py 
    ok模型文件已经生成好了。下面的工作就和之前一样了
"""

 

50. 使用orm和原生sql的优缺点?

"""
使用orm和原生sql的优缺点?
ORM:Object Relational Mapping(对象关系映射)
类名对应------》数据库中的表名
类属性对应---------》数据库里的字段
类实例对应---------》数据库表里的一行数据
obj.id obj.name.....类实例对象的属性
可以通过类和对象来操作数据库, 本质上是对类和对象的操作转换成sql语句并执行
ORM:
    优点:书写比较方便简单 开发效率比较高 
    缺点:执行效率比较低
原生sql:
    缺点:书写就比较复杂,且开发效率比较低 
    优点:但是执行效率比较高(两个差距不是太大)
如果想要提高开发效率推荐使用ORM或者访问数量比较少的话 ORM更好一些

"""

 

51. 简述MVC和MTV

"""
简述MVC和MTV
MVC是众所周知的模式,即:将应用程序分解成三个组成部分:model(模型),view(视图),和 controller(控制器)。其中:
             M 管理应用程序的状态(通常存储到数据库中),并约束改变状态的行为(或者叫做“业务规则”)。
             C 接受外部用户的操作,根据操作访问模型获取数据,并调用“视图”显示这些数据。控制器是将“模型”和“视图”隔离,并成为二者之间的联系纽带。
             V 负责把数据格式化后呈现给用户。

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

 

52. django的contenttype组件的作用?

"""
ContentType 
    1. http请求头
        现象:reqeust.POST中未获取到数据。
                a. 老板数据没法来
                b. 自己
                    request.POST
                    requset.boy 
        Content-Type请求头的作用?
            用于标记请求体数据的格式,如:
                1. Content-Type:application/x-www-form-urlencoded
                    请求体:b'pwd=123&user=root'
                    
                2. Content-Type:application/json
                    请求体:{"pwd": 123, "user": "root"}
    2. django中的组件
        1. django contenttypes组件的作用?
            - 数据库迁移时,找到所有app中的表并录入到django_content_type表
            - 内置两个字段:
                先导入:
                from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
                from django.contrib.contenttypes.models import ContentType
                GenericRelation     # 用于GenericForeignKey的反向关联查询
                GenericForeignKey   
                               
                GenericForeignKey:
                    content_type = models.ForeignKey(ContentType, blank=True, null=True)
                    object_id = models.PositiveIntegerField("绑定课程", blank=True, null=True, help_text="可以把优惠券跟课程绑定")
                    content_object = GenericForeignKey('content_type', 'object_id')
                GenericRelation:    
                    coupon = GenericRelation("Coupon")
                
        2. 使用contenttypes组件
            表结构:
                from django.db import models
                from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
                from django.contrib.contenttypes.models import ContentType
                # Create your models here.
    
                class Course(models.Model):
                
                    name = models.CharField(max_length=32)
    
                    # 不影响数据库的列,用于帮助开发者查询数据
                    price_policy_list = GenericRelation("PricePolicy")  # 用于GenericForeignKey反向查询
    
                class DegreeCourse(models.Model):
                   
                    name = models.CharField(max_length=32)
    
    
                class PricePolicy(models.Model):
                  
                    price = models.FloatField(verbose_name='价格')
                    period = models.IntegerField(verbose_name='周期')
    
                    content_type = models.ForeignKey(ContentType,on_delete=models.CASCADE)  # 关联course or degree_course
                    object_id = models.PositiveIntegerField()
    
                    # 不影响数据库的列,用于帮助开发者增加或查询数据
                    content_object = GenericForeignKey('content_type', 'object_id')
    
                    def __str__(self):
                        return str(self.price)

"""

 

53. 谈谈你对restfull 规范的认识?

  1. 使用HTTPS代替HTTP
  2. 在url中体现自己的url是api
  3. 在url中体现 版本:V1,V2,。
  4. 名词==》面向资源编程
  5. 行为
  6. 条件
  7. 状态码
  8. 错误信息
  9. 返回结果
  10. HyperLink

54. 接口的幂等性是什么意思?

 

55. 什么是RPC?

RPC是指远程过程调用,也就是说两台服务器A,B,一个应用部署在A服务器上,

想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。

维护两个队列   分别放请求消息和返回消息

 

56. Http和Https的区别?

 

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

django rest framework框架的作用?
        帮助开发者可以快速开发出遵循restful规范的API 

在编写接口时可以不适用django rest framework框架,
rest framework帮助开发者提供了很多组件,可以提高开发效率
如果不使用:也可以做,那么就可以django的CBV来实现,开发者编写的代码会更多一些。
如果 使用:内部帮助我们提供了很多方便的组件,我们通过配置就可以完成相应操作,如:
  序列化,可以做用户请求数据校验+queryset对象的序列化称为json
  解析器,获取用户请求数据request.data,会自动根据content-type请求头的不能对数据进行解析
  分页,将从数据库获取到的数据在页面进行分页显示。
  还有其他:
    认证
    权限
    访问频率控制

58. 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 中传参         /v1/                     from rest_framework.versioning import URLPathVersioning  需要在路由中用正则匹配取版本值

    GET请求的传参  version = v1    from rest_framework.versioning import BaseVersioning

    请求头
认证
  问题:认证流程?

 from rest_framework.authentication import BaseAuthentication
  自定义的认证类为了规范  要继承 BaseAuthentication

  方法中可以定义三种返回值:

    认证成功:
      返回元祖 (user,auth)      在类中用requests.user 和 request.auth 接收
      返回 None                      request.user为默认值AnonymousUser(匿名用户)  request.auth为None

    认证失败:

      跑出异常 
  流程:

    as_view()
        dispatch()
           再去request中进行认证处理

  配置: 可以根据源码进行配置  把认证类配置成全局配置    也可以配置匿名用户的名称和token值

权限

  用法和配置同认证方法相同。

  返回值: 
    - True, 有权访问
    - False,无权访问


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

 

访问频率的控制

  用法和配置同认证方法相同。


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

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

  控制流程:

    匿名用户,根据用户IP或代理IP作为标识进行记录,为每一个用户在redis中创建一个列表
    {
      throttle_1.1.1.1:[1526868876.497521,152686885.497521...]
      throttle_1.1.1.2:[1526868876.497521,152686885.497521...]
      throttle_1.1.1.3:[1526868876.497521,152686885.497521...]
      throttle_1.1.1.4:[1526868876.497521,152686885.497521...]
      throttle_1.1.1.5:[1526868876.497521,152686885.497521...]
    }

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

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

    }

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

    正常频率为:     1分钟:40次

视图

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

分页

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

渲染器

"""

 

59. django rest framework框架中的视图都可以继承哪些类?

参见我的博客

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

参见第58题

61. django rest framework如何实现的用户访问频率控制?

Route(路由)           
@app.route('/user/<username>', endpoint="别名")  endpoint 给路由起别名    用 url_for 反向生成url
templates(模板)
Models(orm模型)
blueprint(蓝图)
Jinja2模板引擎

 

62. Flask框架的优势?

63. Flask框架依赖组件?

64. Flask蓝图的作用?

"""
flask蓝图blueprint的作用:
当项目很大的时候,蓝图用于为应用提供目录划分,实现模块化的应用
作用:
    将不同的功能模块化
    构建大型应用
    优化项目结构
    增强可读性,易于维护(跟Django的view功能相似)
    项目解耦
"""

 

列举使用过的Flask第三方组件?

简述Flask上下文管理流程?

Flask中的g的作用?

Flask中上下文管理主要涉及到了那些相关的类?并描述类主要作用?

为什么要Flask把Local对象中的的值stack 维护成一个列表?

Flask中多app应用是怎么完成?

在Flask中实现WebSocket需要什么组件?

wtforms组件的作用?

Flask框架默认session处理机制?

解释Flask框架中的Local对象和threading.local对象的区别?

Flask中 blinker 是什么?

SQLAlchemy中的 session和scoped_session 的区别?

SQLAlchemy如何执行原生SQL?

ORM的实现原理?

DBUtils模块的作用?

以下SQLAlchemy的字段是否正确?如果不正确请更正:

1

2

3

4

5

6

7

8

9

10

11

fromdatetime importdatetime

fromsqlalchemy.ext.declarative

importdeclarative_base

fromsqlalchemy importColumn, Integer, String, DateTime





Base =declarative_base()



classUserInfo(Base):
   

    __tablename__ ='userinfo'
   

    id=Column(Integer, primary_key=True, autoincrement=True)


    name =Column(String(64), unique=True)


    ctime =Column(DateTime, default=datetime.now())

SQLAchemy中如何为表设置引擎和字符编码?

SQLAchemy中如何设置联合唯一索引?

简述Tornado框架的特点。

简述Tornado框架中Future对象的作用?

Tornado框架中如何编写WebSocket程序?

Tornado中静态文件是如何处理的?
如: <link href="{{static_url("commons.css")}}" rel="stylesheet" />

Tornado操作MySQL使用的模块?

Tornado操作redis使用的模块?

简述Tornado框架的适用场景?

git常见命令作用:

简述以下git中stash命令作用以及相关其他命令。

git 中 merge 和 rebase命令 的区别。

公司如何基于git做的协同开发?

如何基于git实现代码review?

git如何实现v1.0 、v2.0 等版本的管理?

什么是gitlab?

github和gitlab的区别?

如何为github上牛逼的开源项目贡献代码?

git中 .gitignore文件的作用?

什么是敏捷开发?

简述 jenkins 工具的作用?

公司如何实现代码发布?

简述 RabbitMQ、Kafka、ZeroMQ的区别?

RabbitMQ如何在消费者获取任务后未处理完前就挂掉时,保证数据不丢失?

RabbitMQ如何对消息做持久化?

RabbitMQ如何控制消息被消费的顺序?

以下RabbitMQ的exchange type分别代表什么意思?如:fanout、direct、topic。

简述 celery 是什么以及应用场景?

简述celery运行机制。

celery如何实现定时任务?

简述 celery多任务结构目录?

celery中装饰器 @app.task 和 @shared_task的区别?

简述 requests模块的作用及基本使用?

简述 beautifulsoup模块的作用及基本使用?

简述 seleninu模块的作用及基本使用?

scrapy框架中各组件的工作流程?

在scrapy框架中如何设置代理(两种方法)?

scrapy框架中如何实现大文件的下载?

scrapy中如何实现限速?

scrapy中如何实现暂定爬虫?

scrapy中如何进行自定制命令?

scrapy中如何实现的记录爬虫的深度?

scrapy中的pipelines工作原理?

scrapy的pipelines如何丢弃一个item对象?

简述scrapy中爬虫中间件和下载中间件的作用?

scrapy-redis组件的作用?

scrapy-redis组件中如何实现的任务的去重?

scrapy-redis的调度器如何实现任务的深度优先和广度优先?

简述 vitualenv 及应用场景?

简述 pipreqs 及应用场景?

在Python中使用过什么代码检查工具?

简述 saltstack、ansible、fabric、puppet工具的作用?

B Tree和B+ Tree的区别?

请列举常见排序并通过代码实现任意三种。

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

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

有没有刷过leetcode?

列举熟悉的的Linux命令。

公司线上服务器是什么系统?

解释 PV、UV 的含义?

解释 QPS的含义?

uwsgi和wsgi的区别?

supervisor的作用?

什么是反向代理?

简述SSH的整个过程。

有问题都去那些找解决方案?

是否有关注什么技术类的公众号?

最近在研究什么新技术?

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

posted @ 2018-10-09 16:53  你有我搞笑吗  阅读(325)  评论(0编辑  收藏  举报