发布于2019-08-03 09:06 阅读(5998) 评论(0) 点赞(1) 收藏(1)
0,python2和python3的区别
""" .1 默认解释器编码:py2-> ascii ; py3->utf-8 .2 字符串和字节(*****) py2: unicode str = bytes py3: str,字符串 bytes,字节 .3 经典类和新式类 py2: - 经典 - 新式(直接或间接继承object) py3: - 新式 .4 yield from ... """
20、python2和python3区别?列举5个
1、Python3 使用 print 必须要以小括号包裹打印内容,比如 print('hi')
Python2 既可以使用带小括号的方式,也可以使用一个空格来分隔打印内容,比如 print 'hi'
2、python2 range(1,10)返回列表,python3中返回迭代器,节约内存4
4、python2中unicode表示字符串序列,str表示字节序列
python3中str表示字符串序列,byte表示字节序列
5、python2中为正常显示中文,引入coding声明,python3中不需要
6、python2中是raw_input()函数,python3中是input()函数
1,什么是GIL?
GIL全局解释器锁
在同一个进程里的每一个线程同一时间只能有一个线程访问cpu,只要在多线程/进程之间用到全局 变量就要加上锁
2,python中@staticmethod和@classmethod的区别?
@classmethod(cls):类方法,类名去调用,它会将类空间传给cls
@staticmethod():静态方法,不用传入类空间,对象空间的方法,相当于普通函数.
3,python里面如何拷贝一个对象,并解释深浅拷贝
浅拷贝:第一层创建的是新的内存地址,而从第二层开始,指向的都是同一个内存地址,所以,对于第二层及更深的层数来说,保持一致性
深拷贝:完全独立(复制其数据对象完完全全放独立的一个内存,完全拷贝,数据不共享)
4,python里面search()和math()的区别
search():从左到右找,找到第一个就返回,找不到返回None match():从开头找,找不到报错,相当于在前面加个"^"
5,简述迭代器生成器以及他们的区别
迭代器就是用于迭代操作的的对象,遵从迭代协议(内部实现了__iter__()和__next__()方法,可以像列表(可迭代对象,只有__iter__()方法)一样迭代获取其中的值,与列表不同的是,构建迭代器的时候,不像列表一样一次性把数据加到内存,而是以一种延迟计算的方式返回元素,即调用next方法时候返回此值。
迭代器取值:__next__,或者for循环
生成器本质上也是一个迭代器,自己实现了可迭代协议,与生成器不同的是生成器的实现方式不同,可以通过生成器表达式和生成器函数两种方式实现,代码更简洁。生成器和迭代器都是惰性可迭代对象,只能遍历一次,数据取完抛出Stopiteration异常
生成式取值:一个yield对应一个next
6,什么是协程,python的协程是如何实现的
协程:能在一条线程的基础上,在多个任务之间互相切换
协程的实现:
import gevent def test1(): print(1,2) gevent.sleep(0)#执行到这里的时候切换去函数test2 print(3,4) def test2(): print(5,6) gevent.sleep(0) print(7,8) gevent.joinall( [gevent.spawn(test1),gevent.spawn(test2)] )#在函数test1等待的时候,协程去执行了函数test2
7,什么是装饰器,请用装饰器实现singleton
装饰器:装饰器的本质是闭包函数,功能,在不改变原函数的基础上,为原函数增加一些额外的功能
# 使用装饰器实现单例模式 def singleton(cls, *args, **kwargs): instance = {} def _instance(): if cls not in instance: instance[cls] = cls(*args, *kwargs) return instance[cls] return _instance @singleton class Test_singleton: def __init__(self): self.num = 0 def add(self): self.num = 99 ts1 = Test_singleton() ts2 = Test_singleton() print(ts1) print(ts2)
8,请使用python实现快速排序
一行代码实现: quick_sort = lambda array: array if len(array) <= 1 else quick_sort([item for item in array[1:] if item <= array[0]]) + [array[0]] + quick_sort([item for item in array[1:] if item > array[0]])
#常见快排 def quick_sort(array, left, right): if left >= right: return low = left high = right key = array[low] while left < right: while left < right and array[right] > key: right -= 1 array[left] = array[right] while left < right and array[left] <= key: left += 1 array[right] = array[left] array[right] = key quick_sort(array, low, left - 1) quick_sort(array, left + 1, high)
#算法中的快排 def quick_sort(array, l, r): if l < r: q = partition(array, l, r) quick_sort(array, l, q - 1) quick_sort(array, q + 1, r) def partition(array, l, r): x = array[r] i = l - 1 for j in range(l, r): if array[j] <= x: i += 1 array[i], array[j] = array[j], array[i] array[i + 1], array[r] = array[r], array[i+1] return i + 1
9,简述select和epoll的原理和区别
select原理概述 调用select时,会发生以下事情: 从用户空间拷贝fd_set到内核空间; 注册回调函数__pollwait; 遍历所有fd,对全部指定设备做一次poll(这里的poll是一个文件操作,它有两个参数,一个是文件fd本身,一个是当设备尚未就绪时调用的回调函数__pollwait,这个函数把设备自己特有的等待队列传给内核,让内核把当前的进程挂载到其中); 当设备就绪时,设备就会唤醒在自己特有等待队列中的【所有】节点,于是当前进程就获取到了完成的信号。poll文件操作返回的是一组标准的掩码,其中的各个位指示当前的不同的就绪状态(全0为没有任何事件触发),根据mask可对fd_set赋值; 如果所有设备返回的掩码都没有显示任何的事件触发,就去掉回调函数的函数指针,进入有限时的睡眠状态,再恢复和不断做poll,再作有限时的睡眠,直到其中一个设备有事件触发为止。 只要有事件触发,系统调用返回,将fd_set从内核空间拷贝到用户空间,回到用户态,用户就可以对相关的fd作进一步的读或者写操作了。 epoll原理概述 调用epoll_create时,做了以下事情: 内核帮我们在epoll文件系统里建了个file结点; 在内核cache里建了个红黑树用于存储以后epoll_ctl传来的socket; 建立一个list链表,用于存储准备就绪的事件。 调用epoll_ctl时,做了以下事情: 把socket放到epoll文件系统里file对象对应的红黑树上; 给内核中断处理程序注册一个回调函数,告诉内核,如果这个句柄的中断到了,就把它放到准备就绪list链表里。 调用epoll_wait时,做了以下事情: 观察list链表里有没有数据。有数据就返回,没有数据就sleep,等到timeout时间到后即使链表没数据也返回。而且,通常情况下即使我们要监控百万计的句柄,大多一次也只返回很少量的准备就绪句柄而已,所以,epoll_wait仅需要从内核态copy少量的句柄到用户态而已。 对比 select缺点: 最大并发数限制:使用32个整数的32位,即32*32=1024来标识fd,虽然可修改,但是有以下第二点的瓶颈; 效率低:每次都会线性扫描整个fd_set,集合越大速度越慢; 内核/用户空间内存拷贝问题。 epoll的提升: 本身没有最大并发连接的限制,仅受系统中进程能打开的最大文件数目限制; 效率提升:只有活跃的socket才会主动的去调用callback函数; 省去不必要的内存拷贝:epoll通过内核与用户空间mmap同一块内存实现。 当然,以上的优缺点仅仅是特定场景下的情况:高并发,且任一时间只有少数socket是活跃的。 如果在并发量低,socket都比较活跃的情况下,select就不见得比epoll慢了(就像我们常常说快排比插入排序快,但是在特定情况下这并不成立)。
10,简述python的垃圾回收机制
垃圾回收 Python的GC模块主要运用了引用计数来跟踪和回收垃圾。在引用计数的基础上,还可以通过“标记-清除”解决容器对象可能产生的循环引用的问题。通过分代回收以空间换取时间进一步提高垃圾回收的效率。 引用计数 原理:当一个对象的引用被创建或者复制时,对象的引用计数加1;当一个对象的引用被销毁时,对象的引用计数减1,当对象的引用计数减少为0时,就意味着对象已经再没有被使用了,可以将其内存释放掉。 优点:引用计数有一个很大的优点,即实时性,任何内存,一旦没有指向它的引用,就会被立即回收,而其他的垃圾收集技术必须在某种特殊条件下才能进行无效内存的回收。 缺点:但是它也有弱点,引用计数机制所带来的维护引用计数的额外操作与Python运行中所进行的内存分配和释放,引用赋值的次数是成正比的,这显然比其它那些垃圾收集技术所带来的额外操作只是与待回收的内存数量有关的效率要低。同时,引用技术还存在另外一个很大的问题-循环引用,因为对象之间相互引用,每个对象的引用都不会为0,所以这些对象所占用的内存始终都不会被释放掉。如下: a = [] b = [] a.append(b) b.append(a) print a [[[…]]] print b [[[…]]] 标记-清除 标记-清除只关注那些可能会产生循环引用的对象,显然,像是PyIntObject、PyStringObject这些不可变对象是不可能产生循环引用的,因为它们内部不可能持有其它对象的引用。Python中的循环引用总是发生在container对象之间,也就是能够在内部持有其它对象的对象,比如list、dict、class等等。这也使得该方法带来的开销只依赖于container对象的的数量??? 原理:1. 寻找跟对象(root object)的集合作为垃圾检测动作的起点,跟对象也就是一些全局引用和函数栈中的引用,这些引用所指向的对象是不可被删除的;2. 从root object集合出发,沿着root object集合中的每一个引用,如果能够到达某个对象,则说明这个对象是可达的,那么就不会被删除,这个过程就是垃圾检测阶段;3. 当检测阶段结束以后,所有的对象就分成可达和不可达两部分,所有的可达对象都进行保留,其它的不可达对象所占用的内存将会被回收,这就是垃圾回收阶段。(底层采用的是链表将这些集合的对象连接在一起) 缺点:标记和清除的过程效率不高。 分代回收 原理:将系统中的所有内存块根据其存活时间划分为不同的集合,每一个集合就成为一个“代”,Python默认定义了三代对象集合,垃圾收集的频率随着“代”的存活时间的增大而减小。也就是说,活得越长的对象,就越不可能是垃圾,就应该减少对它的垃圾收集频率。那么如何来衡量这个存活时间:通常是利用几次垃圾收集动作来衡量,如果一个对象经过的垃圾收集次数越多,可以得出:该对象存活时间就越长。
11,写一个简单的python socket编程
server端: import socket sk = socket.socket() # 创建客户套接字 sk.bind(('127.0.0.1',8898)) #把地址绑定到套接字 sk.listen() #监听链接 conn,addr = sk.accept() #接受客户端链接 ret = conn.recv(1024) #接收客户端信息 print(ret) #打印客户端信息 conn.send(b'hi') #向客户端发送信息 conn.close() #关闭客户端套接字 sk.close() #关闭服务器套接字(可选) client端: import socket sk = socket.socket() # 创建客户套接字 sk.connect(('127.0.0.1',8898)) # 尝试连接服务器 sk.send(b'hello!') ret = sk.recv(1024) # 对话(发送/接收) print(ret) sk.close() # 关闭客户套接字
12,下面是我输出结果是什么?
#下面代码会输出什么 def f(x,l=[]): for i in range(x): l.append(i*i) print(l) f(2) #[0, 1] f(3,[3,2,1]) #[3, 2, 1, 0, 1, 4] f(3) #[0, 1, 0, 1, 4]
#下面代码会输出什么 class Parent(object): x=1 class Child1(Parent): pass class Child2(Parent): pass print(Parent.x,Child1.x,Child2.x) #1 1 1 print(Parent.x,Child1.x,Child2.x) #1 2 1 Parent.x=3 print(Parent.x,Child1.x,Child2.x) #3 2 3[6, 6, 6, 6]
#下面代码会输出什么 def multipliers(): return [lambda x:i*x for i in range(4)] print([m(2) for m in multipliers()]) #[6, 6, 6, 6]
13,Git的常用命令
14,列表去重(不使用set,用基本的方法实现):list=[9,4,2,5,8,4,5,3]
def quchong(list1): list2=[]; for i in list1: if i not in list2: list2.append(i); print(list2); list1 = [9, 4, 2, 5, 8,4,5,3]; quchong(list1)
15,单例模式实现
import threading import time class Foo(object): _instance = None _lock = threading.RLock() def __new__(cls, *args, **kwargs): if cls._instance: return cls._instance with cls._lock: if not cls._instance: cls._instance = object.__new__(cls) return cls._instance def task(): obj = Foo() print(obj) for i in range(10): t = threading.Thread(target=task) t.start() time.sleep(100) obj = Foo()
16,python自带的数据类型
数字、字符串、Bytes、列表、元组、字典、集合、布尔等
17,说说==以及is的区别
==比较数值
is比较内存地址
18,python函数中*args和**kwargs这两个参数是什么意思
1:*args的功能:------接收多个位置参数,转换成元组tuple形式 2:**kwargs的功能------接收多个关键字参数,转换成字典dict形式 3:位置参数一定要在关键字参数之前,也就是(*args,**kwargs)
19,什么是lambda函数,它有什么好处
什么是lamda函数? lambda 函数是一个可以接收任意多个参数(包括可选参数)并且返回单个表达式值的函数。 (注意:lambda 函数不能包含命令,它们所包含的表达式不能超过一个) lamda函数有什么好处? 1、lambda函数比较轻便,即用即仍,很适合需要完成一项功能,但是此功能只在此一处使用,连名字都很随意的情况下; 2、匿名函数,一般用来给filter,map这样的函数式编程服务; 3、作为回调函数,传递给某些应用,比如消息处理
20,用过的标准包以及第三方包(os以及sys)
标准包:内置模块? """ os time & datetime random hashlib sys re logging json pickle """ # 11. 第三方模块 """ requsts bs4 pymysql pymongo gevent
21,range和xrange的区别
range: range([start,] stop[, step]),根据start与stop指定的范围以及step设定的步长,生成一个序列。注意这里是生成一个序列。 xrange的用法与range相同,即xrange([start,] stop[, step])根据start与stop指定的范围以及step设定的步长,他所不同的是xrange并不是生成序列,而是作为一个生成器。即他的数据生成一个取出一个。 所以相对来说,xrange比range性能优化很多,因为他不需要一下子开辟一块很大的内存,特别是数据量比较大的时候。 注意:1、xrange和range这两个基本是使用在循环的时候。 2、 当需要输出一个列表的时候,就必须要使用range了。
22,线程,进程的区别
进程:资源分配的最小单位
线程:CPU调度的最小单位
进程:IO密集型/计算密集型 提高并发,资源浪费. 线程:IO密集型提高并发,多个线程 协程:IO密集型提供并发,1个线程 计算密集型:进程 IO密集型:线程 < 协程
区别:
1、 一个程序中至少有一个进程,一个进程中至少有一个线程;
2、 线程的划分尺度小于进程(占有资源),使得多线程程序的并发性高;
3、 进程运行过程中拥有独立的内存空间,而线程之间共享内存,从而极大的提高了程序的运行效率
4、 线程不能独立运行,必须存在于进程中
优缺点:
线程开销小,但是不利于资源的管理和保护,而进程反之。
23,描述对python中数据类型列表list,字典 dict,元组 tuple的理解
元组:()用元括弧括起来的一组元素集合。其特点是内容不可变,即一旦定义其长度和内容都是固定的;类似于C询言的数组。如: t = (0, True, ‘a’) 上面就定义了一个包含3个子元素的元组列表,访问元组成员的格式是使用成员下标,如: print t(1) True (理解为C的数组) 列表:[]由中括弧括起来的包含一组元素的集合;其特点是长度和内容都可以改变。定义如下: L = [0, False, ‘l’] 列表可以进行如下操作: 添加元素:L.append(1) 删除元素:del L[0] 插入元素:L.insert(2, 3) 修改元素:L[1] = True (理解为java链表数组) 字典:{}Python中的字典和其它询言的字典是一个意思,是对hashmap的实现;其询法定义为: d = {‘k1’: ‘k’, ‘k2’: ‘k2’} 字典可以有如下操作: 增加键值对:d[‘k3’] = 3 删除键值对:del d[‘k’] 修改键值对:d[‘k2’] = True 获取键值: d[‘k1’]
24,如何删除一个list中的元素,如何删除dict中的一对kv
l1 = ["alex","wusir"]
l1.remove("alex")
dic = {'name':'老男孩','age':56,'hobby':'women'} del dic['name']
25,如何查找一个字符串中特定字符?Find()和index()两个函数有什么差异?
都是通过元素找索引:
find()方法:查找子字符串,若找到返回从0开始的下标值,若找不到返回-1
index方法是在字符串里查找子串第一次出现的位置,如果查找不到子串,会抛出异常,
26,使用过python哪些第三方件?
1.Web框架 Django: 开源Web开发框架,它鼓励快速开发,并遵循MVC设计,开发周期短。 ActiveGrid: 企业级的Web2.0解决方案。 Karrigell: 简单的Web框架,自身包含了Web服务,py脚本引擎和纯python的数据库PyDBLite。 Tornado: 一个轻量级的Web框架,内置非阻塞式服务器,而且速度相当快 webpy: 一个小巧灵活的Web框架,虽然简单但是功能强大。 CherryPy: 基于Python的Web应用程序开发框架。 Pylons: 基于Python的一个极其高效和可靠的Web开发框架。 Zope: 开源的Web应用服务器。 TurboGears: 基于Python的MVC风格的Web应用程序框架。 Twisted: 流行的网络编程库,大型Web框架。 Quixote: Web开发框架。 2.科学计算 Matplotlib: 用Python实现的类matlab的第三方库,用以绘制一些高质量的数学二维图形。 SciPy: 基于Python的matlab实现,旨在实现matlab的所有功能。 NumPy: 基于Python的科学计算第三方库,提供了矩阵,线性代数,傅立叶变换等等的解决方案。 3.GUI PyGtk: 基于Python的GUI程序开发GTK+库。 PyQt: 用于Python的QT开发库。 WxPython: Python下的GUI编程框架,与MFC的架构相似。 4.其它 BeautifulSoup: 基于Python的HTML/XML解析器,简单易用。 PIL: 基于Python的图像处理库,功能强大,对图形文件的格式支持广泛。 PyGame: 基于Python的多媒体开发和游戏软件开发模块。 Py2exe: 将python脚本转换为windows上可以独立运行的可执行程序。
27,描述一下MVC架构
MVC是一种架构设计模式,是一种设计理念。是为了达到分层设计的目的,从而使代码解耦,便于维护和代码的复用。MVC是3个单词的缩写,全称:Model-View-Controller(模型-视图-控制器)。
1、Model
模型层,可以简单理解就是数据层,用于提供数据。在项目中,(简单理解)一般把数据访问和操作,比如将对象关系映射这样的代码作为Model层,也就是对数据库的操作这一些列的代码作为Model层。比如代码中我们会写DAO和DTO类型的代码,那这个DAO和DTO我们可以理解为是属于Model层的代码。
2、View
视图层,就是UI界面,用于跟用户进行交互。一般所有的JSP、Html等页面就是View层。
3、Controller
控制层,Controller层的功能就是将Model和View层进行关联。比如View主要是显示数据的,但是数据又需要Model去访问,这样的话,View会先告诉Controller,然后Controller再告诉Model,Model请求完数据之后,再告诉View。这样View就可以显示数据了。
28,描述一下表与视图的理解
数据库中的数据都是存储在表中的,而视图只是一个或多个表依照某个条件组合而成的结果集,一般来说你可以用update,insert,delete等sql语句修改表中的数据,而对视图只能进行select操作。但是也存在可更新的视图,对于这类视图的update,insert和delete等操作最终会作用于与其相关的表中数据。因此,表是数据库中数据存储的基础,而视图只是为了满足某种查询要求而建立的一个对象。
表是物理存在的,你可以理解成计算机中的文件!
视图是虚拟的内存表,你可以理解成Windows的快捷方式!
区别:1、视图是已经编译好的sql语句。而表不是
2、视图没有实际的物理记录。而表有。
3、表是内容,视图是窗口
4、表只用物理空间而视图不占用物理空间,视图只是逻辑概念的存在,表可以及时对它进行修改,但视图只能有创建的语句来修改
5、表是内模式,视图是外模式
6、视图是查看数据表的一种方法,可以查询数据表中某些字段构成的数据,只是一些SQL语句的集合。从安全的角度说,视图可以不给用户接触数据表,从而不知道表结构。
7、表属于全局模式中的表,是实表;视图属于局部模式的表,是虚表。
8、视图的建立和删除只影响视图本身,不影响对应的基本表。
29,有0<x<=10,10<x<=20,20<x<=30,......,190<x<=200,200<x这样的 21个区间分别对应1-21二十一个级别,请编写一个函数level(x)根据输入数值返回对应级别.
30,有一个数据结构如下所示,请编写一个函数从该结构数据中返回由指定的字段和对应的值组成的字典,如果指定字段不存在,则跳过该字段.
data:{"time":"2016-08-05T13:13:05",
"some_id":"ID1234",
"grp1":{"fld1":1,
"fld2":2},
"xxx2":{"fld3":0,
"fld5":0.4},
"fld6":11,
"fld7":7,
"fld46":8}
fields:由"|"连接的一以"fld"开头的字符串,如:fld2|fld3|fld7|fld19
def select(data,fields):
#Todo:implementation
return result
data={'time':'2016-08-05T13;13:05', 'some_ID':'ID1234', 'graps1':{'fld1':1,'fld2':2}, 'xxx2':{'fld3':0,'fld5':0.4}, 'fld6':11, 'fld7':7, 'fld':8 } # 类递归思想 # 栈的思想 fields = 'fld2|fld3|fld7|fld9' fields_lst = fields.split('|') #['fld2', 'fld3', 'fld7', 'fld9'] result = {} data_lst = [1] while data != 1: for key in data: if key in fields_lst: result[key] = data[key] if type(data[key]) == dict: data_lst.append(data[key]) data = data_lst.pop() print(result)
#思路一: def select(data,fields): result = {} field_lst = fields.split('|') for key in data: if key in field_lst: result[key] = data[key] elif type(data[key]) == dict: res = select(data[key],fields) result.update(res) return result data={"time":"2016-08-05T13:13:05", "some_id":"ID1234", "grp1":{ "fld1":1,"fld2":2}, "xxx2":{ "fld3":0,"fld5":0.4}, "fld6":11, "fld7":7, "fld46":8} fields = 'fld2|fld3|fld7|fld19' print(select(data,fields))
#思路二: def select(data,fields,result = {}): field_lst = fields.split('|') for key in data: if key in field_lst: result[key] = data[key] elif type(data[key]) == dict: select(data[key], fields) return result data={"time":"2016-08-05T13:13:05", "some_id":"ID1234", "grp1":{ "fld1":1,"fld2":2}, "xxx2":{ "fld3":0,"fld5":0.4}, "fld6":11, "fld7":7, "fld46":8} fields = 'fld2|fld3|fld7|fld19' select(data,fields) print(select(data,fields))
31,斐波契纳数列1,2,3,5,8,13,21......根据这样的规律,编程求出400万以内最大的斐波契纳数,并求出它是第几个斐波契纳数
li=[1,2] while li[-1]<4000000: li.append(li[-1]+li[-2]) del li[-1] print(li[-1]) print(len(li))
def func(x): if x <= 3: return x else: first = 2 second = 3 for i in range(3,x-1): value = first + second first = second second = value return first+second print func(32)
32,上机编程实现以下功能:
dicta = {"a":1,"b":2,"c":3,"d":4,"f":"hello"}
dictb = {"b":3,"d":5,"e":7,"m":9,"k":"world"}
要求写一段代码,实现两个字典的相加,不同的key对应的值保留,相同的key对应的值相加后保留,如果是字符串就拼接,如上示例得到结果为:
dictc={"a":1,"b":5,"c";3,"d":9,"e":7,"m":9,"f":"hello","k":"world"}
dicta={'a':1,'b':2,'c':3,'d':4,'f':'hello'} dictb={'b':3,'d':5,'e':7,'m':9,'k':'world'} dic={} for key1 in dicta: for key2 in dictb: if key1==key2: dic[key1]=dicta[key1]+dictb[key2] for a in dicta: if a not in dic: dic[a]=dicta[a] for b in dictb: if b not in dic: dic[b]=dictb[b] print(dic)
三、Python部分
1、 __new__.__init__区别,如何实现单例模式,有什么优点
__new__是一个静态方法,__init__是一个实例方法
__new__返回一个创建的实例,__init__什么都不返回
__new__返回一个cls的实例时后面的__init__才能被调用
当创建一个新实例时调用__new__,初始化一个实例时调用__init__
2、深浅拷贝
浅拷贝只是增加了一个指针指向一个存在的地址,而深拷贝是增加一个指针并且开辟了新的内存,这个增加的指针指向这个新的内存,
采用浅拷贝的情况,释放内存,会释放同一内存,深拷贝就不会出现释放同一内存的错误
3、HTTP/IP相关协议,分别位于哪层
http协议是超文本传输协议,http协议是基于TCP/IP通信协议来传递数据
http协议工作与c/s架构上,浏览器作为http的客户端通过URL向http服务端即web服务器发送所用请求。web服务器收到所有请求后,向客户端发送响应信息,
http特点是短连接,无状态
地址栏键输入URL,按下回车之后经历了什么?
1.浏览器向DNS服务器请求解析该URL中的域名所对应的IP地址
2.解析出IP地址后,根据IP地址和默认端口80,和服务器建立TCP连接
3.浏览器发出读取文件的http请求,该请求报文作为TCP三次握手的第三个报文的数据发送给服务器
4.服务器对浏览器请求做出响应,并把对应的html文件发送给浏览器
5.释放TCP连接
6.浏览器将该HMTL渲染并显示内容
4、TCP/UDP区别
TCP协议是面向连接,保证高可靠性(数据无丢失,数据无失序,数据无错误,数据无重复达到)传输层协议
UDP:数据丢失,无秩序的传输层协议(qq基于udp协议)
5、webscoket
websocket是基于http协议的,可持续化连接
轮询:浏览器每隔几秒就发送一次请求,询问服务器是否有新消息
长轮询:客户端发起连接后,如果没有消息,就一直不返回response给客户端,直到有消息返回,返回完之后,客户端再次发起连接
6、RabbitMQ:
服务器端有Erlang语言来编写,支持多种客户端,只会ajax,用于分布式系统中存储转发消息,在易用性、扩展性、高可用性的方面不俗。
connection是RabbitMQ的socket连接,它封装了socket部分相关协议逻辑
connectionFactroy为connection的制造工厂
channel是我们与RabbitMQ打交道的最重要的一个接口,大部分的业务操作是在chaanel这个接口中完成,包括定义Queue、定义Exchange、
绑定Queue与Exchange,发布消息等
7、装饰器
调用装饰器其实是一个闭包函数,为其他函数添加附加功能,不修改被修改的源代码和不修改被修饰的方式,装饰器的返回值也是一个函数对象。
比如:插入日志、性能测试、事物处理、缓存、权限验证等,有了装饰器,就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
8、闭包
1.必须有一个内嵌函数
2.内嵌函数必须引用外部函数的变量(该函数包含对外作用域而不是全局作用域名字的引用)
3.外部函数的返回值必须是内嵌函数
9、迭代器与生成器
迭代可迭代对象对应_iter_(方法)和迭代器对应_next_(方法)的一个过程
生成器:包括含有yield这个关键字,生成器也是迭代器,调动next把函数变成迭代器。
10、classmethod,staticmethod,property
类方法:将类的函数转换成类方法,函数上装饰@classmethod会将函数的自动传值参数改成cls
静态方法:此方法相当于给类扩展一个功能,将类内的函数实例化,给类或对象使用,此时类内的函数就是普通函数,不管是类还是实例化的对象都可以使用
实例化:类的实例化就会产生一个实例(对象),可以理解为类()把虚拟的东西实例化,得到具体存在的值
11、常用的状态码
200--服务器成功返回网页
204--请求收到,但返回信息为空
304--客户端已经执行了GET,但文件未变化
400--错误请求,如语法错误
403--无权限访问
404--请求的页面不存在
500--服务器产生内部错误
12、多进程,多线程,协程,GIL
GIL:全局解释器锁,是锁在cpython解释器上,导致同一时刻,同一进程只能有一个线程被执行
多进程:多进程模块multiprocessing来实现,cpu密集型,IO计算型可以用多进程
多线程:多线程模块threading来实现,IO密集型,多线程可以提高效率
协程:依赖于geenlet,对于多线程应用。cpu通过切片的方式来切换线程间的执行,遇到IO操作自动切换,线程切换时需要耗时,
而协成好处没有切换的消耗,没有锁定概念。
进程:是资源管理单位,进行是相互独立的,实现并发和并发
线程:是最小的执行单位,线程的出现为了降低上下文切换的消耗,提供系统的并发性
13、IO多路复用/异步非阻塞
IO多路复用:通过一种机制,可以监听多个描述符 select/poll/epoll
select:连接数受限,查找配对速度慢,数据由内核拷贝到用户态
poll:改善了连接数,但是还是查找配对速度慢,数据由内核拷贝到用户态
epoll:epoll是linux下多路复用IO接口,是select/poll的增强版,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率
异步非阻塞:异步体现在回调上,回调就是有消息返回时告知一声儿进程进行处理。非阻塞就是不等待,不需要进程等待下去,
继续执行其他操作,不管其他进程的状态。
14、PEP8规范,规范的好处是什么?
1.缩进:4个空实现缩进,尽量不使用Tab
2.行:没行最大长度不超过79,换行可以使用反斜杠
3.命名规范:
4.注释规范:
15、range-and-xrange
都在循环时使用,xrange内存性能更好,xrange用法与range完全相同,range一个生成list对象,xrange是生成器
16、with上下文机制原理
_enter_和_exit_,上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象类中声明_enter_和_exit_方法,
使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须收到干预
17、经典类、新式类
经典类遵循:深度优先,python2中
新式类遵循:广度优先,Python3中
18、有没有一个工具可以帮助查找Python的bug和进行静态的代码分析?
PyChecker是一个Python代码的静态分析工具,它可以帮助查找Python代码的bug,会对代码的复杂度和格式提出警告,
Pylint是另外一个工具可以进行codingstandard检查
19、 Python是如何进行内存管理的
1.对象引用计数:
引用计数增加的情况:
来保持追踪内存中的对象,所有对象都用引用计数,一个对象分配一个新名称
将其放入一个容器中(列表,字典,元祖)
引用计数减少的情况:
使用del语句对对象别名显示的销毁
引用超出作用域或被重新赋值
sys.getrefcount()函数可以获得对象的当前引用计数
2.标记-清除机制
3.分代技术
20、什么是python?使用python有什么好处?
python是一种编程语言,它有对象、模块、线程、异常处理和自动内存管理。它简洁,简单、方便、容易扩展、有许多自带的数据结果,而且它开源
21、什么是pickling和unpickling?
Pickle模块读入任何python对象,将它们转换成字符串,然后使用dump函数将其转储到一个文件中——这个过程叫做pickling
反之从存储的字符串文件中提取原始python对象的过程,叫做unpickling
22、python是如何被解释的?
Python是一种解释性语言,它的源代码可以直接运行,Python解释器会将源代码转换成中间语言,之后再翻译成机器码再执行
23、数组和元祖之间的区别是什么?
数组和元祖之间的区别:数组内容可以被修改,而元祖内容是只读的,不可被修改的,另外元祖可以被哈希,比如作为字典的key
24、参数按值传递和引用传递是怎么实现的?
python中的一切都是类,所有的变量都是一个对象的引用。引用的值是由函数确定的,因此无法被改变,但是如果一个对象是可以被修改的,你可以改动对象
25、Python都有哪些自带的数据结构?
Python自带的数据结构分为可变和不可变的:可变的有:数组、集合、字典,不可变的是:字符串、元祖、整数
26、什么是python的命名空间?
在python中,所有的名字都存在于一个空间中,它们在改空间中存在和被操作——这就是命名空间,它就好像一个盒子,在每个变量名字都对应装着一个对象,
当查询变量的时候,会从该盒子里面寻找相应的对象
27、python中的unittest是什么?
在python中,unittest是python中的单元测试框架,它拥有支持共享搭建、自动测试、在测试中暂停代码、将不同测试迭代成一组
28、*args与**kwargs
*args代表位置参数,它会接收任意多个参数并把这些参数作为元祖传递给函数。**kwargs代表的关键字参数,返回的是字典,位置参数一定要放在关键字前面
29、在Python中什么是slicing?
slicing是一种在有序的对象类型中(数组、元祖、字符串)节选某一段的语法
30、中的docstring是什么?
Python中文档字符串被称为docstring,它在Python中的作用是为函数、模块和类注释生成文档
31、os与sys区别:
os是模块负责程序与操作系统的交互,提供了访问操作系统底层的接口
sys模块是负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控Python时运行的环境
32、实现一个单例模式
_new_()在 _init_()之前被调用,用于生成实例对象。利用这个方法和类的属性的特点可以实现设计模式的单例模式。
单例模式是指创建唯一对象,单例模式设计的类只能实例,实例化1个对象
class Singleton(object):
__instance=None
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
if Singleton.__instance is None:
Singleton.__instance=object.__new__(cls,*args,**kwargs)
return Singleton.__instance
33、算法(冒泡排序,选择排序,插入排序)
冒泡:首先,列表每两个相邻的数,如果前面的比后边的大,
那么交换这两个数,代码关键点:趟和无序区,
时间复杂度为:O(n2)
import random
def dublue_sort(li):
for i in range(len(li)-1):
exchange= False
for j in range(len(li)-i -1):
if li[j] > li[j+1]:
li[j],li[j+1] = li[j+1],li[j]
exchange = True
if not exchange:
return
return li
li=list(range(100))
random.shuffle(li)
print(li)
print(dublue_sort(li))
选择:一趟遍历记录最小的数,放到第一个位置,再一趟遍历记录剩余列表中最小的数,
继续放置,代码关键点:无序区和最小数的位置,时间复杂度为:O(n2)
def select_sort(li):
for i in range(len(li)-1): #i是趟
min_loc=i
#找i位置到最后位置范围内最小的数
for j in range(i,len(li)):
if li[j] < li[min_loc]:
min_loc = j
#和无序区第一个数作交换
li[min_loc],li[i] = li[i],li[min_loc]
return li
li=list(range(100))
random.shuffle(li)
print(select_sort(li))
插入:列表被分为有序区和无序区两个部分。最初有序区只有一个元素,
每次从无序区选择一个元素,插入到有序区的位置,直到无序区变空,
代码关键点:摸到的牌和手里的牌,时间复杂度为:O(n2)
def insert_sort(li):
for i in range(1,len(li)): #i 代表每次摸到的牌的下标
tmp=li[i]
j = i-1 # j代表手里最后一张牌的下标
while True:
if j < 0 or tmp >= li[j]:
break
li[ j + 1] = li [j]
j -=1
li[j+1] = tmp
li=list(range(100))
print(insert_sort(li))
二分:列表查找:从列表中查找指定元素,输入:列表、待查找元素,输出:元素下标或未查找到元素。
二分查找,从有序列表的候选区data[0:n]开始,通过对待查找的值与候选区中间值的比较,
可以使候选区减少一半。时间复杂为:O(logn)
def bin_search(data,val):
low=0
high=len(data)-1
while low <= high :
mid= (low+high) //2
if data[mid] == val:
return mid
elif data[mid] < high :
low = mid + 1
else:
high = mid - 1
return None
print(bin_search([1,2,3,4,5,6,7,8],4))
四、RESTful API设计指南
参考地址:
http://www.ruanyifeng.com/blog/2014/05/restful_api.html
1、协议
API与用户的通信协议,总是使用HTTPs协议
2、域名
应该尽量将API部署在专用域名之下
https://api.example.com
如果确定API很简单,不会有进一步扩展,可以考虑放在主域名下
https://example.org/api/
3、版本
应该将API的版本号放入URL
https://api.example.com/v1/
另一种做法是:将版本号放在HTTP头信息中,
4、路径
https://api.example.com/v1/zoos
https://api.example.com/v1/animals
https://api.example.com/v1/employees
5、动词
对于资源的具体操作类型,由HTTP动词表示
GET(SELECT):从服务器取出资源(一项或多项)。
POST(CREATE):在服务器新建一个资源。
PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
DELETE(DELETE):从服务器删除资源。
还有两个不常用的HTTP动词
GET /zoos:列出所有动物园
POST /zoos:新建一个动物园
GET /zoos/ID:获取某个指定动物园的信息
PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)
DELETE /zoos/ID:删除某个动物园
GET /zoos/ID/animals:列出某个指定动物园的所有动物
DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物
6、过滤信息(Filtering)
如果记录数量很多,服务器不可能都将它们返回给用户,API应该提供参数,过滤返回结果
?limit=10:指定返回记录的数量
?offset=10:指定返回记录的开始位置。
?page=2&per_page=100:指定第几页,以及每页的记录数。
?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
?animal_type_id=1:指定筛选条件
7、状态码(Status Code)
200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
204 NO CONTENT - [DELETE]:用户删除数据成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
33,海滩上有一堆桃子,五只猴子来分,第一只猴子把这堆桃子平均分成五分,多了一个,这只猴子把多的一个扔到了海里,拿走了一份,第二只猴子把剩下的四堆桃子合在一起,又平均分成五分,又多了一个,它同样把多的一个扔到了海里,拿走了一份,第三只,第四只,第五只都是这样做的,问海滩上原来最少有多少桃子.
作者:可爱宝宝
链接:https://www.pythonheidong.com/blog/article/3830/8bf58cbba6930056f6fd/
来源:python黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 python黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-1
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!