2024年最全python面试题,2024年最新2024Python高级面试题汇总解答

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

def top(self):
	return self.item[-1]
	
def clear(self):
	del self.item
	
def isempty(self):
	return item.size() ==0
	
def size(self):
	return len(self.item)
	
def showList(self):
	print(self.item)

47、常用字符串格式化哪几种?



%、format、f


48、简述 生成器、迭代器、可迭代对象 以及应用场景?  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190330142745954.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI3Njk1NjU5,size_16,color_FFFFFF,t_70)



迭代器理解
迭代是Python最强大的功能之一,是访问集合元素的一种方式。
迭代器是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
迭代器有两个基本的方法:iter() 和 next()。
字符串,列表或元组对象都可用于创建迭代器:
任何实现了__iter__和__next__()方法的对象都是迭代器。__iter__返回迭代器自身,__next__返回容器中的下一个值

实现方法:
class iterdemo():

def __init__(self):
    self.number=1

#重写 __iter__方法   说明有可以迭代的能力( iterable)
def __iter__(self):
    print("__iter__")
    return  self

#重写 __next__方法 说明是  迭代器 (iterator) 
def __next__(self):
    print("__next__")
    self.number += 1
    return self.number

=================================================
生成器:

生成器是一种特殊的迭代器,它的返回值不是通过return而是用yield
生成器算得上是Python语言中最吸引人的特性之一,生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅。它不需要再像上面的类一样写__iter__()和__next__()方法了,只需要一个yiled关键字。 生成器一定是迭代器(反之不成立)
方式一:
gen =(x+2 for x in range(10))
print(gen)
方式二:
#每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。

def number():
number=1
print(“number=”,number)
yield number
number+=1
print(“number=”, number)
yield number
number += 1

n = number()#调用一个生成器函数,返回的是一个迭代器对象。
print(n)
结果是: <generator object number at 0x005E4F60>说明是生成器

如果把yield删除掉
结果是: number= 1
None
说明是普通的函数而已

调用
print(next(n))
print(next(n))

调用2次的结果是:
number= 1
1
number= 2
2
但是再调用一次
print(next(n))就会有异常StopIteration 没有已经没有迭代项了


49、用Python实现一个二分查找的函数。



def binary_search(lis, num):
left = 0
right = len(lis) - 1
while left <= right: #循环条件
mid = (left + right) / 2 #获取中间位置,数字的索引(序列前提是有序的)
if num < lis[mid]: #如果查询数字比中间数字小,那就去二分后的左边找,
right = mid - 1 #来到左边后,需要将右变的边界换为mid-1
elif num > lis[mid]: #如果查询数字比中间数字大,那么去二分后的右边找
left = mid + 1 #来到右边后,需要将左边的边界换为mid+1
else:
return mid #如果查询数字刚好为中间值,返回该值得索引
return -1 #如果循环结束,左边大于了右边,代表没有找到

lis = [11, 32, 51, 21, 42, 9, 5, 6, 7, 8]
print(lis)
lis.sort()
print(lis)
while 1:
    num = int(input('输入要查找的数:'))
    res = binary_search(lis, num)
    print(res)
    if res == -1:
        print('未找到!')
    else:
        print('找到!')

2.递归算法

def binary_search(lis, left, right, num):

    if left > right: #递归结束条件
        return -1
    mid = (left + right) / 2
    if num < lis[mid]:
        right = mid -1
    elif num > lis[mid]:
        left = mid + 1
    else:
        return mid
    return binary_search(lis, left, right, num)
    #这里之所以会有return是因为必须要接收值,不然返回None
    #回溯到最后一层的时候,如果没有return,那么将会返回None

lis = [11, 32, 51, 21, 42, 9, 5, 6, 7, 8]
print(lis)
lis.sort()
print(lis)
while 1:
    num = int(input('输入要查找的数:'))
    res = binary_search(lis, 0, len(lis)-1,num)
    print(res)
    if res == -1:
        print('未找到!')
    else:
        print('找到!')

50、谈谈你对闭包的理解?  
 <https://blog.csdn.net/Yeoman92/article/details/67636060>



在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。

一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。

def outer(a):
b = 10
def inner():
print(a+b)
return inner


51、os和sys模块的作用?



os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口;

sys模块负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境。
详细:https://blog.csdn.net/qq_38276669/article/details/83687738


52、如何生成一个随机数?



#python中利用random获取一个0到1的随机浮点数
a = random.random()
print(a)

#python中利用random获取一定范围内的(10到20)的随机浮点数
b = random.uniform(10,20)
print(b)

#python利用random获取一定范围内(10到20)的随机整数
c = random.randint(10,20)
print©

#python利用random从列表集合中获取一个随机值
list = [5,‘hello’,9,‘xiong_it’,3,‘Python’]
d = random.choice(list)
print(d)


53、如何使用python删除一个文件?



使用python删除一个文件或文件夹,需要使用os模块。

import os
os.remove(path) # path是文件的路径,如果这个路径是一个文件夹,则会抛出OSError的错误,这时需用用rmdir()来删除
os.rmdir(path) # path是文件夹路径,注意文件夹需要时空的才能被删除
os.unlink(‘F:\新建文本文档.txt’) # unlink的功能和remove一样是删除一个文件,但是删除一个删除一个正在使用的文件会报错。
import os
path = ‘F:/新建文本文档.txt’ # 文件路径
if os.path.exists(path): # 如果文件存在
# 删除文件,可使用以下两种方法。
os.remove(path)
#os.unlink(path)
else:
print(‘no such file:%s’%my_file) # 则返回文件不存在
import os
os.removedirs(path) # 递归地删除目录。如果子目录成功被删除,则将会成功删除父目录,子目录没成功删除,将抛异常。
import os
for root, dirs, files in os.walk(top, topdown=False):
for name in files:
os.remove(os.path.join(root, name))
for name in dirs:
os.rmdir(os.path.join(root, name))
另一种方法

import shutil
shutil.rmtree()


54、谈谈你对面向对象的理解?


python面试笔记35


55、Python面向对象中的继承有什么特点?



1:在继承中基类的构造(init()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。

2:在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数

3:Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找,即先在本类中查找调用的方法,找不到才去基类中找。

如果在继承元组中列了一个以上的类,那么它就被称作“多重继承” 。

私有属性的访问方法:

例子中的 __money就是私有属性,需要用set,get方法进行访问。


56、面向对象深度优先和广度优先是什么?



MRO即方法解析顺序(method resolution order),用于判断子类调用的属性来自于哪个父类。在Python2.3之前,MRO是基于深度优先算法的,自2.3开始使用C3算法,定义类时需要继承object,这样的类称为新式类,否则为旧式类

经典类采用深度优先搜索

class P1:
def foo(self):
print ‘p1-foo’

class P2 :
def foo(self):
print ‘p2-foo’

 def bar(self):   
     print 'p2-bar'   

class C1 (P1,P2):
pass

class C2 (P1,P2):
def bar(self):
print ‘C2-bar’

class D(C1,C2):
pass

d = D()
d.foo() # 输出 p1-foo
d.bar() # 输出 p2-bar
实例d调用foo()时,搜索顺序是 D => C1 => P1

实例d调用bar()时,搜索顺序是 D => C1 => P1 => P2

经典类的搜索方式:从左到右,深度优先

新式类采用广度优先搜索

class P1(object):
def foo(self):
print ‘p1-foo’

class P2(object):
def foo(self):
print ‘p2-foo’

 def bar(self):   
     print 'p2-bar'   

class C1 (P1,P2):
pass

class C2 (P1,P2):
def bar(self):
print ‘C2-bar’

class D(C1,C2):
pass

d=D()
d.foo() # 输出 p1-foo
d.bar() # 输出 c2-bar
实例d调用foo()时,搜索顺序是 D => C1 => C2 => P1
实例d调用bar()时,搜索顺序是 D => C1 => C2


57、面向对象中super的作用?



class Bicycle(object):
def init(self, name):
self.name = name

def run(self):
    print('我是%s的run方法'%self.name)

class E_Bicycle(Bicycle): # 继承自行车
def init(self, name, age):
super().init(name) # 调用父类的name属性
self.age = age

def run(self):
    super().run()  # 调用父类的run方法
    print('被主人改装%s年了'%(self.age)

b = Bicycle()
b.run()

e_b = E_Bicycle(‘电动车’, 3)
e_b.run()

super() 函数是用于调用父类(超类)的一个方法。
super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。
MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。

以下是 super() 方法的语法:
super(type[, object-or-type])
参数
type – 类。
object-or-type – 类,一般是 self
Python3.x 和 Python2.x 的一个区别是: Python 3 可以使用直接使用 super().xxx 代替 super(Class, self).xxx :

super不是一个关键字,也是不是有函数,他是一个类
super()的作用不是查找父类,而是找MRO列表的上一个类
super()和父类没有任何实质性的关系,只是有时候能调用到父类而已。
在单继承的情况下,super()永远调用的是父类/父对象
super()多用于菱形继承
格式:
super().方法() #python3的格式


![在这里插入图片描述](https://img-blog.csdnimg.cn/20190330192912765.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI3Njk1NjU5,size_16,color_FFFFFF,t_70)  
 58、是否使用过functools中的函数?其作用是什么?



functools用于高阶函数:指那些作用于函数或者返回其他函数的函数。通常情况下,只要是可以被当做函数调用的对象就是这个模块的目标。

partial

首先是partial函数,它可以重新绑定函数的可选参数,生成一个callable的partial对象

update_wrapper

接着是update_wrapper函数,它可以把被封装函数的__name__、module、__doc__和 __dict__都复制到封装函数去:
wraps

再有是wraps函数,它将update_wrapper也封装了进来

total_ordering

最后至于total_ordering函数则给予类丰富的排序方法,使用装饰器简化了操作。如果使用必须在类里面定义一个__lt__(),le(), gt(), 或__ge__()。应该给类添加一个__eq__() 方法。


59、列举面向对象中带爽下划线的特殊方法,如:**new**、**init**



类的特殊成员方法

doc :打印类的描述信息
__init__初始化魔术对象,当一个对象被实例化是自动触发
new 当一个对象被实例化前自动触发,通过传递参数判断对象是否被创建或其他
__del__当一个对象没有任何引用是被触发,回收内存
__call__将对象当作函数调用时触发
module:表示当前操作的对象在那个模块
class:表示当前操作的对象的类是什么
str:如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值


60、如何判断是函数还是方法?



什么是函数?什么是方法?

		def func():
			pass


		class Foo(object):

			def func(self):
				pass

		# 执行方式一
		# obj = Foo()
		# obj.func() # 方法

		# 执行方式二
		# Foo.func(123) # 函数

		from types import FunctionType,MethodType

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


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

61、静态方法和类方法区别?



实例方法,类方法,静态方法都可以通过实例或者类调用,只不过实例方法通过类调用时需要传递实例的引用(python 3可以传递任意对象,其他版本会报错)。

三种方法从不同层次上来对方法进行了描述:实例方法针对的是实例,类方法针对的是类,他们都可以继承和重新定义,而静态方法则不能继承,可以认为是全局函数。


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



魔术方法 用于在某一时刻调用时
__str__魔术方法:

  1. 在打印某个对象的时候,会调用这个对象的__str__方法,打印这个方法的返回值。

  2. 如果在使用str(obj)这个函数的时候,也会调用__str__方法。

__repr__魔术方法:

  1. __repr__魔术方法是用来表述某个对象在内存中的展示形式。

  2. 如果在终端直接输入一个对象,然后按回车,那么将会执行这个对象的__repr__方法。

  3. 如果你将几个对象扔到一个容器中(比如:列表),那么你在打印这个容器的时候,会依次调用这个容器中的元素的__repr__方法。如果没有实现这个__repr__方法,那么得到的将是一个类名+地址的形式,这种形式的是不好理解的。

__dict__魔术属性:

  1. 用来获取用户自定义的属性,以及这个属性对应的值。返回的是一个字典。

  2. dir函数做一个区分。dir函数返回的是这个对象上拥有的所有属性,包括Python内置的属性和用户自己添加的,并且只是获取属性名字,不会获取这个属性对应的值。


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



for x in range(1, 5):
for z in range(1, 5):
for i in range(1, 5):
if i != x and i != z and x != z:
print(i, x, z)


64、什么是反射?以及应用场景?



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

  1. getattr()函数是Python自省的核心函数,具体使用大体如下:
    class A:
    def init(self):
    self.name = ‘twiss’
    #self.age=‘24’
    def method(self):
    print"method print"
    Instance = A()
    print getattr(Instance , ‘name, ‘not find’) #如果Instance 对象中有属性
    name则打印self.name的值,否则打印’not find’
    print getattr(Instance , ‘age’, ‘not find’) #如果Instance 对象中有属性
    age则打印self.age的值,否则打印’not find’
    print getattr(a, ‘method’, ‘default’) #如果有方法method,否则打印其地址,
    否则打印default
    print getattr(a, ‘method’, ‘default’)() #如果有方法method,运行函数并
    打印None否则打印default

  2. hasattr(object, name)
    说明:判断对象object是否包含名为name的特性(hasattr是通过调用getattr(ojbect, name)
    是否抛出异常来实现的)

  3. setattr(object, name, value)
    这是相对应的getattr()。参数是一个对象,一个字符串和一个任意值。字符串可能
    会列出一个现有的属性或一个新的属性。这个函数将值赋给属性的。该对象允许它提供
    。例如,setattr(x,“foobar”,123)相当于x.foobar = 123。

  4. delattr(object, name)
    与setattr()相关的一组函数。参数是由一个对象(记住python中一切皆是对象)和一
    个字符串组成的。string参数必须是对象属性名之一。该函数删除该obj的一个由string
    指定的属性。delattr(x, ‘foobar’)=del x.foobar


67、metaclass作用?以及应用场景?



元类就是创建类这种对象的东西
当python在执行带class语句的时候,会初始化一个类对象放在内存里面。例如这里会初始化一个Trick对象

这个对象(类)自身拥有创建对象(通常我们说的实例,但是在python中还是对象)的能力。
1.类由type创建,创建类时,type的__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法)
2.对象由类创建,创建对象时,类的__init__方法自动执行,对象()执行类的 call 方法


68、用尽量多的方法实现单例模式。



单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。
实现单例模式的几种方式
使用模块
其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做
class Singleton(object):
def foo(self):
pass
singleton = Singleton()
将上面的代码保存在文件 mysingleton.py 中,要使用时,直接在其他文件中导入此文件中的对象,这个对象即是单例模式的对象
from a import singleton


69、装饰器的写法以及应用场景。



装饰器是一个工厂函数,接受一个函数作为参数,然后返回一个新函数,
其闭包中包含被装饰的函数。有了装饰器,
可以提取大量函数中与本身功能无关的类似代码 ( 这块在Flask中用于定义路由的@app.route,就是一个很好的例子),达到代码重用的目的。
可应用于插入日志、性能测试、事务处理等方面。

def deco(func):
def warpper(*args, **kwargs):
print(‘start‘)
func(*args, **kwargs)
print(‘end‘)
return warpper

@deco
def myfunc(parameter):
print(“run with %s” % parameter)

myfunc(“something”)


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



try:
pirnt(‘123’)
except:
print(‘456’)
通过raise 异常对象主动抛出异常


71、什么是面向对象的mro



Method Resolution Order 用来制作一个继承关系的列表
MRO列表的制作原则:
1.子类永远在父类的前面
2.如果继承了多个父类,那么按照()中的顺序在列表中摆放
3.如果多个类同时继承了一个父类,孙子类中只会选取第一个父类中的父类的该方法


72、isinstance作用以及应用场景?



检测一个数据是否由指定的类型创建


73、写代码并实现:



Given an array of integers, return indices of the two numbers such that they add up to a specific target.You may assume that each input would
have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,

return [0, 1]

def nums(lists, n):
if isinstance(lists, list):
for i in range(len(lists)):
for v in lists:
if lists[i] + v == n:
print(i, lists.index(v))
break


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



#字符串、字典、列表、数字、布尔值、None、、自定义class类
import json
import datetime

class MyEncoder(json.JSONEncoder):
def default(self, o): # o是数据类型
if isinstance(o, datetime.datetime)
return o.strftime(‘%Y-%m-%d’)
else:
return super(MyEncoder, self).default(o)


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



json.dumps(jsonData,ensure_ascii=False);


76、什么是断言?应用场景?



在没完善一个程序之前,我们不知道程序在哪里会出错,与其让它在运行最崩溃,不如在出现错误条件时就崩溃,这时候就需要assert断言的帮助

python assert断言是声明其布尔值必须为真的判定,如果发生异常就说明表达示为假。可以理解assert断言语句为raise-if-not,用来测试表示式,其返回值为假,就会触发异常。

断言条件为真时,代码继续执行,负责抛出异常,这个异常通常不会去捕获他,我们设置一个断言目的就是要求必须实现某个条件。

assert True


77、有用过with statement吗?它的好处是什么?



with语句的作用是通过某种方式简化异常处理
自动管理文件关闭


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



1递归方法

def print_directory_contents(sPath):
import os
for sChild in os.listdir(sPath):
sChildPath = os.path.join(sPath,sChild)
if os.path.isdir(sChildPath):
print_directory_contents(sChildPath)
else:
print(sChildPath)

print_directory_contents(‘./test/’)

#2
tapath = ‘./test/’
for i in os.listdir(tapath):
print(i)


79、简述 yield和yield from关键字。



yield 的作用就是把一个函数变成一个生成器, 带有yield的函数不再是一个普通的函数。python解释器会将其视为一个generator
yield:生成器函数关键字
yield from:相当于 for i in obj : yield i

def a():
yield 1
def b():
yield from a()


80、求结果



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

[6, 6, 6, 6]


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


1、简述 OSI 七层协议。



1、物理层
为数据链路层提供物理连接,实现比特流的透明传输,所传输数据的单位是比特,该层定义了通信设备与传输线接口硬件的电气、机械以及功能和过程的特性。
2、数据链路层
在通信的实体之间建立数据链路连接,传送以帧为单位的数据,通过检查发生在连接通信系统间传送路上的比特错误并进行恢复,确保比特序列组成为数据流准确无误地传送给对方的系统。数据链路层在相邻的节点之间实现透明的高可靠性传输。
3、网络层
解决多节点传送时的路由选择、拥挤控制及网络互连等,控制分组传送系统的操作,它的特性对高层是透明的,同时,根据传输层的要求选择服务质量,并向传输层报告未恢复的差错。
4、传输层
为两个端系统(源站和目标站)的会话层之间建立一条传输连接,可靠、透明地传送报文,执行端一端差错控制、顺序和流量控制、管理多路复用等。本层提供建立、维护和拆除传送连接的功能,并保证网络连接的质量。它向高层屏蔽了下层数据通信的细节,因而是OSI网络参考模型中最需要的一层。
5、会话层
不参与具体的数据传输,但对数据传输的同步进行管理。它主要负责提供两个进程之间建立、维护和结束会话连接功能,同时要对进程中必要的信息传送方式、进程间的同步以及重新同步进行管理。
6、表示层
解决在两个通信系统中交换信息时不同数据格式的编码之间的转换,语法选择,数据加密与解密及文本压缩等。
7、应用层
负责向用户提供各种网络应用服务,如文件传输、电子邮件、远程访问等。把进程中于对方进程通信的部分放入应用实体中,同时,对各种业务内容的通信功能进行管理。


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



C/S架构软件(即客户机/服务器模式)分为客户机和服务器两层:第一层是在客户机系统上结合了表示与业务逻辑,第二层是通过网络结合了数据库服务器。简单的说就是第一层是用户表示层,第二层是数据库层。客户端和服务器直接相连,这两个组成部分都承担着重要的角色。
B/S型模式,即浏览器/服务器结构。它是C/S架构的一种改进,可以说属于三层C/S架构。主要是利用了不断成熟的WWW浏览器技术,用通用浏览器就实现了原来需要复杂专用软件才能实现的强大功能,并节约了开发成本,是一种全新的软件系统构造技术。


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



所谓三次握手(Three-Way Handshake)即建立TCP连接,就是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发

  1. 第一次握手:
    Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
  2. 第二次握手:
    Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
  3. 第三次握手:
    Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。

所谓四次挥手(Four-Way Wavehand)即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发

第一次挥手:
Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
第二次挥手:
Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
第三次挥手:
Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
第四次挥手:
Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。


4、什么是arp协议?



地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议。


5、TCP和UDP的区别?



基于连接与无连接
TCP要求系统资源较多,UDP较少;
UDP程序结构较简单
流模式(TCP)与数据报模式(UDP);
TCP保证数据正确性,UDP可能丢包
TCP保证数据顺序,UDP不保证


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



局域网和广域网是按规模大小而划分的两种计算机网络。范围在几千米以内的计算机网络统称为局域网;而连接的范围超过10千米的,则称为广域网,因特网(Intenet)就是目前最大的广域网。


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



TCP的可靠保证,是它的三次握手双向机制,这一机制保证校验了数据,保证了他的可靠性。而UDP就没有了,udp信息发出后,不验证是否到达对方,所以不可靠。


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



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


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



指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能由接收方造成。

socket粘包:

socket 交互send时,连续处理多个send时会出现粘包,soket会把两条send作为一条send强制发送,会粘在一起。

send发送会根据recv定义的数值发送一个固定的数值,如果最后一次,所剩的数值小于recv定义数就会连带两条send数据同时发送,发生粘包状况。

解决方案:

方案1:可以使用time.sleep 在两send之间加上时间(不建议)

方案2:可以在send两条之间加入一条 conn.recv(1024)


10、IO多路复用的作用?



I/O多路复用是通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。

首先,输入操作一般包含两个步骤:

等待数据准备好(waiting for data to be ready)。对于一个套接口上的操作,这一步骤关系到数据从网络到达,并将其复制到内核的某个缓冲区。

将数据从内核缓冲区复制到进程缓冲区(copying the data from the kernel to the process)。

阻塞I/O模型
非阻塞I/O模型
I/O复用模型
正因为阻塞I/O只能阻塞一个I/O操作,而I/O复用模型能够阻塞多个I/O操作,所以才叫做多路复用。


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



简单的来说,防火墙就是一种,避免你的电脑被黑客入侵的一种防护工具,一种确保网络安全的方法!
1.允许网络管理员定义一个中心点来防止非法用户进入内部网络。
2.可以很方便地监视网络的安全性,并报警。
3.可以作为部署NAT(Network Address Translation,网络地址变换)的地点,利用NAT技术,将有限的IP地址动态或静态地与内部的IP地址对应起来,用来缓解地址空间短缺的问题等


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



1)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用 epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在 epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的 时候只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间。这就是回调机制带来的性能提升。

(2)select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把current往设备等待队列中挂一次,而epoll只要 一次拷贝,而且把current往等待队列上挂也只挂一次(在epoll_wait的开始,注意这里的等待队列并不是设备等待队列,只是一个epoll内 部定义的等待队列)。这也能节省不少的开销。


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



进程拥有自己的堆和栈,既不共享堆也不共享栈 进程由操作系统调度

线程拥有自己的堆和共享的栈 共享栈 但不共享堆 线程也是由操作系统调度

协程和线程一样有自己的堆和共享的栈 共享栈但不共享堆 协程由开发人员在适当情况调用


14、GIL锁是什么鬼?



GIL:全局解释器锁。当我们用多线程的时候,
每一个进程中只有一个GIL锁,那么这多个线程中谁拿到GIL锁,
谁即可以用cpu(ps:多个进程有多个Gil锁,但每个进程中只有一个GIL)


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



进程池:使用multiprocessing.Pool
线程池:使用ThreadPool模块


16、threading.local的作用?



threadLocal解决了参数在一个线程中各个函数之间相互传递的问题
一个threadLocal变量虽然是全局变量,但每个线程都只能读写自己线程的独立副本 互不干扰


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



创建一个queue队列,或使用 from multiprocessing import Manage管理要进行通信的数据


18、什么是并发和并行?



并发(concurrency)和并行(parallellism)是:

解释一:并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。

解释二:并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。

解释三:在一台处理器上“同时”处理多个任务,在多台处理器上同时处理多个任务。如hadoop分布式集群

所以并发编程的目标是充分的利用处理器的每一个核,以达到最高的处理性能。


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



当多进程或多线程是不用进程访问相同一个变量
是会造成同一时间执行相同的事 而得不到正确的结果 所以需要用锁锁上这个全局变量,
当某一个进程或线程访问时其他进程或线程均无法访问


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



异步双方不需要共同的时钟,也就是接收方不知道发送方什么时候发送,
所以在发送的信息中就要有提示接收方开始接收的信息,如开始位,同时在结束时有停止位。
非阻塞模式是指利用socket事件的消息机制,Server端与Client端之间的通信处于异步状态。


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



一、工作所在的OSI层次不一样(根本区别,导致接下来的区别)
交换机工作在 OSI模型的数据链路层,所以工作原理比较简单;
路由器工作在OSI模型的网络层,具备更多的网络协议信息,所以可以做出更好的数据转发策略。

二、数据转发所依据的对象也不一样。
交换机工作在数据链路层,所以交换机转发数据依靠的是每个物理地址(MAC地址),MAC地址一般是设备生产商在设备出厂时固定在设备中的,不能进行更改。
路由器工作在网络层,所以其交换数据依靠网络地址(IP地址),而IP地址是由网络管理员自己分配或者系统自动获取的。

三、是否可以分割广播域
由交换机连接的所有端口仍然属于同一个广播域,所以极有可能会产生数据拥堵;
连接到路由器上的所有端口不在属于同一个广播域,所以不会产生类似的数据拥堵问题。


22、什么是域名解析?



域名解析是把域名指向网站空间IP,让人们通过注册的域名可以方便地访问到网站的一种服务


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



127.0.0.1 localhost

::1 localhost

127.0.0.1 www.gkate.com
修改后用浏览器访问“www.gkate.com”会被解析到127.0.0.1,导致无法显示该网页


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



应用于一个生产数据一个处理数据的场景
优势生产者和消费者之间不直接进行通信 而是通过一个队列相当于一个缓冲区,
平衡了生产者和消费者的处理能力


25、什么是cdn?



尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,
使内容传输的更快、更稳定。通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、
负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。


26、LVS是什么及作用?



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

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

LVS :单向的

End user ------>LVS --------> tomcat …> end user

Ngnix 有个来回

End user ------>Ngnix--------> tomcat---->Ngnix …> end user


27、Nginx是什么及作用?



Nginx是一个http服务器。同效果的http服务器还有Apache、tomcat等
作用:
1、 http服务器。Nginx是一个http服务可以独立提供http服务。可以做网页静态服务器。
2、 虚拟主机。可以实现在一台服务器虚拟出多个网站。例如个人网站使用的虚拟主机。基于端口的,不同的端口基于域名的,不同域名
3、 反向代理,负载均衡。当网站的访问量达到一定程度后,单台服务器不能满足用户的请求时,需要用多台服务器集群可以使用nginx做反向代理。并且多台服务器可以平均分担负载,不会因为某台服务器负载高宕机而某台服务器闲置的情况。


28、keepalived是什么及作用?


29、haproxy是什么以及作用?


30、什么是负载均衡?



负载均衡是高可用网络基础架构的的一个关键组成部分,
有了负载均衡,我们通常可以将我们的应用服务器部署多台,
然后通过负载均衡将用户的请求分发到不同的服务器用来提高网站、
应用、数据库或其他服务的性能以及可靠性。


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


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



asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。
asyncio的编程模型就是一个消息循环。我们从asyncio模块中直接获取一个
EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO。


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



当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,
等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,
经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。
由于切换是在IO操作时自动完成,所以gevent需要修改Python自带的一些标准库,
这一过程在启动时通过monkey patch完成


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



Twisted是用Python实现的基于事件驱动的网络引擎框架,
Twisted支持许多常见的传输及应用层协议,包括TCP、UDP、SSL/TLS、HTTP、IMAP、SSH、IRC以及FTP。就像Python一样,Twisted也具有“内置电池”(batteries-included)的特点。
Twisted对于其支持的所有协议都带有客户端和服务器实现,同时附带有基于命令行的工具,
使得配置和部署产品级的Twisted应用变得非常方便。


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


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



关系型:Mysql / Oracle / SQL Server
非关系型:redis / MongoDB…


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



MySQL数据库中的表引擎一般常用两种:MyISAM和InnoDB
区别:
MyISAM类型的数据文件有三个1.frm(结构)、2.MYD(数据)、3.MYI(索引)
MyISAM类型中的表数据增 删 改速度快,不支持事务,没有InnoDB安全。
InnoDB类型的数据文件只有一个 .frm
InnoDB类型的表数据增 删 改速度没有MyISAM的快,但支持事务,相对安全。


3、简述数据三大范式?



第一范式(1NF):原子性 字段不可再分,否则就不是关系数据库;

第二范式(2NF):唯一性 一个表只说明一个事物;

第三范式(3NF):每列都与主键有直接关系,不存在传递依赖;
1NF:列表字段不可分;

2NF:有主键且非主键依赖主键;

3NF:非主键字段不能相互依赖;


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



同时对一组数据进行操作的语句就成为事务
在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。


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



一对多 :一个学生对多门考试成绩
多对多 :一个老师教多个学生 一个学生让好几个老师教


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



设置一个商品计数的列 自动递增为1


7、常见SQL(必备)


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



触发器:制定一个sql条件和要做的事当满足的时候自动触发并执行要做的事
函数(存储过程):Mysql储存过程简而言之就是一组已经好的命令,需要使用的时候拿出来用就可以
视图:将一个写好的查询语句封装起来 当调用的时看到的数据就是满足条件的数据 不用每次都写同样的代码


9、MySQL索引种类



唯一索引
主键索引
普通索引
全文索引


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



联合索引


11、主键和外键的区别?




| . | 主键 | 外键 |
| --- | --- | --- |
| 定义 | 允许唯一标识,一条记录,不允许重复,不允许为空 | 表的外键是另外一表的主键,外键可以有重复,可以为空值 |
| 作用 | 用来保证数据完整性 | 用来和其他表建立关系 |
| 个数 | 主键只有一个 | 一个表可以有多个外键 |


12、MySQL常见的函数?



*concat(s1,s2,…Sn) 连接s1,s2…Sn为一个字符串
*length(str) 返回值为字符串str 的长度
*datediff(expr,expr2) 返回起始时间和结束时间的间隔天数


13、列举 创建索引但是无法命中索引的8种情况。  
 面试笔记28.4  
 14、如何开启慢日志查询?



1.查看慢查询是否开启
show variables like ‘slow_query%’;
show variables like ‘long_query_time’;

2.打开慢查询
set global slow_query_log=’ON’;

3.设置慢查询日志记录文件
set global slow_query_log_file=’/var/lib/mysql/test-10-226-slow.log’;

4.指定慢查询事件
set global long_query_time=1;


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



导出:
mysql dump -u root -p 库名 >导出的文件.sql

导入:
mysql -u root -p 库名


16、数据库优化方案?


python面试笔记28.5


17、char和varchar的区别?



char的长度是不可变的,而varchar的长度是可变的,也就是说,定义一个char[10]和varchar[10],如果存进去的是‘csdn’,那么char所占的长度依然为10,除了字符‘csdn’外,后面跟六个空格,而varchar就立马把长度变为4了


18、简述MySQL的执行计划?



数据库的执行计划通俗点说就是,数据库服务器在执行sql语句的时候,会准备几套方案,最后选择消耗资源最小的那个方案。就是执行计划。


19、在对name做了唯一索引前提下,简述以下区别:



select * from tb where name = ‘twiss’   ----—–取出所有name= twiss

select * from tb where name = ‘twiss’ limit 1 ---—–只取出第一条 name= twiss

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



当一个数据库表过于庞大,LIMIT offset, length中的offset值过大,则SQL查询语句会非常缓慢,增加order by,并且order by字段需要建立索引。


21、什么是索引合并?



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


22、什么是覆盖索引?



就是select的数据列只用从索引中就能够取得,不必从数据表中读取,换句话说查询列要被所使用的索引覆盖。


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



对于数据存储层高并发问题,最先想到的可能就是读写分离,在网站访问量大并且读写不平均的情况下,将存储分为master,slave两台,所有的写都路由到master上,所有的读都路由到slave上,然后master和slave同步。如果一台salve不够,可以加多台,比如一台master,3台slave。


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



分区的主要目的是将数据按照一个较粗的粒度分在不同的表中,这样可以将相关的数据存放在一起,而且如果想一次性的删除整个分区的数据也很方便。
通过一些HASH算法或者工具实现将一张数据表垂直或者水平进行物理切分


25、redis和memcached比较?



1、Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其他东西,例如图片、视频等等;

2、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储;

3、虚拟内存–Redis当物理内存用完时,可以将一些很久没用到的value 交换到磁盘;

4、过期策略–memcache在set时就指定,例如set key1 0 0 8,即永不过期。Redis可以通过例如expire 设定,例如expire name 10;

5、分布式–设定memcache集群,利用magent做一主多从;redis可以做一主多从。都可以一主一从;

6、存储数据安全–memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化);

7、灾难恢复–memcache挂掉后,数据不可恢复; redis数据丢失后可以通过aof恢复;


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



redis默认有十六个db


27、python操作redis的模块?



import redis
r = redis.Redis(host=‘127.0.0.1’, port=6379,decode_responses=True)
r.set(‘name’, ‘OK’)
print(r.get(‘name’))


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



通过scan_iter分片取,减少内存压力
scan_iter(match=None, count=None)增量式迭代获取redis里匹配的的值
# match,匹配指定key
# count,每次分片最少获取个数
    r = redis.Redis(connection_pool=pool)
    for key in r.scan_iter(match='PREFIX_*', count=100000):
        print(key)

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



在Master和Slave互通之后,首先,Slave会发送sync同步指令,当Master收到指令后,将在后台启动存盘进程,同时收集所有来自Slave的修改数据集的指令信息,当后台进程完成之后,Master将发送对应的数据库文件到对应的Slave中,以完成一次完整的同步工作。其次Slave在接受到数据库文件之后,将其存盘并加载到内存中。最后,Master继续收集修改命令和新增的修改指令,并依次发送给Slave,其将在本次执行这些数据的修改命令,从而最终达到数据同步的实现。


30、redis中的sentinel的作用?



Redis Sentinel 为Redis提供了高可用的实现。通俗来说就是你可以部署一套无需人为干预即可防灾的Redis环境。
RS同时为客户端提供了其他诸如监控,通知的功能。
帮助我们自动在主从之间进行切换
检测主从中 主是否挂掉,且超过一半的sentinel检测到挂了之后才进行进行切换。
如果主修复好了,再次启动时候,会变成从。

启动主redis:
redis-server /etc/redis-6379.conf  启动主redis
redis-server /etc/redis-6380.conf  启动从redis
    
在linux中:
    找到 /etc/redis-sentinel-8001.conf  配置文件,在内部:
        - 哨兵的端口 port = 8001
        - 主redis的IP,哨兵个数的一半/1
    
    找到 /etc/redis-sentinel-8002.conf  配置文件,在内部:
        - 哨兵的端口 port = 8002
        - 主redis的IP, 1 

    启动两个哨兵      

31、如何实现redis集群?



redis集群、分片、分布式redis
redis-py-cluster
集群方案:
- redis cluster 官方提供的集群方案。
- codis,豌豆荚技术团队。
- tweproxy,Twiter技术团队。
redis cluster的原理?
- 基于分片来完成。
- redis将所有能放置数据的地方创建了 16384 个哈希槽。
- 如果设置集群的话,就可以为每个实例分配哈希槽:
- 192.168.1.20【0-5000】
- 192.168.1.21【5001-10000】
- 192.168.1.22【10001-16384】
- 以后想要在redis中写值时,
set k1 123
将k1通过crc16的算法,将k1转换成一个数字。然后再将该数字和16384求余,如果得到的余数 3000,那么就将该值写入到 192.168.1.20 实例中。


32、redis中默认有多少个哈希槽?



有2**14个哈希槽 16384个


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



rdb:快照形式是直接把内存中的数据保存到一个dump文件中,定时保存,保存策略
aof:把所有的对redis的服务器进行修改的命令都存到一个文件里,命令的集合
RDB:每隔一段时间对redis进行一次持久化。
- 缺点:数据不完整
- 优点:速度快
AOF:把所有命令保存起来,如果想到重新生成到redis,那么就要把命令重新执行一次。
- 缺点:速度慢,文件比较大
- 优点:数据完整


34、列举redis支持的过期策略。



定时删除
含义:在设置key的过期时间的同时,为该key创建一个定时器,让定时器在key的过期时间来临时,对key进行删除

惰性删除
含义:key过期的时候不删除,每次从数据库获取key的时候去检查是否过期,若过期,则删除,返回null。

定期删除
含义:每隔一段时间执行一次删除(在redis.conf配置文件设置hz,1s刷新的频率)过期key操作

voltile-lru: 从已设置过期时间的数据集(server.db[i].expires)中挑选最近频率最少数据淘汰
volatile-ttl: 从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

allkeys-lru: 从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
allkeys-random: 从数据集(server.db[i].dict)中任意选择数据淘汰
no-enviction(驱逐):禁止驱逐数据


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



LRU(最近少用的淘汰)

即redis的缓存每命中一次,就给命中的缓存增加一定ttl(过期时间)(根据具体情况来设定, 比如10分钟).一段时间后, 热数据的ttl都会较大, 不会自动失效, 而冷数据基本上过了设定的ttl就马上失效了.

相关知识:redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略(回收策略)。redis 提供 6种数据淘汰策略:

volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
no-enviction(驱逐):禁止驱逐数据


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



from . import picklecompat

class Base(object):
“”“Per-spider base queue class”“”

  def __init__(self, server, spider, key, serializer=None):
      """Initialize per-spider redis queue.

      Parameters
      ----------
      server : StrictRedis
          Redis client instance.
      spider : Spider
          Scrapy spider instance.
      key: str
          Redis key where to put and get messages.
      serializer : object
          Serializer object with ``loads`` and ``dumps`` methods.

      """
      if serializer is None:
          # Backward compatibility.
          # TODO: deprecate pickle.
          serializer = picklecompat
      if not hasattr(serializer, 'loads'):
          raise TypeError("serializer does not implement 'loads' function: %r"
                          % serializer)
      if not hasattr(serializer, 'dumps'):
          raise TypeError("serializer '%s' does not implement 'dumps' function: %r"
                          % serializer)

      self.server = server
      self.spider = spider
      self.key = key % {'spider': spider.name}
      self.serializer = serializer

  def _encode_request(self, request):
      """Encode a request object"""
      obj = request_to_dict(request, self.spider)
      return self.serializer.dumps(obj)

  def _decode_request(self, encoded_request):
      """Decode an request previously encoded"""
      obj = self.serializer.loads(encoded_request)
      return request_from_dict(obj, self.spider)

  def __len__(self):
      """Return the length of the queue"""
      raise NotImplementedError

  def push(self, request):
      """Push a request"""
      raise NotImplementedError

  def pop(self, timeout=0):
      """Pop a request"""
      raise NotImplementedError

  def clear(self):
      """Clear queue/stack"""
      self.server.delete(self.key)

class FifoQueue(Base):
“”“Per-spider FIFO queue”“”

  def __len__(self):
      """Return the length of the queue"""
      return self.server.llen(self.key)

  def push(self, request):
      """Push a request"""
      self.server.lpush(self.key, self._encode_request(request))

  def pop(self, timeout=0):
      """Pop a request"""
      if timeout > 0:
          data = self.server.brpop(self.key, timeout)
          if isinstance(data, tuple):
              data = data[1]
      else:
          data = self.server.rpop(self.key)
      if data:
          return self._decode_request(data)

class PriorityQueue(Base):
“”“Per-spider priority queue abstraction using redis’ sorted set”“”

  def __len__(self):
      """Return the length of the queue"""
      return self.server.zcard(self.key)

  def push(self, request):
      """Push a request"""
      data = self._encode_request(request)
      score = -request.priority
      # We don't use zadd method as the order of arguments change depending on
      # whether the class is Redis or StrictRedis, and the option of using
      # kwargs only accepts strings, not bytes.
      self.server.execute_command('ZADD', self.key, score, data)

  def pop(self, timeout=0):
      """
      Pop a request
      timeout not support in this queue class
      """
      # use atomic range/remove using multi/exec
      pipe = self.server.pipeline()
      pipe.multi()
      pipe.zrange(self.key, 0, 0).zremrangebyrank(self.key, 0, 0)
      results, count = pipe.execute()
      if results:
          return self._decode_request(results[0])

class LifoQueue(Base):
“”“Per-spider LIFO queue.”“”

  def __len__(self):
      """Return the length of the stack"""
      return self.server.llen(self.key)

  def push(self, request):
      """Push a request"""
      self.server.lpush(self.key, self._encode_request(request))

  def pop(self, timeout=0):
      """Pop a request"""
      if timeout > 0:
          data = self.server.blpop(self.key, timeout)
          if isinstance(data, tuple):
              data = data[1]
      else:
          data = self.server.lpop(self.key)

      if data:
          return self._decode_request(data)

TODO: Deprecate the use of these names.

SpiderQueue = FifoQueue
SpiderStack = LifoQueue
SpiderPriorityQueue = PriorityQueue


37、如何基于redis实现消息队列?



Redis中五大数据结构之一—列表,其PUSH和POP命令遵循FIFO先进先出原则。当我们需要发布消息的时候执行LPUSH(消息从左边进入队列),消息接收端执行RPOP获得消息(消息从右侧弹出)。对于列表,Redis提供了带有阻塞的命令(命令前加B)。因此,生产者lpush消息,消费者brpop(从列表中弹出最右端元素,如无元素则一直阻塞到timeout)消息,并设定超时时间timeout,可以减少redis的压力。
不要使用redis去做消息队列,这不是redis的设计目标。
但实在太多人使用redis去做去消息队列,redis的作者看不下去,另外基于redis的核心代码,另外实现了一个消息队列disque:https://github.com/antirez/disque


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



创建一个频道 客户端加入频道 等待频道发布订阅
发布者:
import redis

  conn = redis.Redis(host='127.0.0.1',port=6379)
  conn.publish('104.9MH', "hahaha")

订阅者:
import redis

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

  while True:
      msg= pub.parse_response()
      print(msg)

39、什么是codis及作用?



Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别 (不支持的命令列表), 上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作, 所有后边的一切事情, 对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的 Redis 服务.


40、什么是twemproxy及作用?



Twemproxy是一种代理分片机制,由Twitter开源。Twemproxy作为代理,可接受来自多个程序的访问,按照路由规则,转发给后台的各个Redis服务器,再原路返回。该方案很好的解决了单个Redis实例承载能力的问题。
是 Twtter 开源的一个 Redis 和 Memcache 代理服务器,主要用于管理 Redis 和 Memcached 集群,减少与Cache 服务器直接连接的数量。


41、写代码实现redis事务操作。



import redis

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

conn = redis.Redis(connection_pool=pool)

pipe = r.pipeline(transaction=False)

pipe = conn.pipeline(transaction=True)

开始事务

pipe.multi()

pipe.set(‘name’, ‘bendere’)
pipe.set(‘role’, ‘sb’)

提交

pipe.execute()

注意:咨询是否当前分布式redis是否支持事务


42、redis中的watch的命令的作用?



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

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

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

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

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

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

          # 执行,把所有命令一次性推送过去
          pipe.execute()
  - 数据库的锁 

43、基于redis如何实现商城商品数量计数器?



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


44 、简述redis分布式锁和redlock的实现机制。



在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段。
一个Client想要获得一个锁需要以下几个操作:

得到本地时间Client使用相同的key和随机数,按照顺序在每个Master实例中尝试获得锁。在获得锁的过程中,为每一个锁操作设置一个快速失败时间(如果想要获得一个10秒的锁, 那么每一个锁操作的失败时间设为5-50ms)。
这样可以避免客户端与一个已经故障的Master通信占用太长时间,通过快速失败的方式尽快的与集群中的其他节点完成锁操作。

客户端计算出与master获得锁操作过程中消耗的时间,当且仅当Client获得锁消耗的时间小于锁的存活时间,并且在一半以上的master节点中获得锁。才认为client成功的获得了锁。

如果已经获得了锁,Client执行任务的时间窗口是锁的存活时间减去获得锁消耗的时间。
如果Client获得锁的数量不足一半以上,或获得锁的时间超时,那么认为获得锁失败。客户端需要尝试在所有的master节点中释放锁, 即使在第二步中没有成功获得该Master节点中的锁,仍要进行释放操作。


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



对节点和数据,都做一次哈希运算,然后比较节点和数据的哈希值,数据取和节点最相近的节点做为存放节点。这样就保证当节点增加或者减少的时候,影响的数据最少。
hash_ring 是python中做一致性哈希的模块
Python模块–hash_ring,即Python中的一致性hash


46、如何高效的找到redis中所有以twiss开头的key?



key twiss*
redis 有一个keys命令。
语法:KEYS pattern
说明:返回与指定模式相匹配的所用的keys。
该命令所支持的匹配模式如下:
(1)?:用于匹配单个字符。例如,h?llo可以匹配hello、hallo和hxllo等;
(2):用于匹配零个或者多个字符。例如,hllo可以匹配hllo和heeeello等;
(3)[]:可以用来指定模式的选择区间。例如h[ae]llo可以匹配hello和hallo,但是不能匹配hillo。
同时,可以使用“/”符号来转义特殊的字符


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


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



HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传送协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。
HTTP是一个应用层协议,由请求和响应构成,是一个标准的客户端服务器模型。HTTP是一个无状态的协议。端口号为80


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



WebSocket是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。


3、什么是magic string ?



有触发时机在满足条件时自动触发就是魔术方法


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



使用媒体查询的方式,创建多个元素宽度是相对的的布局理想的响应式布局是指的对PC/移动各种终端进行响应的
@media (min-width: 768px){
.pg-header{
background-color: green;
}
}
@media (min-width: 992px){
.pg-header{
background-color: pink;
}
}


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



Bootstrap / vue / React


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



AJAX是在不加载整个页面的情况异步下与服务器发送请求交换数据并更新部分网页的艺术
$.ajax({
url:‘user/add’,//当前请求的url地址
type:‘get’,//当前请求的方式 get post
data:{id:100},//请求时发送的参数
dataType:‘json’,//返回的数据类型
success:function(data){
//ajax请求成功后执行的代码
console.log(data);
},
error:function(){
//ajax执行失败后执行的代码
alert(‘ajax执行错误’);
},
timeout:2000,//设置当前请求的超时时间 异步请求生效
async:true //是否异步 false同步 true异步
})


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



轮询:客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并关闭连接。

优点:后端程序编写比较容易。 缺点:请求中有大半是无用,浪费带宽和服务器资源。 实例:适于小型应用。
https://www.cnblogs.com/zhaowinter/p/5332681.html


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



客户端向服务器发送Ajax请求,服务器接到请求后hold住连接,直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求。
优点:在无消息的情况下不会频繁的请求,耗费资小。
缺点:服务器hold连接会消耗资源,返回数据顺序无保证,难于管理维护。 Comet异步的ashx,
实例:WebQQ、Hi网页版、Facebook IM。


9、vuex的作用?



在使用库或框架时,需要注意一个「适用性」的问题。
Vuex 或者说实现了 Flux 思想的库,解决了几个问题:

组件之间的数据通信
使用单向数据流的方式进行数据的中心化管理
为什么要解决这样的问题呢?其实是因为当程序逻辑过于复杂的时候,非中心化的数据管理会让整个 app 的逻辑非常混乱。
举一个不使用中心化的数据管理机制的具体例子:

一个 app ,有四个 tab,每个 tab 都需要读取用户的资料。如果数据在每个 tab 的控制器里(或者说组件里)都存了一份,那么在用户手动更新了用户资料之后,就需要在每一个 tab 里都更新一遍用户资料,才能保证用户看到的永远是最新的资料。
如你问题里所说,我每进一个 tab 的时候重新请求一下不就好了吗?
这样的解决方案不是不可以,但弊端也非常明显:

  1. 对于服务器端来说,频繁的请求是非常占用资源的,如果你的 app 用户足够多,那么每多出一个请求,对公司来说,都是一大笔钱。如果数据存在了 store 中,并且所有的 tab 都读取同一份数据,在用户更新资料时,在前端更新了 store 中的数据,是不是在切换 tab 时就减少了四个请求呢?
  2. 对于前端开发者来说,如果你的项目足够复杂,团队的规模也不仅是一个人,那么前端代码就会因为数据分散管理而产生非常严重的性能和稳定性的隐患(比如你的同事觉得进入模块就刷新用户资料太慢了,手贱把刷新的代码删了,你又没发现)。
    https://segmentfault.com/q/1010000011402824

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



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


11、axios的作用?



在浏览器中发送 XMLHttpRequests 请求
在 node.js 中发送 http请求
支持 Promise API
拦截请求和响应
转换请求和响应数据
自动转换 JSON 数据
客户端支持保护安全免受 XSRF 攻击


12、列举vue的常见指令。



条件判断使用 v-if指令
循环使用 v-for 指令。
事件监听可以使用 v-on 指令:


14、简述jsonp及实现原理?



JSONP是用来解决跨域请求问题的
跨域:协议 域名 端口号有一个不一样就是跨域
实现原理:
script标签src属性中的链接却可以访问跨域的js脚本,利用这个特性,服务端不再返回JSON格式的数据,而是返回一段调用某个函数的js代码,在src中进行了调用,这样实现了跨域。


14、是什么cors ?



CORS 全称是跨域资源共享(Cross-Origin Resource Sharing),是一种 AJAX 跨域请求资源的方式,支持现代浏览器,IE支持10以上。


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



GET:请求获取由 Request-URI 所标识的资源。
POST:在 Request-URI 所标识的资源后附加新的数据。
HEAD:请求获取由 Request-URI 所标识的资源的响应消息报头。
OPTIONS:请求查询服务器的性能,或查询与资源相关的选项和需求。
PUT:请求服务器存储一个资源,并用 Request-URI作为其标识。
DELETE:请求服务器删除由 Request-URI所标识的资源。
TRACE:请求服务器回送收到的请求信息,主要用语测试或诊断。
CONNECT:HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。

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



常见的响应状态码有以下几种,在各种下面分别列几个常见的状态码:
1开头(信息)
2开头(成功)
200(OK):请求成功
202(Accepted):已接受请求,尚未处理
204(No Content):请求成功,且不需返回内容
3开头(重定向)
301(Moved Permanently):被请求的资源已永久移动到新位置
301(Moved Temporarily):被请求的资源已临时移动到新位置
4开头(客户端错误)
400(Bad Request):请求的语义或是参数有错
403(Forbidden):服务器拒绝了请求
404(Not Found):未找到请求的资源
5开头(服务器错误)
500(Internal Server Error):服务器遇到错误,无法完成请求
502(Bad Getway):网关错误,一般是服务器压力过大导致连接超时
503(Service Unavailable):服务器宕机


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



User-Agent:浏览器类型,如果Servlet返回的内容与浏览器类型有关则该值非常有用。
Cookie:这是最重要的请求头信息之一
Content-Type:请求类型


18、求结果




**alter(Gkate)**  
 19、求结果




**console.log(Twiss)**  
 20、




**console.log(‘Iran’)**  
 21、




**undefine**  
 22、




**alter(‘Gkate’)**  
 23、



var name =‘twiss’
function foo(){
this.name = ‘Gkate’
this.func = function(){
(function(){
alter(this.name)
})
}
}
var obj = new foo();
obj.func();


**alter(Gkate)**  
 24、django、flask、tornado框架的比较?



Django:Python 界最全能的 web 开发框架,battery-include 各种功能完备,可维护性和开发速度一级棒。常有人说 Django 慢,其实主要慢在 Django ORM 与数据库的交互上,所以是否选用 Django,取决于项目对数据库交互的要求以及各种优化。而对于 Django 的同步特性导致吞吐量小的问题,其实可以通过 Celery 等解决,倒不是一个根本问题。Django 的项目代表:Instagram,Guardian。

Tornado:天生异步,性能强悍是 Tornado 的名片,然而 Tornado 相比 Django 是较为原始的框架,诸多内容需要自己去处理。当然,随着项目越来越大,框架能够提供的功能占比越来越小,更多的内容需要团队自己去实现,而大项目往往需要性能的保证,这时候 Tornado 就是比较好的选择。Tornado项目代表:知乎。

Flask:微框架的典范,号称 Python 代码写得最好的项目之一。Flask 的灵活性,也是双刃剑:能用好 Flask 的,可以做成 Pinterest,用不好就是灾难(显然对任何框架都是这样)。Flask 虽然是微框架,但是也可以做成规模化的 Flask。加上 Flask 可以自由选择自己的数据库交互组件(通常是 Flask-SQLAlchemy),而且加上 celery +redis 等异步特性以后,Flask 的性能相对 Tornado 也不逞多让,也许Flask 的灵活性可能是某些团队更需要的。


25、什么是wsgi?



WSGI(Web Server Gateway Interface,Web 服务器网关接口)则是Python语言中1所定义的Web服务器和Web应用程序之间或框架之间的通用接口标准。
WSGI就是一座桥梁,桥梁的一端称为服务端或网关端,另一端称为应用端或者框架端,WSGI的作用就是在协议之间进行转化。WSGI将Web组件分成了三类:Web 服务器(WSGI Server)、Web中间件(WSGI Middleware)与Web应用程序(WSGI Application)。
Web Server接收HTTP请求,封装一系列环境变量,按照WSGI接口标准调用注册的WSGI Application,最后将响应返回给客户端。


26、django请求的生命周期?



前端请求—>nginx—>uwsgi.—>中间件—>url路由—->view试图—>orm—->拿到数据返回给view—->试图将数据渲染到模版中拿到字符串—->中间件—>uwsgi—->nginx—->前端渲染


27、列举django的内置组件?



url 、view、model、template、中间件


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



process_request(self,request)
process_view(self, request, callback, callback_args, callback_kwargs)
process_exception(self, request, exception)
process_response(self, request, response)
1 请求先执行所有中间件的process_request,然后做路由匹配,找到函数不执行。
2 再执行所有的process_view,在执行视图函数。
3 再执行process_response
4 如果程序报错执行process_exception
5 如果程序有render方法则执行process_template_response


29、简述什么是FBV和CBV?



1 FBV方式请求的过程
用户发送url请求,Django会依次遍历路由映射表中的所有记录,一旦路由映射表其中的一条匹配成功了,
就执行视图函数中对应的函数名,这是fbv的执行流程

2 CBV方式请求的过程
当服务端使用CBV模式的时候,用户发给服务端的请求包含url和method,这两个信息都是字符串类型

服务端通过路由映射表匹配成功后会自动去找dispatch方法,然后Django会通过dispatch反射的方式找到类中对应的方法并执行

类中的方法执行完毕之后,会把客户端想要的数据返回给dispatch方法,由dispatch方法把数据返回经客户端

把上面的例子中的视图函数修改成如下:
from django.views import View

class CBV(View):
def dispatch(self, request, *args, **kwargs):
print(“dispatch…”)
res=super(CBV,self).dispatch(request,*args,**kwargs)
return res

  def get(self,request):
      return render(request, "cbv.html")

  def post(self,request):
      return HttpResponse("cbv.get")

3 FBV和CBV的区别?
- 没什么区别,因为他们的本质都是函数。CBV的.as_view()返回的view函数,view函数中调用类的dispatch方法,在dispatch方法中通过反射执行get/post/delete/put等方法。
- CBV比较简洁,GET/POST等业务功能分别放在不同get/post函数中。FBV自己做判断进行区分。


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



当请求一个页面时,Django会建立一个包含请求元数据的 HttpRequest 对象。 当Django 加载对应的视图时,HttpRequest 对象将作为视图函数的第一个参数。每个视图会返回一个HttpResponse 对象。


31、如何给CBV的程序添加装饰器?



  • 装饰器
    from django.views import View
    from django.utils.decorators import method_decorator

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

class UserView(View):
@method_decorator(auth)
def get(self,request,*args,**kwargs):
return HttpResponse(‘…’)

  • csrf的装饰器要加到dispath
    from django.views import View
    from django.utils.decorators import method_decorator
    from django.views.decorators.csrf import csrf_exempt,csrf_protect

    class UserView(View):
    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
    return HttpResponse(‘…’)


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

  @method_decorator(csrf_exempt,name='dispatch')
  class UserView(View):
      def dispatch(self, request, *args, **kwargs):
          return HttpResponse('...')

32、列举django orm 中所有的方法(QuerySet对象的所有方法)



返回Query Set对象的方法有:

  • all()
  • filter()
  • exclude()
  • order_by()
  • reverse()
  • dictinct()

特殊的QuerySet:

  • values() 返回一个可迭代的字典序列
  • values_list() 返回一个可迭代的元祖序列

返回具体对象的:

  • get()
  • first()
  • last()

返回布尔值的方法有:

  • existe()

返回数学的方法有:

  • count( )

33、only和defer的区别?



defer : 映射中排除某列数据
only : 仅取某个列中的数据


34、select\_related和prefetch\_related的区别?



select_related通过多表join关联查询,一次性获得所有数据,通过降低数据库查询次数来提升性能,但关联表不能太多,因为join操作本来就比较消耗性能
prefetch_related()的解决方法是,分别查询每个表,然后用Python处理他们之间的关系!
都是为了减少SQL查询的数量
title = models.CharField(max_length=32)

class UserInfo(models.Model):
name = models.CharField(max_length=32)
email = models.CharField(max_length=32)
ut = models.ForeignKey(to=‘UserType’)
ut = models.ForeignKey(to=‘UserType’)
ut = models.ForeignKey(to=‘UserType’)
ut = models.ForeignKey(to=‘UserType’)

1次SQL

select * from userinfo

objs = UserInfo.obejcts.all()
for item in objs:
print(item.name)

n+1次SQL

select * from userinfo

objs = UserInfo.obejcts.all()
for item in objs:
# select * from usertype where id = item.id
print(item.name,item.ut.title)

示例1:
.select_related()
# 1次SQL
# select * from userinfo inner join usertype on userinfo.ut_id = usertype.id
objs = UserInfo.obejcts.all().select_related(‘ut’)
for item in objs:
print(item.name,item.ut.title)
示例2:
.prefetch_related()
# select * from userinfo where id <= 8
# 计算:[1,2]
# select * from usertype where id in [1,2]
objs = UserInfo.obejcts.filter(id__lte=8).prefetch_related(‘ut’)
for obj in objs:
print(obj.name,obj.ut.title)
两个函数的作用都是减少查询次数


35、filter和exclude的区别?



filter是查询满足条件的数据
exclude是查询不满足添加的数据


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



1.使用execute执行自定义SQL

from django.db import connection, connections

cursor = connection.cursor() # cursor = connections[‘default’].cursor()

cursor.execute(“”“SELECT * from auth_user where id = %s”“”, [1])

row = cursor.fetchone()

2.使用extra方法

extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)

Entry.objects.extra(select={‘new_id’: “select col from sometable where othercol > %s”}, select_params=(1,))

Entry.objects.extra(where=[‘headline=%s’], params=[‘Lennon’])

Entry.objects.extra(where=[“foo=‘a’ OR bar = ‘a’”, “baz = ‘a’”])

Entry.objects.extra(select={‘new_id’: “select id from tb where id > %s”}, select_params=(1,), order_by=[‘-nid’])

3.使用raw方法

解释:执行原始sql并返回模型

说明:依赖model多用于查询

用法:

book = Book.objects.raw(“select * from hello_book”)

for item in book:

print(item.title)


37、django orm 中如何设置读写分离?



class Router1:
def allow_migrate(self, db, app_label, model_name=None, **hints):
“”"
All non-auth models end up in this pool.
“”"
if db==‘db1’ and app_label == ‘app02’:
return True
elif db == ‘default’ and app_label == ‘app01’:
return True
else:
return False

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

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

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

38、F和Q的作用?



F:操作数据表中的某列值,F( )允许Django在未实际链接数据的情况下具有对数据库字段的值的引用,不用获取对象放在内存中再对字段进行操作,直接执行原生产sql语句操作。

通常情况下我们在更新数据时需要先从数据库里将原数据取出后方在内存里,然后编辑某些属性,最后提交

Q:对对象进行复杂查询,并支持&(and),|(or),~(not)操作符。
F:
Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。
修改操作也可以使用F函数,比如将每一本书的价格提高30元

例:把所有书名后面加上(第一版)
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.all().update(title=Concat(F(“title”), Value(“(”), Value(“第一版”), Value(“)”)))
Q:
Q(条件1) | Q(条件2) 或
Q(条件1) & Q(条件2) 且
Q(条件1) & ~Q(条件2) 非


39、values和values\_list的区别?



values方法可以获取number字段的字典列表。
values_list可以获取number的元组列表。
values_list方法加个参数flat=True可以获取number的值列表。


40、如何使用django orm批量创建数据?



def bulk_create(self, objs, batch_size=None):
# 批量插入
# batch_size表示一次插入的个数
objs = [
models.DDD(name=‘r11’),
models.DDD(name=‘r22’)
]
models.DDD.objects.bulk_create(objs, 10)


41、django的Form和ModeForm的作用?



  • 作用:
    - 对用户请求数据格式进行校验
    - 自动生成HTML标签
    • 区别:
      • Form,字段需要自己手写。
        class Form(Form):
        xx = fields.CharField(.)
        xx = fields.CharField(.)
        xx = fields.CharField(.)
        xx = fields.CharField(.)
      • ModelForm,可以通过Meta进行定义
        class MForm(ModelForm):
        class Meta:
        fields = “all
        model = UserInfo
    • 应用:只要是客户端向服务端发送表单数据时,都可以进行使用,如:用户登录注册

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



方式一:重写构造方法,在构造方法中重新去数据库获取值
class UserForm(Form):
name = fields.CharField(label=‘用户名’,max_length=32)
email = fields.EmailField(label=‘邮箱’)
ut_id = fields.ChoiceField(
# choices=[(1,‘二B用户’),(2,‘山炮用户’)]
choices=[]
)

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

      self.fields['ut_id'].choices = models.UserType.objects.all().values_list('id','title')

方式二: ModelChoiceField字段
from django.forms import Form
from django.forms import fields
from django.forms.models import ModelChoiceField
class UserForm(Form):
name = fields.CharField(label=‘用户名’,max_length=32)
email = fields.EmailField(label=‘邮箱’)
ut_id = ModelChoiceField(queryset=models.UserType.objects.all())

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

      def __str__(self):
          return self.title

43、django的Model中的ForeignKey字段中的on\_delete参数有什么作用?



on_delete有CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET()五个可选择的值
CASCADE:此值设置,是级联删除。

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

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

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

SET():此值设置,会调用外面的值,可以是一个函数。


44、django中csrf的实现机制?



Django预防CSRF攻击的方法是在用户提交的表单中加入一个csrftoken的隐含值,这个值和服务器中保存的csrftoken的值相同,这样做的原理如下:

1、在用户访问django的可信站点时,django反馈给用户的表单中有一个隐含字段csrftoken,这个值是在服务器端随机生成的,每一次提交表单都会生成不同的值

2、当用户提交django的表单时,服务器校验这个表单的csrftoken是否和自己保存的一致,来判断用户的合法性

3、当用户被csrf攻击从其他站点发送精心编制的攻击请求时,由于其他站点不可能知道隐藏的csrftoken字段的信息这样在服务器端就会校验失败,攻击被成功防御

具体配置如下:

template中添加{%csrf_token%}标签


45、django如何实现websocket?  
 <https://www.cnblogs.com/huguodong/p/6611602.html>  
 46、基于django使用ajax发送post请求时,都可以使用哪种方法携带csrf token?



方法一:

方法二:
//模板页面中必须要有 {% csrf_token %}

方法三:

//必须先引入它

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



在settings.py中添加:
LOGGING = {
‘disable_existing_loggers’: False,
‘version’: 1,
‘handlers’: {
‘console’: {
# logging handler that outputs log messages to terminal
‘class’: ‘logging.StreamHandler’,
‘level’: ‘DEBUG’, # message level to be written to console
},
},
‘loggers’: {
‘’: {
# this sets root level logger to log debug and higher level
# logs to console. All other loggers inherit settings from
# root level logger.
‘handlers’: [‘console’],
‘level’: ‘DEBUG’,
‘propagate’: False, # this tells logger to send logging message
# to its parent (will send if set to True)
},
‘django.db’: {
# # django also has database level logging
‘handlers’: [‘console’],
‘level’: ‘DEBUG’,
‘propagate’: False,
},
},
}


48、django缓存如何设置?



三种粒度缓存

1 中间件级别
‘django.middleware.cache.UpdateCacheMiddleware’,
‘django.middleware.cache.FetchFromCacheMiddleware’,
CACHE_MIDDLEWARE_SECONDS=10

2 视图级别

  from django.views.decorators.cache import cache_page
  @cache_page(15)
  def index(request):
      import time
      t=time.time()
      return render(request,"index.html",locals())

3 局部缓存
{% load cache %}


{% cache 15 “time_cache” %}

缓存时间:{{ t }}


{% endcache %}


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



pip install django-redis
apt-get install redis-server

然后在settings.py 里面添加CACHES = {
‘default’: {
‘BACKEND’: ‘redis_cache.cache.RedisCache’,
‘LOCATION’: ‘127.0.0.1:6379’,
“OPTIONS”: {
“CLIENT_CLASS”: “redis_cache.client.DefaultClient”,
},
}
在类中引用
conn = get_redis_connection(“default”)


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



name 可以用于在 templates, models, views ……中得到对应的网址,相当于“给网址取了个小名”,只要这个名字不变,网址变了也能通过名字获取到。


51、django的模板中filter和simple\_tag的区别?



simple_tag
  -参数任意,但是不能作为if条件判断的条件
filter
  -参数最多只能有两个,但是可以作为if条件判断的条件。


52、django-debug-toolbar的作用?



django_debug_toolbar 是django的第三方工具包,给django扩展了调试功能。
包括查看执行的sql语句,db查询次数,request,headers,调试概览等。


<https://blog.csdn.net/weixin_39198406/article/details/78821677>  
 53、django中如何实现单元测试?



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


<https://www.jianshu.com/p/34267dd79ad6>  
 54、解释orm中 db first 和 code first的含义?



datebase first就是代表数据库优先,那么前提就是先创建数据库。
model first就是代表model优先,那么前提也就是先创建model,然后根据model自动建立数据库。


55、django中如何根据数据库表生成model中的类?


<https://jingyan.baidu.com/article/4ae03de3e513d23eff9e6bb7.html>


56、使用orm和原生sql的优缺点?



ORM框架:

对象关系映射,通过创建一个类,这个类与数据库的表相对应!类的对象代指数据库中的一行数据。

简述ORM原理:

让用户不再写SQL语句,而是通过类以及对象的方式,和其内部提供的方法,进行数据库操作!把用户输入的类或对象转换成SQL语句,转换之后通过pymysql执行完成数据库的操作。

ORM的优缺点:

优点:

  • 提高开发效率,降低开发成本
  • 使开发更加对象化
  • 可移植
  • 可以很方便地引入数据缓存之类的附加功能

缺点:

  • 在处理多表联查、where条件复杂之类的查询时,ORM的语法会变得复杂。就需要写入原生SQL。

57、简述MVC和MTV



MVC: 模型 视图 控制器
MTV: 模型 模板 视图


58、django的contenttype组件的作用?



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

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

59、谈谈你对restfull 规范的认识?



  • restful其实就是一套编写接口的协议,协议规定如何编写以及如何设置返回值、状态码等信息。
    • 最显著的特点:
      restful: 给用户一个url,根据method不同在后端做不同的处理,比如:post 创建数据、get获取数据、put和patch修改数据、delete删除数据。
      no rest: 给调用者很多url,每个url代表一个功能,比如:add_user/delte_user/edit_user/
    • 当然,还有协议其他的,比如:
      • 版本,来控制让程序有多个版本共存的情况,版本可以放在 url、请求头(accept/自定义)、GET参数
      • 状态码,200/300/400/500
      • url中尽量使用名词,restful也可以称为“面向资源编程”
      • api标示:
        api.YueNet.com
        www.YueNet.com/api/

    • https

    • 域名

      • api.twiss.com
      • www.twiss.com/api
    • 版本:

      • www.twiss.com/api/v1
    • URL资源,名词

      • www.twiss.com/api/v1/student
    • 请求方式:

      • GET/POST/PUT/DELETE/PATCH/OPTIONS/HEADERS/TRACE
    • 返回值:

      • www.twiss.com/api/v1/student/ -> 结果集
      • www.twiss.com/api/v1/student/1/ -> 单个对象
    • URL添加条件

      • www.twiss.com/api/v1/student?page=11&size=9
    • 状态码:

      • 200
      • 300
        • 301
        • 302
      • 400
        • 403
        • 404
      • 500
    • 错误信息
      {
      code:1000,
      meg:‘xxxx’
      }

    • hyperlink
      {
      id:1
      name: ‘xiangl’,
      type: http://www.xxx.com/api/v1/type/1/
      }


60、接口的幂等性是什么意思?



一个接口通过首先进行1次访问,然后对该接口进行N次相同访问的时候,对访问对象不造成影响,那么就认为接口具有幂等性。
比如:
GET, 第一次获取数据、第二次也是获取结果,幂等。
POST, 第一次新增数据,第二次也会再次新增,非幂等。
PUT, 第一次更新数据,第二次不会再次更新,幂等。
PATCH,第一次更新数据,第二次可能再次更新,非幂等。
DELTE,第一次删除数据,第二次不会再次删除,幂等。


61、什么是RPC?



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


62、Http和Https的区别?



超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此,HTTP协议不适合传输一些敏感信息,比如:信用卡号、密码等支付信息。

为了解决HTTP协议的这一缺陷,需要使用另一种协议:安全套接字层超文本传输协议HTTPS,为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。


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



1.客户端-服务端分离

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

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

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

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

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

4.统一接口

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

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

优点:提高可扩展性


64、django rest framework框架中都有那些组件?



 - 路由,自动帮助开发者快速为一个视图创建4个url
        www.gkate.com/api/v1/student/$
        www.gkate.com/api/v1/student(?P<format>\w+)$
        
        www.gkate.com/api/v1/student/(?P<pk>\d+)/$
        www.gkate.com/api/v1/student/(?P<pk>\d+)(?P<format>\w+)$
        
- 版本处理
    - 问题:版本都可以放在那里?
            - url
            - GET 
            - 请求头 
- 认证 
    - 问题:认证流程?

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

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

最后

不知道你们用的什么环境,我一般都是用的Python3.6环境和pycharm解释器,没有软件,或者没有资料,没人解答问题,都可以免费领取(包括今天的代码),过几天我还会做个视频教程出来,有需要也可以领取~

给大家准备的学习资料包括但不限于:

Python 环境、pycharm编辑器/永久激活/翻译插件

python 零基础视频教程

Python 界面开发实战教程

Python 爬虫实战教程

Python 数据分析实战教程

python 游戏开发实战教程

Python 电子书100本

Python 学习路线规划

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值