分享一篇文章,没有什么奇技淫巧,只是一些简单的小贴士,贴到这里用来提醒一下自己:Python编程方面的一些技巧。
1. list切片的技巧 somelist[start:end:stride]
test = [1, 2, 3, 4, 5]
# 从索引最开始到结束,每隔两个取出一个
# 实际上就是肉眼数的奇数位,索引的偶数位
odds = test[::2]
print(odds) # 结果 -> [1, 3, 5]
# 从索引第一位到结束,每隔两个取出一个
# 实际上就是肉眼数的偶数位,索引的奇数位
evens = test[1::2]
print(evens) # 结果 -> [2, 4]
# 对于byte的字符串来说还有神奇的特效(only byte)
byte_str = b'abcd'
print(byte_str[::-1]) # 结果 -> dcba
# 尽量不要很复杂的切片方式,尽量能够多次解决复杂
# 不要同时出现start end stride三个参数
2. 多使用列表表达式
# 1. 例子没有
# list, dict, set都有对列表表达式的支持
# 列表表达式代替使用map和filter,可以避免写lambda函数
# 2. 例子
# 列表表达式处理多重for循环
martix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat_list = [x for row in martix for x in row]
print(flat_list) # 结果 -> [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 拆解代码大致就是:
new_list = []
for row in martix:
for x in row:
new_list.append(x)
# 3.例子
# 从一个列表中找出一个数字大于4且是偶数的
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 第一种
b = [x for x in a if x > 4 if x % 2 ==0]
# 第二种
c = [x for x in a if x > 4 and x % 2 ==0]
# 结果都是一样的,只是判断上的区别
# Tips:
# 列表表达式能用就尽量用,可以缩减一些代码量,但是不要写的过于复杂
# 太复杂的表达式,查bug更难找,而且也不利于别人进行维护
3. 数据量大的时候尽量使用生成器表达式代替列表表达式
# 原因很简单,列表表达式需要开辟较大的内存空间进行存储
"""
官方解释: 生成器表达式,它是对推导和生成器的一种泛化。
生成器在运行时不会将整个输出序列呈现出来,而是会估值为迭代器,
这个迭代器每次可以根据生成器表达式产生一项数据。
"""
# 1. 例子
# 读取一个多行文本,统计每一行的长度
it = (len(x) for x in open('/.')
print(it) # 结果 -> at 某个内存地址>
# 需要输出时就用next
print(next(it))
4. 使用enumerate代替range
# 原因很简单,封装的比range好
test = ['vannila', 'chocolate', 'pecan', 'strawberry']
# 第一种
for i , flavor in enumerate(test):
print('%d: %s' % (i + 1, flavor))
# 结果如下
>>>
1: vannila
2: chcolate
3: pecan
4: strawberry
# 解释一下: i + 1 实际上就是为了更好看,如果不i + 1,实际上就是索引的位置.
# 第二种
for i , flavor in enumerate(test, 1):
print('%d: %s' % (i, flavor))
# 结果一样, 实际上就是在enumerate的函数中已经封装了
# 显得更简便,而且同时能输出索引位置或输出实际中的计数位
5. 合理利用try/except/else/finally
# except的例子就不说了,用过都知道
# 直接上else的例子
# 函数的功能就是: 加载一个json,返回对应key的值
def load_json_key(data, key)
try:
result_dict = json.loads(data)
except ValueError as err:
raise KeyError from err
else:
return result_dict[key]
"""
解释:
实际上这个else可要可不要,因为写在try里面也是可以的
但是如果为了代码的可阅读性,else是一个很必要的东西
代码阅读上就知道try里面是代码中可能存在错误的的地方
如果写在一堆的话,还有错误,那你的except就要增加多几个了
而且写代码也并不建议嵌套try-except,毕竟那不服合代码的风格.
"""
# finally的话,实际上就一个代码清理的过程
# 一般用在IO或者数据库读写上,用来关闭流, 例子就不写了.
6. 线程方面的---使用concurrent.futures,实现并行计算
# coding: utf-8 from concurrent.futures import ThreadPoolExecutor as Pool
# from multiprocessing import Pool import requests
import time
urls = ["http://www.gzcc.cn", "http://jwxw.gzcc.cn",
"http://www.baidu.com", "http://www.qq.com",
"http://www.163.com", "http://www.sohu.com"]
def task(url, timeout=10): return requests.get(url=url, timeout=timeout)
if __name__ == '__main__':
start_1 = time.time()
for each_url in urls:
response = task(url=each_url)
print('%s, %s' % (response.url, response.status_code))
end_1 = time.time()
print("顺序执行的时长: %f" % (end_1 - start_1))
start_2 = time.time()
pool = Pool(max_workers=4)
# pool = Pool(processes=4)
processes = pool.map(task, urls)
for each_process in processes:
print('%s, %s' % (each_process.url, each_process.status_code))
end_2 = time.time()
print("并行执行的时长: %f" % (end_2 - start_2))
# 第一种的结果: 1.4s
# 第二种的结果: 0.4s
# 结果的提升是肯定有的,但是和网络情况有关系。
# 关于导入的包 concurrent.future
# 对于这个包里面的ThreadPoolExecutor和multiprocessing的Pool对比,作用实际上差不多,具体时间差异我还没怎么测试过.
# 但是如果你认真看源码的话会发现,实际上future的包在process的那一块也是调用multiprocessing的
# 按照源码的意思就是在子线程中运行多个python的解释器,从而实现并行.
# 但是一般的代码或者多线程爬虫上基本体会不出,因为爬虫的核心还是在网络速度上,而一般的代码也没必要
# 除非计算矩阵或者其他的需要巨大计算量的时候再考虑使用.
7. 与分析方面有关的---重视精度时使用decimal
# 例子
rate = 1.45
seconds = 3 * 60 + 42
cost = rate * seconds / 60
print(cost) # 结果很奇怪: 5.364999999999999
# 这时候可能会想到用round的函数
# 1、如果这时你的需求是不足一分也当一分的计算
# 类似于向上取整round的方法会把结果变成5.36而不是5.37
# 2、如果没有要求的时候使用round就可以了
#
# 针对第一种问题,就引出一个decimal的方法了,改写一下
from decimal import Decimal
rate = Decimal('1.45')
seconds = Decimal(3 * 60 + 42)
cost = rate * seconds / Decimal(60)
print(cost) # 结果 -> 5.365
# 重点说下这里。
# 有个很奇怪的地方,有兴趣的可以研究下为什么。
# 把rate的那个1.45去掉单引号包围,再运行就明白为什么奇怪了
# 反观结果, 5.365貌似也不是我们想要的,这里就引入一个quantize方法了
# 在代码顶部加上
from decimal import ROUND_UP
# cost还是刚刚的cost
rounded = cost.quantize(Decimal('0.01'), rounding=ROUND_UP)
print(rounded) # 结果 -> 5.37
# 兜兜转转就到结果这里了.一般这些情况都是对精度要求很高才需要,一般情况就当看不见好了.
8. 协作开发的时候尽量不要写import *
你的代码在导包的时候写了import *,你自己开发是很明白有什么方法的.
但是在协作开发或者开源项目的时候尽量避免.
因为其他开发者并不知道里面的方法是干啥的.
9. 配置文件独立化
# 例如一些数据库的配置,selenium的webdriver的配置,甚至开发的模式配置可以通过一些json格式的配置文件进行维护.
# 好处1: 在于这样管理项目不用"东奔西跑",为了一个全局变量找半天
# 好处2: 在协同开发的时候,可以不用变动的代码的情况下,根据自己的开发环境确定一些全局配置
# 缺点的话,实际上也算不上缺点.就是每次都要读取一次配置文件,代码的速度会减慢一点点,但是并不碍事.
你想更深入了解学习Python知识体系,你可以看一下我们花费了一个多月整理了上百小时的几百个知识点体系内容: