写在前面
Python是一门解释型的、动态型的OOP语言,结识Python的这几年来,其语法的简洁、结构的条理性深刻的吸引了我。下面是我总结出来的一些Python常用知识点。
列表碾平式
需求: 将[[1,2],[3,4]] 转换为[1,2,3,4],具体实现有以下几种方法
test_list = [[1,2],[3,4]]
1. from itertools import chain
list(chain.from_iterable(test_list))
结果:[1, 2, 3, 4]
2. from itertools import chain
list(chain(*test_list))
结果:[1, 2, 3, 4]
3. sum(test_list, [])
结果:[1, 2, 3, 4]
4. [x for y in test_list for x in y]
结果:[1, 2, 3, 4]
5. 万能方法(递归)
func = lambda x: [y for t in x for y in func(t)] if type(x) is list else [x]
func(test_list)
结果:[1, 2, 3, 4]复制代码
PS: 项目中,难免会有类似的需求,对于结构嵌套一致的情况,上述的1,2,3,4方法都可以很好的解决(不建议用for循环嵌套的方式,那是最low的方法,没有之一);对于结构嵌套不一致的情况,第5种方法就派上了用场,其采用了递归的思想,堪称万能的方法,屡试不爽。项目中,大家可以根据实际应用场景来挑选最适合自己的方法。肚中有粮,心中不慌;大家可以把上述方法都记下来,以做到有的放矢。
三目操作符
对于Python的三元表达式,想必大家对if else
都不会感到陌生,但是对and or
操作想必是另一种感觉了,不过大家对其他语言的? :
应该不会陌生,没错,这次的主角and or
就和? :
有着异曲同工之妙。
代码参考:
1 == 1 and 2 or 3 返回2
1 == 2 and 2 or 3 返回3复制代码
PS:习惯于if else
的同学偶尔用下and or
是不是会给人耳目一新的感觉。
and or 分开来用
- [x] and 用法如下:
1 and 2 and 3 返回3
1 and 2 and '' 返回''
'' and 2 and 0 返回''
PS:如果都为真则返回最后一个值,如果其中某些值为假,则返回第一个为假的值复制代码
- [x] or 用法如下
1 or '' or 0 返回1
'' or 0 or [] 返回[]
PS:如果都为假返回最后一个值,如果其中某些值为真,则返回第一个为真的值复制代码
使用场景:在项目中我们经常会有这样的需求,在将一个字典更新之后还想要返回更新后的字典,这是我们就可以这样写:dic = dic1.update(dic2) or dic1
列表推导式
需求:将[1,2,3]中的每一项都加1
good: [x+1 for x in [1,2,3]]
bad: def add_list(goal_list):
tmp_list = []
for x in goal_list:
tmp_list.append(x+1)复制代码
PS: 列表推导式底层是用C实现的,其执行速度要比for循环快好多
vars() 用法
代码参考:
```
def func(a, b, c):
print vars()
执行func(1, 2, 3)
输出:{"a":1,"b":2,"c":3}
PS: vars()的值为字典,其键值对来源于当前作用域的所有变量。
```复制代码
使用场景:在调用他人接口或方法时,需要将传入的参数打印以记录日志,此刻vars()便派上用场了。
偏函数之partial
代码示例:
import functools
def add(a, b):
return a + b
add(4, 2)
6
plus3 = functools.partial(add, 3)
plus5 = functools.partial(add, 5)
plus3(4)
7
plus3(7)
10
plus5(10)
15复制代码
实际使用心得:
之前做对象存储的项目中,我需要同时去调用三个一样的接口(大部分参数一样)下面是我的部分代码,供大家参考
my_thread = functools.partial(myThread, dic, zone_id, start, end, customer_id) my_thread1 = my_thread("day", "gets", "2") my_thread1 = my_thread("day", "original_traffic", "3")复制代码
使用场景:
当我们需要同时去调用一个函数,并且发现大部分参数一致的时候,便可以采取上述方法,一来代码简洁,二来可读性高。
Python搭建简易服务
- Python搭建简易邮件服务器:
python -m smtpd -n -c DebuggingServer localhost:1025
Python搭建简易web服务器:
- Python2:
python -m SimpleHTTPServer port
- Python3:
python -m http.server port
- Python2:
Python搭建简易ftp服务
pip install pyftpdlib python -m pyftpdlib -p 21 ftp://localhost:21复制代码
遍历字典
在项目中遍历字典是很常见的需求,下面介绍下常用的方法并做下比较:
dic = {'name': 'peter', 'age': 27}
1. for key, value in dic.items():
print key, value
2. for key, value in dic.iteritems():
print key, value复制代码
PS:iteritems
和items
的区别在于iteritems
采用了生成器的原理,只有在需要的时候才会把值生成,其之间的区别类似于range
和 xrange
;readline
和 xreadline
内存管理
Python的内存管理主要分为引用计数和垃圾回收机制两大部分,且看下面代码:
[ ] 内存分配:
a = 1 b = 1 a is b True --------------------- a = 1000 b = 1000 a is b False复制代码
PS: 在Python中,整数和短小的字符,Python都会缓存这些对象,以便重复使用。当我们创建多个等于1的引用时,实际上是让这些引用指向了同一个对象。
[ ] 引用计数:
在Python中,所谓引用计数(reference count)是指所有指向该对象的引用的总数;
我们可以使用
sys
包中的getrefcount()
,来查看某个对象的引用计数。需要注意的是,当使用该函数查看某个对象的引用计数时,实际上是临时创建了该对象的一个新的引用,所有使用getrefcount()
所得到的结果,会比期望的值多1。from sys import getrefcount aa = 'test refcount' print(getrefcount(a)) bb = aa print(getrefcount(a))复制代码
PS: 由于上述原因,两个
getrefcount()
将返回2和3,并不是期望的1和2.[ ] 引用减少
引用减少大致分为两类:
指向该对象的引用指向了其他对象
from sys import getrefcount aa = 'test refcount' bb = aa print(getrefcount(aa)) 3 bb = 1 print(getrefcount(aa)) 2复制代码
使用
del
关键字显示的删除某个引用from sys import getrefcount aa = 'test refcount' bb = aa print(getrefcount(aa)) 3 del bb print(getrefcount(aa)) 2复制代码
[ ] 垃圾回收
不断的创建对象,如果不及时销毁的话,那Python的体积会越来越大,再大的内存也会有耗完的时候;不用像C语言那样,需要手动的去管理内存、Python已经帮我们做好了(Python的垃圾回收机制),你只需要去关心你的业务逻辑即可,其他的都交给Python来处理。
从原理上讲,当Python中某个对象的引用计数降为0时,该对象就应该被回收。但是频繁的启动垃圾回收机制毕竟是个很耗时的问题;因此Python只有在特定条件下(当Python中被分配对象和取消分配对象的次数之间的差值达到某个阈值时),Python会自动启动垃圾回收机制。
我们可以通过
gc
模块的get_threshold()
方法,查看该阈值:import gc print(gc.get_threshold())复制代码
该方法会返回
(700, 10, 10)
,后面的俩10是与分代回收相关的,稍后讲解。700便是垃圾回收机制启动的阈值。可以通过gc
模块中的set_threshold()
方法重新设定该值。当然了,我们也可以手动启动垃圾回收机制,使用
gc.collect()
即可。[ ] 分代回收
Python同时采用了分代回收的机制,设想一下:存活越久的对象、越不可能是垃圾对象。程序在运行时,往往会产生大量的临时对象,程序结束之后,这些临时对象的生命周期也就随之告一段落。但有一些对象会被长期占用,垃圾回收机制在启动的时候会减少扫描到他们的频率。
Python将所有对象分为0,1,2三代。所有新创建的对象都是0代,当垃圾回收机制在启动多次0代机制并扫描到他们的时候,这些对象如果依然存活在内存的话,他们就会被归入下一代对象,以此类推。
刚才上面所提到的
(700, 10, 10)
三个参数后面的俩10所代表的意思是:每10次0代垃圾回收,会配合1次1代的垃圾回收;而每10次1代的垃圾回收会配合1次的2代垃圾回收。当然我们同样可以使用
set_threshold()
来调整此策略的比例,比如对1代对象进行更频繁的扫描。import gc gc.set_threshold(700, 5, 10)复制代码
新式类、经典类
[ ] 新式类: 显示的继承了
object
的类class A(object): attr = 1 class B(A): pass class C(A): attr = 3 class D(B, C): pass if __name__ == '__main__': d = D() print 'attr = ', d.attr # attr = 3复制代码
[ ] 经典类:没有继承自
object
的类class A(): attr = 1 class B(A): pass class C(A): attr = 3 class D(B, C): pass if __name__ == '__main__': d = D() print 'attr = ', d.attr # attr = 1复制代码
PS: 通过以上代码的输出结果可以看出,新式类会广度搜索,也就是一层层的向上搜索;经典类是深度优先,即遇到一个超类点就向上搜索。
装饰器
Python的装饰器被称为Python的语法糖,哪里需要粘哪里。
代码示例:
@makeh1
@makeeitalic
def say():
return 'Peter'
我们希望输出结果为:<h1><i>Peter</i></h1>复制代码
去看看官方文档,答案就看下面:
def makeh1(func):
def wrp():
return "<h1>" + func() + "</h1>"
return wrp
def makeeitalic(func):
def wrp():
return "<i>" + func() + "</i>"
return wrp
@makeh1
@makeeitalic
def say():
return 'Hello Peter'
print say()
输出:<h1><i>Hello Peter</i></h1>复制代码
实际应用场景:
使用过django
的小伙伴想必都用过login_required
装饰器,但是如果用户没登录的话login_required
会重定向到登录页面;在做web开发的过程中,我们会经常用
ajax异步提交数据到后台,这时如果再继续使用原有的login_required
装饰器肯定是不行了(该装饰器不会重定向到登录页面,ajax也没有任何返回结果),下面我们改变下原有代码:
from django.shortcuts import HttpResponse
import json
def is_authenticat(func):
def wrp(req, **kwargs):
if req.user.is_authenticated():
return func(req, **kwargs)
else:
json_str = {'status': 0, 'msg': u'请登录'}
return HttpResponse(json.dumps(json_str), content_type='application/json')
return wrp复制代码
上述代码便很好的解决了问题,也算是对Python装饰器的一个很好的使用场景。
写在结语
Python的奥妙远不止于此
Python的深度还需要继续探索
以上就是平时工作中所总结出来的常用的知识点
希望对大家以后的工作会有所帮助