1.谈一谈Python的装饰器(decorator)
- 引入日志
- 函数执行时间统计
- 执行函数钱预备处理
- 执行函数后的清理功能
- 权限校验等场景
- 缓存
2.简要描述Python的垃圾回收机制
引用计数:Python在内存中存储每个对象的引用计数,如果计数变成0,该对象就会消失,分配给该对象的内存就会释放出来。
标记-清除:一些容器对象,比如list、dict、tuple,instance等可能会出现引用循环,对于这些循环,垃圾回收器会定时回收这些循环(对象之间通过引用(指针)连在一起,构成一个有向图,对象构成这个有向图的节点,而引用关系构成这个有向图的边)。
分代收集:Python把内存根据对象存活时间划分为三代,对象创建之后,垃圾回收器会分配它们所属的代。每个对象都会被分配一个代,而被分配更年轻的代是被优先处理的,因此越晚创建的对象越容易被回收。
2. __new__和__init__的区别
_new_ 方法负责创建一个实例对象,_init_ 方法负责将该实例对象进行初始化;
new() 方法是在类准备将自身实例化时调用;
-new() 方法始终都是类的静态方法,即使没有被加上静态方法装饰器 ;
继承自object的新式类才有new;
new至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供;
-new必须要有返回值,返回实例化出来的实例,这点在自己实现new时要特别注意,可以return父类new出来的实例,或直接是object的new出来的实例。
_init_有一个参数self,就是这个_new_返回的实例,_init_在_new_的基础上可以完成一些其它初始化的动作,_init_不需要返回值;
3.说一说Python自省
help,dir([obj]),sys,type().....
4.Python是如何进行内存管理的?
从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制
一、对象的引用计数机制
python内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数。
引用计数增加的情况:
1,一个对象分配一个新名称
2,将其放入一个容器中(如列表、元组或字典)
引用计数减少的情况:
1,使用del语句对对象别名显示的销毁
2,引用超出作用域或被重新赋值
sys.getrefcount( )函数可以获得对象的当前引用计数
多数情况下,引用计数比你猜测得要大得多。对于不可变数据(如数字和字符串),解释器会在程序的不同部分共享内存,以便节约内存。
二、垃圾回收
1,当一个对象的引用计数归零时,它将被垃圾收集机制处理掉。
2,当两个对象a和b相互引用时,del语句可以减少a和b的引用计数,并销毁用于引用底层对象的名称。然而由于每个对象都包含一个对其他对象的应用,因此引用计数不会归零,对象也不会销毁。(从而导致内存泄露)。为解决这一问题,解释器会定期执行一个循环检测器,搜索不可访问对象的循环并删除它们。
三、内存池机制
Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。
1,Pymalloc机制。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。
2,Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的malloc。
3,对于Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。
5.Python里面如何实现tuple和list的转换?
函数tuple(seq)可以把所有可迭代的(iterable)序列转换成一个tuple, 元素不变,排序也不变。
例如,tuple([1,2,3])返回(1,2,3),tuple(’abc’)返回(’a’.’b',’c').如果参数已经是一个tuple的话,函数不做任何拷贝而直接返回原来的对象,所以在不确定对象是不是tuple的时候来调用tuple()函数也不是很耗费的。
函数list(seq)可以把所有的序列和可迭代的对象转换成一个list,元素不变,排序也不变。
例如list([1,2,3])返回(1,2,3),list(’abc’)返回['a', 'b', 'c']。如果参数是一个list,她会像set[:]一样做一个拷贝
6.Python里面如何拷贝一个对象?
一般来说可以使用copy.copy()方法或者copy.deepcopy()方法,几乎所有的对象都可以被拷贝
一些对象可以更容易的拷贝,Dictionaries有一个copy方法:
newdict = olddict.copy()
7.用Python来进行查询和替换一个文本字符串?
可以使用sub()方法来进行查询和替换,sub方法的格式为:sub(replacement, string[, count=0]) replacement是被替换成的文本 string是需要被替换的文本 count是一个可选参数,指最大被替换的数量
例子:
import re
p = re.compile(’(blue|white|red)’)
print(p.sub(’colour’,'blue socks and red shoes’))
print(p.sub(’colour’,'blue socks and red shoes’, count=1))
输出:
colour socks and colour shoes
colour socks and red shoes
subn()方法执行的效果跟sub()一样,不过它会返回一个二维数组,包括替换后的新的字符串和总共替换的数量
例如:
import re
p = re.compile(’(blue|white|red)’)
print(p.subn(’colour’,'blue socks and red shoes’))
print(p.subn(’colour’,'blue socks and red shoes’, count=1))
输出
(’colour socks and colour shoes’, 2)
(’colour socks and red shoes’, 1)
8.Python里面match()和search()的区别?
match()函数只检测RE是不是在string的开始位置匹配, search()会扫描整个string查找匹配, 也就是说match()只有在0位置匹配成功的话才有返回,如果不是开始位置匹配成功的话,match()就返回none
9. 迭代器和生成器
迭代器:是访问集合元素的一种方式,从集合的第一个元素开始访问,直到所有元素被访问结束。其优点是不需要事先准备好整个迭代过程中的所有元素,仅在迭代到某个元素时才开始计算该元素。适合遍历比较巨大的集合。__iter__():方法返回迭代器本身,__next__():方法用于返回容器中下一个元素或数据。
生成器:带有yield的函数不再是一个普通函数,而是一个生成器。当函数被调用时,返回一个生成器对象。不像一般函数在生成值后退出,生成器函数在生成值后会自动挂起并暂停他们的执行状态。
'''迭代器'''
print('for x in iter([1, 2, 3, 4, 5]):')
for x in iter([1, 2, 3, 4, 5]):
print(x)
'''生成器'''
def myyield(n):
while n>0:
print("开始生成...:")
yield n
print("完成一次...:")
n -= 1
for i in myyield(4):
print("遍历得到的值:",i)
9.闭包
闭包可以实现先将一个参数传递给一个函数,而并不立即执行,以达到延迟求值的目的。满足以下三个条件:必须有一个内嵌函数;内嵌函数必须引用外部函数中变量;外部函数返回值必须是内嵌函数。
10.什么是GIL
Python代码的执行由python虚拟机(也叫解释器主循环,CPython版本)来控制,Python在设计之初就考虑到要在解释器的主循环中,同时只有一个线程在执行,即任意时刻,只有一个线程在解释器中运行。对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。
11.对比一下dict中items 与iteritems
dict.items()返回的是一个完整的列表,而dict.iteritems()返回的是一个生成器(迭代器)。
dict.items()返回列表list的所有列表项,形如这样的二元组list:[(key,value),(key,value),...],dict.iteritems()是generator, yield 2-tuple。相对来说,前者需要花费更多内存空间和时间,但访问某一项的时间较快(KEY)。后者花费很少的空间,通过next()不断取下一个值,但是将花费稍微多的时间来生成下一item。
12.是否遇到过python的模块间循环引用的问题,如何避免它
这是代码结构设计的问题,模块依赖和类依赖 如果老是觉得碰到循环引用,很可能是模块的分界线划错地方了。可能是把应该在一起的东西硬拆开了,可能是某些职责放错地方了,可能是应该抽象的东西没抽象 总之微观代码规范可能并不能帮到太多,重要的是更宏观的划分模块的经验技巧,推荐uml,脑图,白板等等图形化的工具先梳理清楚整个系统的总体结构和职责分工 采取办法,从设计模式上来规避这个问题,比如: 1. 使用 “__all__” 白名单开放接口 2. 尽量避免 import
13.python数据结构
list,tuple, dict, set
14.Python如何实现单例模式?其他23种设计模式python如何实现?
https://www.cnblogs.com/huchong/p/8244279.html
15.解释一下WSGI 和FastCGI 的关系?
WSGI是python的接口规范,这个规范是针对WEB服务器和python应用(框架等)的交互的。FASTCGI则是两者底层的通信协议的规范。
16.解释一下Django 和Tornado 的关系、差别
Django适合初学者或者小团队的快速开发,适合做管理类、博客类网站、或者功能十分复杂需求十分多的网站
Tornado适合高度定制,适合访问量大,异步情况多的网站
17.解释下Django使用redis缓存服务器
为了能在Django中使用redis,还需要安装redis for Django的插件。然后在Django的settings中配置了。
18. scrapy框架
1.首先Spiders(爬虫)将需要发送请求的url(requests)经ScrapyEngine(引擎)交给Scheduler(调度器)。
2.Scheduler(排序,入队)处理后,经ScrapyEngine,DownloaderMiddlewares(可选,主要有User_Agent, Proxy代理)交给Downloader。
3.Downloader向互联网发送请求,并接收下载响应(response)。将响应(response)经ScrapyEngine,SpiderMiddlewares(可选)交给Spiders。
4.Spiders处理response,提取数据并将数据经ScrapyEngine交给ItemPipeline保存(可以是本地,可以是数据库),提取url重新经ScrapyEngine交给Scheduler进行下一个循环。直到无Url请求程序停止结束。
19.什么是Flask?
Flask 是 Python 编写的一款轻量级 Web 应用框架。其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2。Flask 使用 BSD 授权。其中两个环境依赖是 Werkzeug 和 jinja2,这意味着它不需要依赖外部库。正因如此,我们将其称为轻量级框架。
Flask 会话使用签名 cookie 让用户查看和修改会话内容。它会记录从一个请求到另一个请求的信息。不过,要想修改会话,用户必须有密钥 Flask.secret_key。
21.当退出Python时,是否释放全部内存?
No。循环引用其它对象或引用自全局命名空间的对象的模块,在 Python 退出时并非完全释放。另外,也不会释放 C 库保留的内存部分。
22. 写一个简单的python socket编程
python 编写server的步骤:1第一步是创建socket对象。调用socket构造函数。如:socket = socket.socket(family, type ) family参数代表地址家族,可为AF_INET或AF_UNIX。AF_INET家族包括Internet地址,AF_UNIX家族用于同一台机器上的进程间通信。type参数代表套接字类型,可为SOCK_STREAM(流套接字)和SOCK_DGRAM(数据报套接字)。
2.第二步是将socket绑定到指定地址。这是通过socket对象的bind方法来实现的:socket.bind( address )由AF_INET所创建的套接字,address地址必须是一个双元素元组,格式是(host,port)。host代表主机,port代表端口号。如果端口号正在使用、主机名不正确或端口已被保留,bind方法将引发socket.error异常。
3.第三步是使用socket套接字的listen方法接收连接请求。socket.listen( backlog )backlog指定最多允许多少个客户连接到服务器。它的值至少为1。收到连接请求后,这些请求需要排队,如果队列满,就拒绝请求。
4.第四步是服务器套接字通过socket的accept方法等待客户请求一个连接。connection, address =socket.accept()调用accept方法时,socket会时入“waiting”状态。客户请求连接时,方法建立连接并返回服务器。accept方法返回一个含有两个元素的元组(connection,address)。第一个元素connection是新的socket对象,服务器必须通过它与客户通信;第二个元素address是客户的Internet地址。
5. 第五步是处理阶段,服务器和客户端通过send和recv方法通信(传输数据)。服务器调用send,并采用字符串形式向客户发送信息。send方法返回已发送的字符个数。服务器使用recv方法从客户接收信息。调用recv 时,服务器必须指定一个整数,它对应于可通过本次方法调用来接收的最大数据量。recv方法在接收数据时会进入“blocked”状态,最后返回一个字符串,用它表示收到的数据。如果发送的数据量超过了recv所允许的,数据会被截短。多余的数据将缓冲于接收端。以后调用recv时,多余的数据会从缓冲区删除(以及自上次调用recv以来,客户可能发送的其它任何数据)。
6. 传输结束,服务器调用socket的close方法关闭连接。
python编写client的步骤:
1. 创建一个socket以连接服务器:socket= socket.socket( family, type )
2.使用socket的connect方法连接服务器。对于AF_INET家族,连接格式如下:socket.connect((host,port) )host代表服务器主机名或IP,port代表服务器进程所绑定的端口号。如连接成功,客户就可通过套接字与服务器通信,如果连接失败,会引发socket.error异常。
3. 处理阶段,客户和服务器将通过send方法和recv方法通信。
4. 传输结束,客户通过调用socket的close方法关闭连接。
下面给个简单的例子:
server.py
if __name__ =='__main__':
import socket
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.bind(('localhost',8001))
sock.listen(5)
while True:
connection,address =sock.accept()
try:
connection.settimeout(5)
buf =connection.recv(1024)
if buf == '1':
connection.send('welcometo server!')
else:
connection.send('pleasego out!')
except socket.timeout:
print 'time out'
connection.close()
client.py
python 代码
if __name__ =='__main__':
import socket
sock =socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('localhost',8001))
import time
time.sleep(2)
sock.send('1')
print sock.recv(1024)
sock.close()
在终端运行server.py,然后运行clien.py,会在终端打印“welcometo server!"。如果更改client.py的sock.
23.tornado的核心
Tornado 的核心是 ioloop 和 iostream 这两个模块,前者提供了一个高效的 I/O 事件循环,后者则封装了 一个无阻塞的 socket 。通过向 ioloop 中添加网络 I/O 事件,利用无阻塞的 socket ,再搭配相应的回调 函数,便可达到梦寐以求的高效异步执行。
24. post和get
-
GET在浏览器回退时是无害的,而POST会再次提交请求。
-
GET产生的URL地址可以被Bookmark,而POST不可以。
-
GET请求会被浏览器主动cache,而POST不会,除非手动设置。
-
GET请求只能进行url编码,而POST支持多种编码方式。
-
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
-
GET请求在URL中传送的参数是有长度限制的,而POST么有。
-
对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
-
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
-
GET参数通过URL传递,POST放在Request body中。
25 string和list互转
list转字符串 .join(list) 字符串转list list(string)
26. find 和grep
grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来。find命令的作用是在目录中搜索文件
27. 如何提高python运行效率
关键代码使用外部功能包;在排序时使用键;对循环的优化
28. yield的用法
yield简单来说就是一个生成器,这样函数它记住上次返回时在函数中的位置。对于生成器第二次(或n次)调用跳转至该函数。
29. 描述数组、链表、队列、堆栈的区别?
数组和链表是数据存储方式的概念,数组在连续的空间中存储数据,而链表可以在非连续的空间中存储数据;队列和堆栈是描述数据存取方式的概念,队列是先进先出,而堆栈是后进先出;队列和堆栈可以用数组来实现,也可以用链表实现。
30.RESTFUL
- 每一个URI代表一种资源;
- 客户端和服务器之间,传递这种资源的某种表现层;
- 客户端通过四个HTTP动词(GET.POST,PUT,DELETE),对服务器端资源进行操作,实现"表现层状态转化".
31. python的常用算法
https://blog.csdn.net/ZhangQiye1993/article/details/81532103
32.open和send
open在post,get都可以,send只能post