谢乾坤 | Kingname

给时光以生命。

我们知道,Python 里面的生成器只能被消费一次,例如如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def name_generator():
for name in ['产品经理', 'kingname']:
yield name

def say_hello(g):
print('hello 函数开始运行')
for name in g:
print('hello', name)
print('hello 函数运行完成')

def say_hi(g):
print('hi函数开始运行')
for name in g:
print('hi', name)
print('hi函数运行完成')

names = name_generator()
say_hello(names)
say_hi(names)

运行效果如下图所示:

say_hello函数里面,生成器已经被完整遍历了一次,那么在say_hi里面,就什么数据都拿不到了。

但如果我们用的是列表,就可以多次遍历,如下图所示:

大家注意观察区别。

那么有什么办法,能让生成器被多次完整迭代呢?这个时候就要使用itertools.tee这个函数了。它通过dequeue实现了让生成器多次消费的办法。

阅读全文 »

产品经理中午没有赶上食堂的午饭,于是纠集了一批人一起点外卖。然而正当她要下单时,老板找她有开会,于是她让开发小哥随便帮忙点一份。

产品经理开完会回来以后,发现还剩三份外卖没有人拿,分别是鲱鱼汤、螺蛳粉和大肠刺身。此时开发小哥碰巧不在,产品经理一时不知道哪一份才是自己的。

阅读全文 »

不是因为我高产似那啥。而是因为这些文章是我每天一篇发布在微信公众号上的,然后每隔一段时间整体搬运到博客上面来。

所以还没有关注我微信公众号的同学,请扫描下面的二维码,关注我的公众号,每天一篇原创文章,每天都有新技能 Get。

在上一篇文章里面,我们讲到了如何使用Python的yield关键字简化代码,压平多层嵌套字典的。

那么如果我们的数据不仅仅有字典,还有列表,是一个字典列表多层嵌套的数据怎么办呢?例如:

1
2
3
4
5
6
7
8
9
10
11
12
nest_dict = {
'a': 1,
'b': {
'c': 2,
'd': 3,
'e': {'f': 4}
},
'g': {'h': 5},
'i': 6,
'j': {'k': {'l': {'m': 8}}},
'n': [1, {'o': 1, 'p': [1, 2, 3], 'q': {'r': {'s': 100}}}, 3, [1, 2, 3], 5]
}

现在,请停下来,敲一敲代码,想想如何把处理列表的逻辑添加进去。

首先,我们来看一下最终被压平以后的数据长什么样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{'a': 1,
'b_c': 2,
'b_d': 3,
'b_e_f': 4,
'g_h': 5,
'i': 6,
'j_k_l_m': 8,
'n_0': 1,
'n_1_o': 1,
'n_1_p_0': 1,
'n_1_p_1': 2,
'n_1_p_2': 3,
'n_1_q_r_s': 100,
'n_2': 3,
'n_3_0': 1,
'n_3_1': 2,
'n_3_2': 3,
'n_4': 5}

对于'n': ['a', 'b', 'c']这种形式的数据,我们把它转换为: {'n_0': 'a', 'n_1': 'b', 'n_2': 'c'}

阅读全文 »

我们经常遇到各种字典套字典的数据,例如:

1
2
3
4
5
6
7
8
9
10
11
nest_dict = {
'a': 1,
'b': {
'c': 2,
'd': 3,
'e': {'f': 4}
},
'g': {'h': 5},
'i': 6,
'j': {'k': {'l': {'m': 8}}}
}

有没有什么简单的办法,把它压扁,变成:

1
2
3
4
5
6
7
8
9
{
'a': 1,
'b_c': 2,
'b_d': 3,
'b_e_f': 4,
'g_h': 5,
'i': 6,
'j_k_l_m': 8
}
阅读全文 »

写过一段时间代码的同学,应该对这一句话深有体会:程序的时间利用率和空间利用率往往是矛盾的,可以用时间换空间,可以用空间换时间,但很难同时提高一个程序的时间利用率和空间利用率。

但如果你尝试使用生成器来重构你的代码,也许你会发现,在一定程度上,你可以既提高时间利用率,又提高空间利用率。

阅读全文 »

说到安装 Python 的第三方库,会 Python 的同学都知道,在终端使用pip install xxx即可。

那么如果我想在代码里面安装第三方库怎么办呢?可能有人想到使用 os 模块:

1
2
3
import os
package_name = 'requests'
os.system(f'pip install {package_name}')

这种方法确实可行,并且即使你在虚拟环境中使用这种方式安装,也确实不会安装到系统的 Python 环境中。

阅读全文 »

我们在开发的过程中,会创建非常多的日志,对日志进行 rotate 是一个基本要求。

所谓的rotate,可以理解为对日志按照一定的规则进行切分。例如,每天晚上0点生成一个新的日志文件,并把老的文件归档。又或者每个日志文件超过多少 MB 以后就自动切分,并把老的内容单独存档或者压缩。存档以后的日志文件保存多少个。超过数量以后先删除老日志再删除新日志。

如果我们使用的是 Python,那么我们可以使用自带的logging模块或者第三方的logoru来写日志。但如果我们使用像是 MongoDB这种第三方的软件,那么要对日志进行 rotate 就非常麻烦了。如果不加以管理,MongoDB 的日志很容易就达到几十GB。

还有其他软件,他们的日志散落在系统的各个位置,我们应该如何替他们 rotate 呢?

阅读全文 »

假设有一个 Redis 集合,里面有 N 条数据,你不停从里面lpop数据,直到某一条数据的值为'Stop'字符串为止(已知里面必有一条数据为'Stop'字符串,但其位置不知道)。

阅读全文 »

我们平时导入第三方模块的时候,一般使用的是import关键字,例如:

1
2
import scrapy
from scrapy.spider import Spider

但是如果各位同学看过 Scrapy 的settings.py文件,就会发现里面会通过字符串的方式来指定pipeline 和 middleware,例如:

1
2
3
4
5
6
7
8
DOWNLOADER_MIDDLEWARES = {
'Test.middlewares.ExceptionRetryMiddleware': 545,
'Test.middlewares.BOProxyMiddlewareV2': 543,
}

SPIDER_MIDDLEWARES = {
'Test.middlewares.LoggingRequestMiddleware': 543,
}

我们知道,这里的Test.middlewares.ExceptionRetryMiddleware实际上对应了根目录下面的Test文件夹里面的middlewares.py文件中的ExceptionRetryMiddleware类。那么 Scrapy 是如何根据这个字符串,导入这个类的呢?

阅读全文 »
0%