面试题
1 Python字符串格式化中,%s和.format的主要区别是什么?
1.1、匿名tuple(推荐在参数少时用)
python用一个tuple将多个值传递给模板,每个值对应一个格式符。print ("I'm %s.I'm %d year old" % ('Vamei',99)) #引号内的为模板 连接模板和tuple的"%"为格式化操作符#或者将整个字符串表达式赋值给a,再输出a.a="I'm %s.I'm %d year old" % ('Vamei',99)print (a)
2.字符串格式化(format)(不需要指定字符串还是数字类型)
自python2.6开始,新增了一种格式化字符串的函数str.format(),通过{ }和 . 来代替传统%
2.1位置参数
print ('my name is {},age is {}'.format('hoho',18))print ('my name is {1},age is {0}'.format(18,'hoho'))li=['hoho',18]print ('my name is {1},age is {0}'.format(*li))
2.2 关键字参数
hash={'name':'hoho','age':18}print 'my name is {name},age is {age}'.format(**hash)print 'my name is {name},age is {age}'.format(name='hoho',age=18)
主要区别:不需要指定字符串还是数字类型
- 现有两元组,(('a'),('b')), (('c'),('d')) 请用匿名函数将其变为[{'a': 'c'}, {'b': 'd'}]
res = lambda t1,t2:[{i:j} for i,j in zip(t1,t2)]print(res(t1,t2))
- 请给出二分法查找的python示例代码
def func(l,aim): mid = (len(l)-1)//2 print('mid===>',mid) if l: if aim > l[mid]: func(l[mid+1:],aim) elif aim< l[mid]: func(l[:mid],aim) elif aim == l[mid]: print('There you are',l[mid]) else: print('No match')func(l,88)
- 如何给列表去重并保持原先顺序不变。 示例一(简单粗暴):
l = [11,2,3,4,5,6,7,2,3,4]new_l = []for i in l: if i not in new_l: new_l.append(i)print(new_l)
- 示例说明args和*kwargs 的作用
多个实参,放到一个元组里面,以开头,可以传多个参数;*是形参中按照关键字传值把多余的传值以字典的方式呈现
*args:(表示的就是将实参中按照位置传值,多出来的值都给args,且以元祖的方式呈现)
**kwargs:(表示的就是形参中按照关键字传值把多余的传值以字典的方式呈现)
- 解释一下什么是匿名函数,它有什么好处?
匿名lambda x,y,z=1:x+y+z #与函数有相同的作用域,但是匿名意味着引用计数为0,使用一次就释放,除非让其有名字func=lambda x,y,z=1:x+y+z func(1,2,3)#让其有名字就没有意义
好处:一次性使用,随时随地定义。
更易读,因为那个映射到列表上的函数具体是要做什么,非常一目了然。- Python中如何书写可变参数和关键字参数?
在Python中定义函数,可以用必选参数、默认参数、可变参数和关键字参数,这4种参数都可以一起使用,或者只用其中某些,但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数和关键字参数。
详情请见链接:
- Python 模块中的match 和 search的区别
re.match() 总是从字符串“开头”去匹配,并返回匹配的字符串的match对象。所以当我用re.match()函数去匹配字符串非开头部分的字符串时,会返回NONE。
re.search()函数将对整个字符串进行搜索,并返回第一个匹配的字符串的match对象。- 1 and 2 和 1 or 2 的输出结果分别是什么?为什么?
python 中的and从左到右计算表达式,若所有值均为真,则返回最后一个值,若存在假,返回第一个假值。
1 or 2 是因为 1 是非零 所以返回的值是1.
- 写出一下打印结果
print((i%2 for i in range(10))) #at 0x000001C577DDE258>print([i%2 for i in range(10)]) #[0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
总结:
1.把列表解析的[]换成()得到的就是生成器表达式
2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存
3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议。
-
python2 和 Python3 有哪些显著的区别?
. 在 Python3 中 print要加括号。 .Python3 中,数字除法将会带小数点。 .字符编码。image.png
详情:
英文网: 中文网:-
请描述 unicode,utf-8, gbk之间的关系。
unicode----->encode-------->utf-8
utf-8-------->decode---------->unicode
-
迭代器,生成器,装饰器
迭代器
#迭代器即迭代的工具,那什么是迭代呢?#迭代是一个重复的过程,每次重复即一次迭代,并且每次迭代的结果都是下一次迭代的初始值while True: #只是单纯地重复,因而不是迭代 print('===>') l=[1,2,3]count=0while count < len(l): #迭代 print(l[count]) count+=1
为何要有迭代器?什么是可迭代对象?什么是迭代器对象?
#1、为何要有迭代器?对于序列类型:字符串、列表、元组,我们可以使用索引的方式迭代取出其包含的元素。但对于字典、集合、文件等类型是没有索引的,若还想取出其内部包含的元素,则必须找出一种不依赖于索引的迭代方式,这就是迭代器#2、什么是可迭代对象?可迭代对象指的是内置有__iter__方法的对象,即obj.__iter__,如下'hello'.__iter__(1,2,3).__iter__[1,2,3].__iter__{'a':1}.__iter__{'a','b'}.__iter__open('a.txt').__iter__#3、什么是迭代器对象?可迭代对象执行obj.__iter__()得到的结果就是迭代器对象而迭代器对象指的是即内置有__iter__又内置有__next__方法的对象文件类型是迭代器对象open('a.txt').__iter__()open('a.txt').__next__()#4、注意:迭代器对象一定是可迭代对象,而可迭代对象不一定是迭代器对象
迭代器对象的使用
dic={'a':1,'b':2,'c':3}iter_dic=dic.__iter__() #得到迭代器对象,迭代器对象即有__iter__又有__next__,但是:迭代器.__iter__()得到的仍然是迭代器本身iter_dic.__iter__() is iter_dic #Trueprint(iter_dic.__next__()) #等同于next(iter_dic)print(iter_dic.__next__()) #等同于next(iter_dic)print(iter_dic.__next__()) #等同于next(iter_dic)# print(iter_dic.__next__()) #抛出异常StopIteration,或者说结束标志#有了迭代器,我们就可以不依赖索引迭代取值了iter_dic=dic.__iter__()while 1: try: k=next(iter_dic) print(dic[k]) except StopIteration: break
迭代器优缺点
#优点: - 提供一种统一的、不依赖于索引的迭代方式 - 惰性计算,节省内存#缺点: - 无法获取长度(只有在next完毕才知道到底有几个值) - 一次性的,只能往后走,不能往前退
生成器
我们知道的迭代器有两种:一种是调用方法直接返回的,一种是可迭代对象通过执行iter方法得到的,迭代器有的好处是可以节省内存。
如果在某些情况下,我们也需要节省内存,就只能自己写。我们自己写的这个能实现迭代器功能的东西就叫生成器。
Python中提供的生成器:
1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行
2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表
生成器Generator: 本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现) 特点:惰性运算,开发者自定义
生成器函数:
一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。#只要函数内部包含有yield关键字,那么函数名()的到的结果就是生成器,并且不会执行函数内部代码def func(): print('====>first') yield 1 print('====>second') yield 2 print('====>third') yield 3 print('====>end')g=func() print(g) #
迭代器,生成器详情请见:
装饰器
#开放封闭原则:对修改封闭,对扩展开放
装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式 装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能- def func(a,b=[]) 这样的写法有什么陷阱? Python函数在定义的时候,默认参数b的值就被计算出来了,即[],因为默认参数b也是一个变量,它指向对象[],每次调用该函数,如果改变了b的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。
所以,定义默认参数要牢记一点:默认参数必须指向不变对象!
- python 实现九九乘法表 两种方式? 方式一:
for i in range(1,10): for j in range(1,i+1): print('%s * %s = %s '%(i,j,i*j), end=' ') print(' ')
方式二:
print( '\n'.join([' '.join(['%s*%s=%-2s' % (y,x,x*y) for y in range(1,x+1)]) for x in range(1,10)]))
- 如何在Python中拷贝一个对象,并说出他们的区别。 拷贝的方法有两种:深拷贝和浅拷贝 copy.copy() and copy.deepcopy(). 区别,官网链接:
—–我们寻常意义的复制就是深复制,即将被复制对象完全再复制一遍作为独立的新个体单独存在。所以改变原有被复制对象不会对已经复制出来的新对象产生影响。
—–而浅复制并不会产生一个独立的对象单独存在,他只是将原有的数据块打上一个新标签,所以当其中一个标签被改变的时候,数据块就会发生变化,另一个标签也会随之改变。这就和我们寻常意义上的复制有所不同了。
- 谈谈你对Python装饰器的理解。 装饰器本质上是一个Python的函数,他可以让其他函数在不需要任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它有很多应用场景,比如:插入日志,事务处理,缓存,权限等。概括的总结:装饰器的作用就是为已经存在的对象添加额外的功能。
def outer(func): def inner(*args,**kwargs): ''' before the decorator :param args: :param kwargs: :return: ''' ret = func(*args,**kwargs) ''' after the decorator ''' return ret return inner@outerdef bar(): print('from bar')bar()
- Python基础: 计算列表中元素的个数和向末尾追加元素所用的方法? len(), append().
判断字典中有没有某个key的方法? 用get('key')方法,若没有, 返回值是None
现有my_list = range(100)
#取前三个元素print(my_list[0:4])#取倒数第二个元素print(my_list[-2])#取最后十个元素print(my_list[-10:])
- 简述Python中的垃圾回收机制。 官网链接:
Python在内存中存储了每个对象的引用计数(reference count)。如果计数值变成0,那么相应的对象就会小时,分配给该对象的内存就会释放出来用作他用。
偶尔也会出现引用循环(reference cycle)。垃圾回收器会定时寻找这个循环,并将其回收。举个例子,假设有两个对象o1和o2,而且符合o1.x == o2和o2.x == o1这两个条件。如果o1和o2没有其他代码引用,那么它们就不应该继续存在。但它们的引用计数都是1。 Python中使用了某些启发式算法(heuristics)来加速垃圾回收。例如,越晚创建的对象更有可能被回收。对象被创建之后,垃圾回收器会分配它们所属的代(generation)。每个对象都会被分配一个代,而被分配更年轻代的对象是优先被处理的。- Python的名称空间问题:
def scope_test(): def do_local(): spam = "local spam" def do_nonlocal(): nonlocal spam spam = "nonlocal spam" def do_global(): global spam spam = "global spam" spam = "test spam" do_local() print("After local assignment:", spam) do_nonlocal() print("After nonlocal assignment:", spam) do_global() print("After global assignment:", spam)scope_test()print("In global scope:", spam)
打印结果
After local assignment: test spamAfter nonlocal assignment: nonlocal spamAfter global assignment: nonlocal spamIn global scope: global spam
- 如何判断一个变量是否是字符串?
a = 'sdsdf'print(isinstance(a,str))
-
Differences between list and tuple in python.
link: -
range 和 xrange的区别
首先,xrange在python3中已经不适用。
range: 函数说明:range([start,] stop[, step]),根据start与stop指定的范围以及step设定的步长,生成一个列表。 xrange: xrange与range类似,只是返回的是一个“xrange object”对象,而非数组list。要生成很大的数字序列的时候,用xrange会比range性能优很多,因为不需要一上来就开辟一块很大的内存空间,这两个基本上都是在循环的时候用。 区别: range 会生成一个list对象,而xrange会返回一个生成器对象。- '1','2','3' 如何 变成 ['1','2','3']?
x = '1','2','3'li = []for i in x: li.append(i)print(li)
'1','2','3' 如何 变成 [1,2,3]
x = '1','2','3'li = []for i in x: li.append(int(i))print(li)
- is 和 == 的区别
Python中的对象包含三要素:id、type、value
其中id用来唯一标识一个对象,type标识对象的类型,value是对象的值 is判断的是a对象是否就是b对象,是通过id来判断的 ==判断的是a对象的值是否和b对象的值相等,是通过value来判断的- 一行实现[1,4,9,16,25,36,49,81,100]
target = list(map(lambda x: x*x,[1,2,3,4,5,6,7,8,9,10]))
- print(map(str,[1,2,3,4])) 输入的是啥?
map object
- PEP8开发规范:
- 请简单解释Python中的 staticmethod(静态方法)和 classmethod(类方法),并补全下面的代码
方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。
普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;
类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls; 静态方法:由类调用;无默认参数;class A(object): def foo(self,x): print('executing foo(%s,%s)'%(self,x)) @classmethod def class_foo(cls,x): print('executing class_foo(%s,%s)'%(cls,x)) @staticmethod def static_foo(x): print('executing static_foo(%s)'%x)a = A()#调用foo函数,参数传入1a.foo(1)#调用class_foo函数,参数传入1a.class_foo(1)A.class_foo(1)#调用static_foo函数,参数传入1a.static_foo(1)A.static_foo(1)
30、Python如何实现单例模式?
1 基于类 注意: 加锁,否则多线程模式会报错import time,threadingclass Foo(object): lock = threading.Lock() def __init__(self): time.sleep(1) @classmethod def instance(cls,*args,**kwargs): if not hasattr(cls,'_instance'): with Foo.lock: if not hasattr(cls,'_instance'): obj = cls(*args,**kwargs) setattr(cls,'_instance',obj) return cls._instancedef func(arg): obj = Foo.instance() print(obj)for i in range(10): t = threading.Thread(target=func,args=(i,)) t.start()
2 . 基于new方法,也要加锁,原理同上
import threading,timeclass Singleton(object): lock = threading.Lock() def __init__(self): time.sleep(1) def __new__(cls, *args, **kwargs): if not hasattr(cls,'_instance'): with Singleton.lock: if not hasattr(cls,'_instance'): Singleton._instance = object.__new__(cls,*args,**kwargs) return Singleton._instancedef task(args): obj = Singleton() print(obj)for i in range(10): t = threading.Thread(target=task,args=(i,)) t.start()
- 基于metaclass 加锁,原理同上
import threadingclass SingletonType(type): lock = threading.Lock() def __call__(cls, *args, **kwargs): if not hasattr(cls,'_instance'): with SingletonType.lock: if not hasattr(cls,'_instance'): cls._instance = super(SingletonType, cls).__call__(*args,**kwargs) return cls._instanceclass Foo(metaclass=SingletonType): def __init__(self): passobj = Foo()obj2 = Foo()
31、请写出一段代码去除list里面的重复元素
法一:print(list(set(li)))法二:for i in li: if li.count(i)>1: li.remove(i)print(li)
32、如何用Python删除一个文件?
import osos.remove(r'D:\ggg\fileobj')os.remove('路径')
- 面相对象
class Person: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def __hash__(self): return hash(self.name+self.sex) def __eq__(self, other): if self.name == other.name and self.sex == other.sex:return Truep_lst = []for i in range(84): p_lst.append(Person('egon',i,'male'))print(p_lst) ####每一个Person对象的内存地址,打印在一个列表里。print(set(p_lst)) ######一个Person对象的内存地址 {<__main__.Person object at 0x000002A1C8566A58>}
34、Python如何生成随机数
import randomprint(random.randint(1,10))
35、如何在一个function里面设置一个全局的变量
n = 1def func(): global n ##声明n是全局变量 n = 2 print('inside the function',n) # n = 2print('outside the funciton',n) #调func之前,n=1func()print(n) #调func之后,n的值被修改为2
36、介绍except的用法和作用
答案: 37、 请用Python写一个获取用户输入数字,并根据数字大小输出不同信息的脚本while 1: digit_input = int(input('Please enter a integer: ').strip()) if not digit_input: continue else: if digit_input>0: print('This is a positive number') elif digit_input == 0: print('This is a zero') elif digit_input <0: print('This is a negative number')
38、请解释生成器与函数的不同,并实现和简单地使用生成器。
先看生成器:
def gensquares(N): for i in range(N): yield i **2for item in gensquares(5): print(item)
再看普通函数:
def gensquares(N): res = [] for i in range(N): res.append(i*i) return resfor item in gensquares(5): print(item)
总结:
1、语法上和函数类似: 生成器函数和常规函数几乎是一模一样的。它们都是使用def语句进行定义,区别在于,生成器使用yield语句返回一个值,而常规函数使用return语句返回一个值。 2、自动实现迭代协议:对于生成器,Python会自动实现迭代协议,以便应用到迭代背景中(如for循环等),由于生成器自动实现了迭代协议,所以,我们可以调用它的next方法,并且,在没有值可以返回的时候,生成器自动产生StopIteration异常。- 状态挂起,生成器使用yield语句返回一个值。yield语句挂起该生成器函数的状态,保留足够的信息,以便之后从它离开的地方继续执行
39、请输入一个字符串,打印结果为倒叙
while 1: a = input('please enter a string ') print(a[::-1])
40、请写出自己的算法,按升序合并如下列表
list1 = [2,3,8,4,9,5,6] list2 = [5,6,10,17,11,2]list1 = [2,3,8,4,9,5,6]list2 = [5,6,10,17,11,2]list1.extend(list2)print(sorted(list(set(list1))))
41、已排好序的列表aList和字符char1,表示aList中存在char1则返回False,不存在则返回True的表达式:
expression = lambda a:False if a in aList else Trueprint(expression('pea'))
42、不依赖中间变量,交换a和b的值
a = a + bb = a - ba = a - b
43、求aList 和 bList交集的表达式:
aList&bList
44、现有列表 aList = [3,1,-4,-2] 按照其元素的绝对值大小进行排序的表达式是sorted(abs(i) for i in a)
45、获取Python解释器版本的方法是:import sysprint(sys.version)
46、到底什么是Python?你可以在回答中与其他技术进行对比(也鼓励这样做)。
关键点: (1)Python是一门解释型语言,这就是说与C语言和C的衍生语言不同,Python代码运行之前不需要编译,其他解释型语言还包括Ruby和PHP。 (2)Python是动态类型语言,在声明变量时,不需要声明变量的类型。 (3)Python非常适合面向对象编程(OOP),因为它支持通过组合(composition)和继承(inheritance)的方式定义类(class)。 (4)Python代码编写快,但是运行速度比编译语言通常要慢。好在Python允许加入基于C语言编写的扩展,因此我们能够优化代码,消除瓶颈,这点通常是可以实现的。numpy就是一个很好的例子。 (5)Python的用途非常广---网络应用,自动化,科学建模,大数据应用,等等。它通常也被用作胶水语言,帮助其他语言和组件改善运行状况。47、如果模块是被导入的,则name的值是py文件名,如果模块时被执行的,则name的值是'main'.
48、要保持追踪内存中的状态, python使用了引用计数这一项技术, 就是python内部记录着所有使用中的对象各有多少引用.
49、简述一下Python内存中的垃圾回收机制。
Python在内存中存储了每个对象的引用计数(reference count)。如果计数值变为0,那么相应的对象就会消失。分配给该对象的内存就会释放出来用作他用。 偶尔也会出现引用循环。垃圾回收器会定时寻找这个循环,并将其回收。 Python中还使用了某些启示算法来加速回收。50、从输入到页面返回,中间都发生了什么?
1、浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址;
2、解析出 IP 地址后,根据该 IP 地址和默认端口 80,和服务器建立[TCP连接]
3、浏览器发出读取文件(URL 中域名后面部分对应的文件)的HTTP 请求,该请求报文作为 的第三个报文的数据发送给服务器;
4、服务器对浏览器请求作出响应,并把对应的 html 文本发送给浏览器;
5、释放 ;
6、浏览器将该 html 文本并显示内容;
51、HTTP状态码有什么不同,列出你知道的HTTP状态代码,然后请讲出他们都是什么意思。
状态代码有三位数字组成,第一个数字定义了响应的类别,共分五种类别:
1xx:指示信息--表示请求已接收,继续处理
2xx:成功--表示请求已被成功接收、理解、接受
3xx:重定向--要完成请求必须进行更进一步的操作
4xx:客户端错误--请求有语法错误或请求无法实现
5xx:服务器端错误--服务器未能实现合法的请求
常见状态码:
200 OK//客户端请求成功400 Bad Request//客户端请求有语法错误,不能被服务器所理解401 Unauthorized//请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用403 Forbidden//服务器收到请求,但是拒绝提供服务404 Not Found//请求资源不存在,eg:输入了错误的URL500 Internal Server Error//服务器发生不可预期的错误503 Server Unavailable//服务器当前不能处理客户端的请求,一段时间后可能恢复正常
52、lambda表达式和列表推导式:
l1 = [i for i in range(10)]l2 = [lambda: i for i in range(10)]print(l1[0]) ###0print(l2[0]) #. at 0x000002003F170B70>print(l2[0]()) #9
53、eval和exec的区别
eval有返回值 exec没有返回值print(eval('2+3')) #5 eval中的参数是一个字符串,可以把这个字符串当作表达式求值exec('a=2+1') #exec中的参数是 aprint(a) # 3exec("print('1+1')") # 1+1
eval还可以将字符串转换成对象
class obj(object): passa = eval('obj()')print(a,type(a)) #<__main__.obj object at 0x000001F1F6897550>
53、cookie和session的区别
a、session在服务器端,cookie在客户端(浏览器) b、session默认被存在服务器的一个文件里(不是内存) c、sesison 的运行依赖session_id, 而session_id是存在cookie中,也就是说,如果浏览器禁用了cookie,同时session也会失效(但是可以通过其他方式实现,比如在URL中传递session_id) d、session可以放在文件、数据库、或内存中都可以、 e、用户验证场景通常会用session f、维持一个会话的核心就是客户端的唯一标识,即session_id54、http是有状态协议还是无状态协议?如何从两次请求中判断是否是同一用户?
无状态协议。判断session_id 是否是相同。55、有一个数组[3,4,1,2,5,6,6,5,4,3,3]请写一个函数,找出该数组中没有重复的书的总和。
def MyPlus(l): new_l = [] for i in l: if i not in new_l: new_l.append(i) return sum(new_l)print(MyPlus(l = [2,3,4,4,5,5,6,7,8]))
56、Python一行print出1~100的偶数列表:
print([i for i in range(1,100) if i % 2 == 0 ])
57、1,2,3,4,5能组成多少个互不相同且无重复的元素?
nums = []for i in range(1,6): for j in range(1,6): for k in range(1,6): if i != j and j != k and i !=k: new_num = i*100 + k*10 + j if new_num not in nums: nums.append(new_num)print(nums)
58、请写出五种http的请求方法:
get,post,put,delete,head,connect.59、描述多进程开发中join与daemon的区别
守护进程(daemon)
主进程创建守护进程 其一:守护进程会在主进程代码执行结束后就终止 其二:守护进程内无法开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children 注意:进程之间是相互独立的,主进程的代码运行结束,守护进程随即终止p.join([timeout]): 主进程等待相应的子进程p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。需要强调的是p.join()只能join住start开始的进程,而不能join住run开启的进程。
60、简述GIL对Python性能的影响。
由于GIL(Global Interpreter Lock)的影响,Python无法利用多核优势。
GIL本质就是一把互斥锁,既然是互斥锁,所有互斥锁的本质都是一样--将并发运行变成串行,以此来控制同一时间内共享的数据只能被一个任务修改,进而保证数据安全。
可以肯定的一点是:保护不同的数据的安全,就应该加不同的锁。 现在的计算机基本上都是多核,python对于计算密集型的任务开多线程的效率并不能带来多大性能上的提升,甚至不如串行(没有大量切换),但是,对于IO密集型的任务效率还是有显著提升的。 因此,对于IO密集型的任务,Python多线程更合适。61、执行Python脚本的两种方式
1、./run.py.shell直接调用python脚本2、python run.py 调用python 解释器来调用python脚本
62、TCP协议和UDP协议的区别是什么?
1、TCP协议是有连接的,有连接的意思是开始传输实际数据之前TCP的客户端和服务器端必须通过三次握手建立连接,会话结束后也要结束连接。而UDP是无连接的
2、TCP协议保证数据发送,按序送达,提供超时重传保证数据可靠性,但是UDP不保证按序到达,甚至不能保证到达,还是努力交付,即便是按序发送的序列,也不保证按序送到。 3、TCP协议所需资源多,TCP首部需20个字节(不算可选项),UDP首部字段只需8个字节。 4、TCP有流量控制和拥塞控制,UDP没有。网络拥堵不会影响发送端的发送速率。 5、TCP面向的字节流的服务,UDP面向的是报文的服务。三次握手建立连接时,发送方再次发送确认的必要性?
主 要是为了防止已失效的连接请求报文段突然又传到了B,因而产生错误。假定出现一种异常情况,即A发出的第一个连接请求报文段并没有丢失,而是在某些网络结 点长时间滞留了,一直延迟到连接释放以后的某个时间才到达B,本来这是一个早已失效的报文段。但B收到此失效的连接请求报文段后,就误认为是A又发出一次 新的连接请求,于是就向A发出确认报文段,同意建立连接。假定不采用三次握手,那么只要B发出确认,新的连接就建立了,这样一直等待A发来数据,B的许多 资源就这样白白浪费了。四次挥手释放连接时,等待2MSL的意义?
第 一,为了保证A发送的最有一个ACK报文段能够到达B。这个ACK报文段有可能丢失,因而使处在LAST-ACK状态的B收不到对已发送的FIN和ACK 报文段的确认。B会超时重传这个FIN和ACK报文段,而A就能在2MSL时间内收到这个重传的ACK+FIN报文段。接着A重传一次确认。 第二,就是防止上面提到的已失效的连接请求报文段出现在本连接中,A在发送完最有一个ACK报文段后,再经过2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。一句话总结TCP和UDP的区别:
TCP是面向连接的,可靠的字节流服务,UPD是面向无连接的,不可靠而数据报服务。
63、Python中有如下一个字典,
dic_tmp = {'carry':17,'bob':21,'matty':23,'jack':33,'tom':17,'alex':23} 请按照key值进行排序print(sorted(dic_tmp.items(),key=lambda dic_tmp : dic_tmp[0]))
64、简述InnoDB和MyISAM的特点:
InnoDB是MySQL最常用的一种引擎,Facebook,Google等公司的成功应用已经证明了InnoDB存储引擎具备高可用性,高性能以及高可扩展性。支持事务,其特点是行锁设计,支持外键,并支持类似Oracle的非锁定读。对于表中数据的存储,InnoDB 存储引擎采用了聚集(clustered)的方式,每张表都是按 主键的顺序进行存储的,如果没有显式地在表定义时指定主键,InnoDB 存储引擎会为每一 行生成一个 6 字节的 ROWID,并以此作为主键。 MyISAM 不支持事务、表锁设计、支持全文索引,主要面向一些 OLAP 数 据库应用, 此外,MyISAM 存储引擎的 另一个与众不同的地方是,它的缓冲池只缓存(cache)索引文件,而不缓存数据文件,这与 大多数的数据库都不相同。65、利用Python上下文管理器,实现一个写入文件的功能(写入内容为‘hello world’)
class Open(object): def __init__(self,name,mode): self.name = name self.mode = mode def __enter__(self): self.opened = open(self.name,self.mode) # 在enter方法中打开文件并返回文件名称 return self.opened # 返回值就是as后面的writer def __exit__(self, exc_type, exc_val, exc_tb): #在 close方法中关闭文件 self.opened.close()with Open('mytext.txt','w') as writer: writer.write('hello world')
65、django的请求生命周期
-
当用户在浏览器中输入url时,浏览器会生成请求头和请求体发给服务端
请求头和请求体中会包含浏览器的动作(action),这个动作通常为get或者post,体现在url之中. -
url经过Django中的wsgi,再经过Django的中间件,最后url到过路由映射表,在路由中一条一条进行匹配,
一旦其中一条匹配成功就执行对应的视图函数,后面的路由就不再继续匹配了. -
视图函数根据客户端的请求查询相应的数据.返回给Django,然后Django把客户端想要的数据做为一个字符串返回给客户端.
-
客户端浏览器接收到返回的数据,经过渲染后显示给用户
66、django rest framework规范
1、URL后面尽量用名词,因为rest frame是面向资源的编程,因此URL命名的时候,用名词能体现出资源。 2、method的不同,实现增删改查。 3、版本号,因为有版本的更替,为了体现出版本间的过渡,因此在发请求的时候,要体现出版本号。 4、返回值,与以往的只返回json数据不同,rest API规范还要加上状态码。 5、域名,由于前后端分离,因此要处理跨域问题。解决办法:JSONP,CORS。 6、过滤,通过URL传参的形式传递搜索条件,(例如,指定返回的记录数量,指定分页等)67、JSONP和CORS
JSONP的本质就是利用script的src属性绕过同源策略。 CORS 整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。 一句话总结CORS,在代码中添加上响应头即可。 68、现有字典dic = {'a':1,'b':2,'c':23,'d':11,'e':4,'f':21},请按照字段中的value进行排序print(sorted(dic.items(),key=lambda dic: dic[1] ))
69、如何查看端口号为8080的是什么进程
netstat -nao | findstr '8080'
70、MySQL搜索引擎和局域网权限,MySQL中的锁
InnoDB 存储引擎(最常用的引擎,支持事务,特点是行锁设计,支持外键) MyISAM 存储引擎(不支持事务,表锁设计,支持全文索引) NDB 存储引擎 Memory 存储引擎71、算法,按照空间复杂度,进行优化。
72、ES6语法,
73、二叉树的遍历
class BiTreeNode(object): def __init__(self,data): self.data = data self.lchild = None self.rchild = Nonea = BiTreeNode('A')b= BiTreeNode('B')c = BiTreeNode('C')d = BiTreeNode('D')e = BiTreeNode('E')f = BiTreeNode('F')g = BiTreeNode('G')e.lchild = ae.rchild = ga.rchild = cc.lchild = bc.rchild = dg.rchild = froot = e# 前序遍历 (先找做子树,后找右子树)def pre_order(root): if root: print(root.data,end='') # EACBDGF pre_order(root.lchild) pre_order(root.rchild)pre_order(root)print('')# 中序遍历def in_order(root): if root: in_order(root.lchild) print(root.data,end='') # ABCDEGF in_order(root.rchild)in_order(root) # ABCDEGFprint('')# 后序遍历def post_order(root): if root: post_order(root.lchild) post_order(root.rchild) print(root.data,end='')post_order(root) #BDCAFGE
74、实现页面实时刷新的方法:
1、轮询 2、长轮询 3、websocket轮询:客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并关闭连接。
优点:后端程序编写比较容易。
缺点:请求中有大半是无用,浪费带宽和服务器资源。 实例:适于小型应用。长轮询:客户端向服务器发送Ajax请求,服务器接到请求后hold住连接,直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求。
优点:在无消息的情况下不会频繁的请求。
缺点:服务器hold连接会消耗资源。 实例:WebQQ、Hi网页版、Facebook IM。 75、提高数据库性能的方法 a、建立索引。 b、书写:SQL语句优化,尽量不要使用select * from等语句 c、76、请写出以下函数的输出结果
def multiplier(): return [lambda x: x * i for i in range(4)]print([m(2) for m in multiplier()]) # 6,6,6,6
具体原因请见:
77、rabbitMQ的几种模式以及简述RPC
总共6中模式,相关如下:
78、你了解webSocket吗?
a、最近在研究。 b、很久以前研究过。79、简单谈谈你了解的websocket。
a. 自己手写socket研究其原理 b. 握手信息 c. 数据加密 了解的应用: 1.基于tornado实现的websocket聊天室 2.弹幕。80、redis和memcached的区别
memcache与redis区别 1)redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储 2)内存使用使用效率对比 使用简单的key-value存储的话,memcached的内存利用率会更高一点,如果redis采用hash结构来做key-value存储,由于其组合式的压缩,内存的利用率更高。 3)性能对比:由于redis只使用单核,而memcached使用多核,所以平均在每一个核上redis在存储小数据时比memcached性能更高,而在100Ks=以上的时候memcached性能要高于redis 4)内存管理机制的不同 在redis中,并不是所有的数据都一一直存储在内存中的,这是和memcached相比最大的一个区别 Redis只会缓存所有的key端的信息,如果redis发现内存的使用量超过某一个值,将触发swap的操作,redis根据相应的表达式计算出那些key对应value需要swap到磁盘,然后再将这些这些key对应的value持久化到磁盘中,同时再内存清除。 5)数据持久化的支持 虽然redis是基于内存的存储系统,但是他本身是支持内存数据的持久化,而且主要提供两种主要的持久化策略,RDB快照和AOF日志,而memcached是不支持数据持久化的操作的81, drop 和 truncate 的区别
truncate table在功能上与不带where子句的delete语句相同:二者均能删除表中的全部行。但truncate table速度比delete快。
TRUNCATE TABLE:删除内容、释放空间但不删除定义。 DELETE TABLE:删除内容不删除定义,不释放空间。 DROP TABLE:删除内容和定义,释放空间。 还有个比较大的区别就是truncate后自增长的ID列也会归零,以后插入记录ID从1开始。 但是delete后你再插入记录,ID会从上次最大的数字开始。 delete可以配合where条件 82、differences between threads and process; Threads share the address space of the process that created it; processes have their own address space. Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process. Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes. New threads are easily created; new processes require duplication of the parent process. Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes. Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes. 83、写出你知道的常见异常AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性xIOError 输入/输出异常;基本上是无法打开文件ImportError 无法引入模块或包;基本上是路径问题或名称错误IndentationError 语法错误(的子类) ;代码没有正确对齐IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]KeyError 试图访问字典里不存在的键KeyboardInterrupt Ctrl+C被按下NameError 使用一个还未被赋予对象的变量SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)TypeError 传入对象类型与要求的不符合UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,导致你以为正在访问它ValueError 传入一个调用者不期望的值,即使值的类型是正确的`