文章目录
迭代器和生成器的区别
一个对象只要实现了__iter__方法就是可迭代的,iter_方法会返回一个迭代器,所谓迭代器就是具有next方法,调用next方法时,迭代器会返回它的下一个值.如果迭代器无值返回,则引发一个StopIteration异常(python3.0中迭代器对象指的是实现__next()方法的)
生成器(一遍循环一边计算)是一种用普通函数语法定义的迭代器,在返回数据的时候使用yield语句(任何包含yield语句的函数都是生成器).当生成器函数被调用时,函数体的代码不会被执行,而是返回一个迭代器.每次请求一个值就会执行生成器中的代码,直到遇到yield或者return 语句
区别:迭代器能做的事情,生成器都能做.生成器自动创建了__iter__()和__next__()方法,使得函数显得简洁.此外,使用生成器推导式(生成器表达式)取代列表推导式解析可以节省内存和cpu;生成器只能遍历一次
参考:https://blog.csdn.net/u014745194/article/details/70176117
https://www.cnblogs.com/wj-1314/p/8490822.html
如何提高python 的运行效率
1)使用生成器
2)关键代码使用外部功能包,比如cython等
3)针对循环优化,尽量避免在循环中方位变量属性
python 如何进行内存管理
1,引用计数:
python中,每一个对象都有一个引用计数,引用计数为了指向该对象的引用总数.当一个对象的引用计数为0时,对象被垃圾回收
引用计数增加的情况:
1)创建对象(x=4);另外被别人创建(y = x);
2)被当做参数传递给函数(f(x));
3)作为容器对象的一个元素(a = [1,x,“33”])
引用计数减少的情况:
1)一个本地引用离开了作用域(上面的f(x)函数结束时,x指向的对象引 用减一);
2)对象的别名被显式销毁(del x);
3)对象的一个别名被赋值给其他对象(x = 789);
4)对象从一个窗口对象中移除(myList.remove(x));
5)窗口对象本身被销毁或者窗口对象本身离开了作用域(def myList)
2,垃圾回收:
当内存中有不再使用的部分时,垃圾收集器就会把他们清理掉.垃圾收集器会去检查那些引用计数为0的对象,清除其在内存中的空间.垃圾回收机制里有一个循环垃圾回收器,用于确保释放循环引用对象(a引用b, b引用a, 导致引用计数永远不为0) 启动垃圾回收就不能做其他任务了,所以内存中的对象不多就没有必要总启动垃圾回收.所以,Python只会在特定条件下,自动启动垃圾回收。当Python运行时,会记录其中分配对象(object allocation)和取消分配对象(object deallocation)的次数。当两者的差值高于某个阈值时,垃圾回收才会启动
[前情了解:在python中,很多时候申请内存都是小块的内存,这些小内存申请后很快又被释放,由于这些内存的申请不是为了创建对象,所以没有对象一级的内存池机制.这就意味着Python在运行期间会大量地执行malloc和free的操作,频繁地在用户态和核心态之间进行切换,这将严重影响Python的执行效率。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放]
3,内存池机制:经由内存池登记的内存不用了以后还是回收到内存池而不是返回给操作系统.
Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的 malloc。另外Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数
参考:https://www.cnblogs.com/vamei/p/3232088.html
Python语言的特点
Python简单易学,既支持面向过程编程,也支持面向对象编程.所以对于开发者而言,使用python可以专注精力于逻辑问题而不是程序语言和语法上.
python免费开源,所以逐渐形成强壮的python社区,社区中有丰富的python库
python可以兼容众多平台
python几乎适用任何开发,它跟其他语言相比因为语法简洁库丰富,它显著提高了程序员的开发效率,一定程度上可以认为它牺牲了代码工作性能.
java是静态编译性语言,它编写时需要定义变量类型,编译后才可以运行,编辑过程中可以检查语法问题,运行时变量类型已经固定了.而Python是动态解释性语言,无需定义变量类型,也无需编译,直接在解释器环境下运行(边解释边执行).
python动态性和解释性使得执行效率不够高成为必然
python数据类型
python的基本数据类型有str,tuple,list,dict,set和Number类型六种,其中数字类型里包括了bool,float,complex, int4种
可变数据类型:list,dict,set
不可变数据类型:str,tuple,Number
python字符串格式化方法
1)百分号方式
2)format方法
type 和isinstance区别
type()不会认为子类是一种父类类型
isinstance()会认为子类是一种父类类型
对GIL(Global Interpreter Lock)全局解释器锁的理解
GIL对多线程的影响简单可以理解为"一个线程运行python,而其他N个睡眠或者等待I/O",也就是保证同一个时刻,只有一个线程对共享资源进行存取.多线程任务中,GIL的存在容易造成任务迟迟不被调度执行导致超时问题.实际工程项目中可以用多进程(每一个进程拥有一个GIL)或者协程方式替代多线程.
协同式多任务处理:当某个任务(比如I/O启动任务)在长的或者不确定的时间没有运行Python代码的需要就会让出GIL,从而其他线程可以获取GIL来运行python. multiprocess->Thread
抢占式多任务处理:线程可以主动释放GIL,也可以先发制人抓取GIL. python程序运行分为两个阶段,第一,python文本被编译成字节码的二进制格式.第二,python解释器的pyeval_evalframeex()函数读取字节码,逐个执行其中指令.当解释器读取字节码时会定期放弃GIL,而不需要经过正在执行代码的线程允许.这样,其他线程就可以抢占GIL运行代码了.
参考:https://www.cnblogs.com/SuKiWX/p/8804974.html
同步异步,阻塞非阻塞
同步和异步是一种访问数据的机制,同步一般主动请求并且等待I/O操作完毕的方式,异步指请求数据后便可以继续处理其他任务,同时等待I/O操作完毕的通知
阻塞和非阻塞是指进程访问的数据如果尚未就绪,进程是否需要等待的问题(直接返回还是等待就绪),等待就绪的称为阻塞
参考:https://www.cnblogs.com/George1994/p/6702084.html
4,find 和grep?
grep命令是一种强大的文本搜索工具,其搜索内容串可以是正则表达式,允许对文本文件进行模式查找.而find通常用来在特定目录下搜索符合条件的文件,也可以用来搜索特定用户属主的文件
5,线上服务因某种原因挂掉解决方案
linux下的后台进程管理利器supervisor 每次文件修改后再linux执行servise supervisord restart
如何定位Python程序的性能问题
python有很多性能测试工具,比如 timeit、profile、cProfile、line_profiler、memory_profiler、PyCharm图形化性能测试工具、objgraph。其中timeit,profile,cProfile都是python内置模块,其余为第三方模块。
1)timeit只输出被测试代码的总运行时间,单位为秒,没有详细的统计
2)profile(python实现的)返回四个参数,
ncall:函数运行次数;
tottime: 函数的总的运行时间,减去函数中调用子函数的运行时间;
第一个percall:percall = tottime / nclall ;
cumtime:函数及其所有子函数调整的运行时间,即函数开始调用到结束的时间
第二个percall:percall = cumtime / nclall
3)cProfile是c语言实现的,返回结果同profile一样
4)line_profiler统计每行代码的执行次数和执行时间等,时间单位为微妙。使用时在 需要测试的函数加上@profile装饰,运行命令为:kernprof -l -v C:\Python34\test.py 返回参数有
Total Time:测试代码的总运行时间 ;
Hits:表示每行代码运行的次数 ;
Time:每行代码运行的总时间 ;
Per Hits:每行代码运行一次的时间
% Time:每行代码运行时间的百分比
5) memory_profile可以统计每行代码占用的内存大小,使用时在需要测试的函数加上@profile装饰,运行命令为: python -m memory_profiler C:\Python34\test.py
6)对于pycharm开发环境来说,可以直接在菜单栏上点击【run】-【Profile xxx.py】就可以看到统计和函数调用分析图
7)objgraph可以列出当前当前内存中存在的对象,可用于定位内存泄漏
IPython是一个基于Python Shell的交互式解释器,它提供了很多Magic函数,其中%prun和%lprun分别用于统计个函数调用次数及耗时和统计各行代码的调用次数及时耗。
# -T选项指定写到的文本文件, -l选项指定只显示前多少行
# 另外也可以用 -l <partial func name> 来过滤,只保留name包含指定子串的函数
%prun -T ./res/prun.txt -l 20 f()
# 另外还有一个cell magic,叫 %%prun
# 它相当于把cell内的多行代码,合并成一行长代码;作为最后一个参数送给 %prun;以免用f()来封装代码的麻烦
#===================================================================================
# 没有-l选项了,只有-f和-m选项
# -f func1 -f func2 -m module1 -m module2 <code to profile> 表示只统计指定的func1和func2两个函数,以及module1和module2两个模块的代码行
# 注意-f指定的必须是可以找到的函数对象,不是函数名称的子串,这一点跟prun有区别
%lprun -T ./res/lprun.txt -f Detector.score_by_sliding_window f()
提升Python程序性能小技巧
1,生成器替换列表
2,直接迭代序列元素,比索引要快 ,eg:在访问arr数组中元素时,for item in arr比for i in range(len(arr))更快
3,尽可能使用映射替换条件搜索 ,映射的搜索速度更快,比如dict比if搜索快
4,尽可能使用局部变量 ,局部变量相对容易维护,而且局部变量的搜素速度更快,这样可以帮助提高性 能和节省内存
5,减少函数调用,比如确定对象类型时,isinstance()>id()>type();重复操作避免放置循环体内
6,先编译好再调用,避免重复编译
7,直接" ".join(arr)替换循环体内str拼接+
python异常处理
python的异常处理通常是用try/except去捕获异常
1)try…except… else(也可以没有else)
try:
block1 #运行代码
except(Exception1,Exception2...) as e:
block2 #如果block1出现上述异常;但如果block1没有出现上面指定的异常,则程序结束
else:
block3 #如果block1无异常
2)try…except…else…finally
try:
block1
except Exception as e:
print e #捕获异常
else:
block2 # block1无发生异常
finally:
block2 #无论block1是否发生异常都会执行
3)raise 触发用户自定义异常
class NetworkError(Exception):
def __init__(self,arg):
self.arg=arg
try:
raise networkError("bad hostname")
except NetworkError as e:
print e.arg
with-block 上下文管理器
with是从Python2.5引入的一个新的语法,它是一种上下文管理协议,目的在于从流程图中把 try,except 和finally 关键字和资源分配释放相关代码统统去掉,简try….except….finlally的处理流程。显然,with是使用那些需要对资源进行访问的场景。with通过__enter__方法初始化,然后在__exit__中做善后以及处理异常。所以with处理的对象必须有这两个方法。
# 基本结构
with expression [as variable]:# expresiion就是上下文管理器, variable接收expression进入__enter__()函数后返回的对象
with-block # 此处为执行代码,代码执行结束后wiexpression会调用__exit__()函数进行资源清理
# for example
with open("xx.txt") as f:
for line in f.readlines():
print line
如果要自定义一个上下文管理器,那就需要定义一个实现__enter__()和__exit__()的类
# 数据库连接
class DBConnection():
def __init__(self):
pass
def cursor(self):
pass
def commit(self):
pass
def rollback(self):
pass
def __enter__(self):
cursor = self.cursor()
return cursor
def __exit__(self, type, value, tb):
if tb is none:
# 无异常,提交事务
self.commit()
else:
# 异常,回滚数据库
self.rollback()
def test():
sql=""
con = DBConnection()
with con as cursor:
cursor.execute(sql)
上述是自定义了一个上下文管理器,python的contextlib模块提供了封装好的实现自定义上下文管理器的方法。想要自定义上下文管理器时,只要借助contextlib模块中的装饰器contextmanager写一个生成器函数就可以了。
#定义生成器函数
@contextmanager
def transaction(db):
db.begin()
try:
yield f # yield前的代码相当于__enter__()函数,yield的返回值相当于__enter__()函数的返回值
except :
db.rollback()
raise
else:
db.commit()
if __name__=="__main__":
db = MySQLdb.connect("localhost", "testuser", "test123", "TESTDB", charset='utf8' )
with transaction(db) as cursor:
cursor.execute(sql) ~~删除线格式~~