Skip to content

Commit 84eae85

Browse files
committed
feat: add funcy and some update
Change-Id: I29e5e1b012a122e4244e90d2a4582430946edff8
1 parent c3e4787 commit 84eae85

15 files changed

+732
-19
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,12 @@ python的强大之处有很大的一方面在于它有各种各样非常强大
315315

316316
## [tqdm](content/tqdm.md)
317317

318+
## [schematics](content/schematics.md)
319+
320+
## [pyautogui](content/pyautogui.md)
321+
322+
## [funcy](content/funcy.md)
323+
318324
## [tools](content/tools.md)
319325

320326
## [Other_thing](content/other_thing.md)

code/funcy_cache_demo.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# -*- coding: utf-8 -*-
2+
import time
3+
import funcy as fc
4+
5+
from functools import wraps
6+
7+
8+
def cache(func):
9+
local_cache = {}
10+
11+
@wraps(func)
12+
def wrapper(*args, **kwargs):
13+
key = "{}:{}".format(";".join(map(str, args)),
14+
";".join(["{}:{}".format(*map(str, item)) for item in sorted(kwargs.items())]))
15+
if key in local_cache:
16+
return local_cache[key]
17+
else:
18+
value = func(*args, **kwargs)
19+
local_cache[key] = value
20+
return value
21+
22+
return wrapper
23+
24+
25+
# @cache
26+
@fc.memoize
27+
def get_timestamp(x):
28+
return int(time.time())
29+
30+
31+
if __name__ == '__main__':
32+
print(get_timestamp(1))
33+
time.sleep(1)
34+
print(get_timestamp(1))
35+
time.sleep(1)
36+
print(get_timestamp(1))
37+
time.sleep(2)
38+
print(get_timestamp(2))
39+
time.sleep(1)
40+
print(get_timestamp(2))
41+
print(get_timestamp.memory)

code/funcy_demo.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# -*- coding: utf-8 -*-
2+
import time
3+
import funcy as fc
4+
5+
from functools import wraps
6+
from compiler.ast import flatten as ast_flatten
7+
8+
9+
def flatten(elements):
10+
return [_ for item in elements for _ in flatten(item)] if isinstance(elements, list) else [elements]
11+
12+
13+
@fc.once
14+
def call_once():
15+
print("only once called")
16+
17+
18+
@fc.once
19+
def call_once_with_args(x):
20+
print("only once with args called")
21+
22+
23+
if __name__ == '__main__':
24+
a = [1, 2, [3, 4, [5, 6], [7, 8]], [9, 10]]
25+
print(fc.flatten(a))
26+
print(ast_flatten(a))
27+
print(flatten(a))
28+
29+
call_once()
30+
call_once()
31+
call_once_with_args(1)
32+
call_once_with_args(2)

code/funcy_flatten_demo.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import funcy as fc
4+
# only support in python2
5+
from compiler.ast import flatten as ast_flatten
6+
7+
8+
def flatten(elements):
9+
result = []
10+
for item in elements:
11+
if isinstance(item, list):
12+
result.extend(flatten(item))
13+
else:
14+
result.append(item)
15+
return result
16+
17+
18+
def old_flatten(elements):
19+
return [_ for item in elements for _ in old_flatten(item)] if isinstance(elements, list) else [elements]
20+
# result = []
21+
# for item in elements:
22+
# if isinstance(item, list):
23+
# item = old_flatten(item)
24+
# else:
25+
# item = [item]
26+
# result.extend(item)
27+
# return result
28+
29+
30+
if __name__ == '__main__':
31+
a = [1, 2, [3, 4, [5, 6], [7, 8]], [9, 10]]
32+
print(fc.flatten(a))
33+
print(ast_flatten(a))
34+
print(flatten(a))

code/funcy_list_demo.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# -*- coding: utf-8 -*-
2+
import funcy as fc
3+
4+
if __name__ == '__main__':
5+
a = [1,3,4,5,2,5,1,5,2,5,1]
6+
print(fc.distinct(a))
7+
print(set(a))
8+
9+
# 按个数分组,舍弃多余的元素
10+
print(fc.partition(2, range(10)))
11+
print(fc.partition(3, range(10)))
12+
# 按个数分组,多余的元素单列
13+
print(fc.chunks(2, range(10)))
14+
print(fc.chunks(3, range(10)))
15+
16+
# 此处不能用 lstrip 或者 rstrip, 因为会将输入字符串当成字符数组
17+
print("open_api_enforce_interface".lstrip("open_api"))
18+
print("open_api_enforce_interface".rstrip("_interface"))
19+
print(fc.cut_prefix("open_api_test_interface", "open_api"))
20+
print(fc.cut_suffix("open_api_test_interface", "interface"))

code/funcy_once_demo.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# -*- coding: utf-8 -*-
2+
import funcy as fc
3+
4+
5+
@fc.once
6+
def call_once():
7+
print("only once called")
8+
9+
10+
@fc.once
11+
def call_once_with_args(x):
12+
print("only once with args called")
13+
14+
15+
if __name__ == '__main__':
16+
call_once()
17+
call_once()
18+
call_once_with_args(1)
19+
call_once_with_args(2)

code/funcy_retry_demo.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# -*- coding: utf-8 -*-
2+
import time
3+
import funcy as fc
4+
5+
from functools import wraps
6+
7+
# def retry(times=3):
8+
# def inner(func):
9+
# @wraps(func)
10+
# def wrapper(*args, **kwargs):
11+
# for i in range(times):
12+
# try:
13+
# return func(*args, **kwargs)
14+
# except Exception as e:
15+
# if i == times-1:
16+
# raise e
17+
# print("occur error:%r" % e)
18+
#
19+
# return wrapper
20+
# return inner
21+
22+
# def retry(times=3):
23+
# def inner(func):
24+
# @wraps(func)
25+
# def wrapper(*args, **kwargs):
26+
# try:
27+
# return func(*args, **kwargs)
28+
# except Exception as e:
29+
# if times <= 1:
30+
# raise e
31+
# print("occur error:%r" % e)
32+
# return retry(times-1)(func)(*args, **kwargs)
33+
#
34+
# return wrapper
35+
#
36+
# return inner
37+
38+
39+
def retry(times=3):
40+
def inner(func):
41+
@wraps(func)
42+
def wrapper(*args, **kwargs):
43+
count = 0
44+
while count < times:
45+
try:
46+
return func(*args, **kwargs)
47+
except Exception as e:
48+
print("occur error:%r" % e)
49+
count += 1
50+
raise
51+
return wrapper
52+
53+
return inner
54+
55+
56+
@fc.retry(5)
57+
# @retry(3)
58+
def raise_exception():
59+
time.sleep(1)
60+
return 1 / 0
61+
62+
63+
if __name__ == '__main__':
64+
print(raise_exception())

content/concurrent.md

Lines changed: 92 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,27 @@ python 中的异步库,集成 threading 和 multiprocessing 两个库。
44

55
可以使用 `ThreadPoolExecutor``ProcessPoolExecutor` 来做线程和进程
66

7-
8-
```
7+
### 简单使用
8+
9+
这个库使用很简单,常见方法也即那么几种
10+
> [concurrent.futures --- 启动并行任务](https://docs.python.org/zh-cn/3/library/concurrent.futures.html)
11+
12+
- concurrent.futures.Executor|ThreadPoolExecutor|ProcessPoolExecutor
13+
- submit
14+
- map
15+
- shutdown
16+
- concurrent.futures.Future
17+
- cancel
18+
- cancel
19+
- cancel
20+
- done
21+
- cancel
22+
- exception
23+
- add_done_callback
24+
- concurrent.futures.wait
25+
- concurrent.futures.as_completed
26+
27+
```python
928
# -*- coding: utf-8 -*-
1029

1130
import time
@@ -76,12 +95,78 @@ if __name__ == '__main__':
7695

7796
```
7897

79-
参考链接
98+
### 动态添加任务
99+
100+
```python
101+
# -*- coding: utf-8 -*-
102+
import time
103+
import random
104+
import traceback
80105

81-
[使用Python进行并发编程-PoolExecutor篇](http://www.dongwm.com/archives/%E4%BD%BF%E7%94%A8Python%E8%BF%9B%E8%A1%8C%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B-PoolExecutor%E7%AF%87/)
106+
from concurrent import futures
107+
from concurrent.futures import ThreadPoolExecutor
108+
109+
result = []
110+
111+
112+
def handle(num, pool):
113+
try:
114+
print("thread for:%d" % num)
115+
sleep_time = random.random()
116+
time.sleep(sleep_time)
117+
if sleep_time < 0.95:
118+
print("thread pool add one")
119+
print("before pool size:%d" % pool._work_queue.qsize())
120+
pool.submit(handle, num*10, pool)
121+
# result.append(pool.submit(handle, 111, pool))
122+
print("after pool size:%d" % pool._work_queue.qsize())
123+
except Exception as e:
124+
# 问题在这里:
125+
# py2: cannot schedule new futures after shutdown
126+
# py3: cannot schedule new futures after interpreter shutdown
127+
print(repr(e))
128+
traceback.print_stack()
129+
130+
131+
if __name__ == '__main__':
132+
# 使用 map 的时候需要注意,其实 pool 会自动帮你把参数 zip 一下,先合并再分别映射
133+
# 其实最后不用调用 shutdown 也会自动等待所有任务结束,然后主进程结束
134+
thread_pool = ThreadPoolExecutor(30)
135+
# map_result = thread_pool.map(handle, range(2), [thread_pool] * 2)
136+
# result.extend(list(map_result))
137+
# 实际上,使用 submit 多个参数的时候也需要注意,参数直接摆开,和 threading 不一样
138+
for i in range(4):
139+
result.append(thread_pool.submit(handle, i, thread_pool))
140+
print("start threading")
141+
# 在没有 shutdown 之后为什么还会自动结束呢?谁在
142+
# thread_pool.shutdown()
143+
while result:
144+
print("before result length:%d" % len(result))
145+
for f in futures.as_completed(result):
146+
result.remove(f)
147+
# 此处还是有风险,如果这里结束了,全都结束了之后,还是会自动调用 shutdown
148+
# 其实还有待提交的请求,这样就尴尬了。
149+
# 但是加等待时间也不能够
150+
if len(result) == 0:
151+
time.sleep(2)
152+
print("after result length:%d" % len(result))
153+
# 还是用 lock 锁定一个计数器比较现实,计数器归零再结束。
154+
155+
# futures.wait(result)
156+
# thread_pool.shutdown()
157+
# 不需要 as_completed 也不需要手动 wait,实际上在 shutdown 的时候其实就是会等待结束的
158+
# 如果使用上下文管理器的话会自动 shutdown
159+
# 问题是在子线程中不能再往线程中加任务了,有点问题
160+
# with ThreadPoolExecutor(30) as thread_pool:
161+
# result = thread_pool.map(handle, range(2), [thread_pool] * 2)
162+
# print("start threading")
163+
# thread_pool.submit(handle, 111, thread_pool)
82164

83-
[使用Python的 concurrent.futures 模块](https://python-parallel-programmning-cookbook.readthedocs.io/zh_CN/latest/chapter4/02_Using_the_concurrent.futures_Python_modules.html)
165+
```
84166

85-
[python并发库:concurrent.futures的使用](https://blog.csdn.net/drdairen/article/details/69487643)
167+
参考链接
86168

87-
[python并发 1:使用 futures 处理并发](https://segmentfault.com/a/1190000009819359)
169+
[使用Python进行并发编程-PoolExecutor篇](http://www.dongwm.com/archives/%E4%BD%BF%E7%94%A8Python%E8%BF%9B%E8%A1%8C%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B-PoolExecutor%E7%AF%87/)
170+
[使用Python的 concurrent.futures 模块](https://python-parallel-programmning-cookbook.readthedocs.io/zh_CN/latest/chapter4/02_Using_the_concurrent.futures_Python_modules.html)
171+
[python并发库:concurrent.futures的使用](https://blog.csdn.net/drdairen/article/details/69487643)
172+
[python并发 1:使用 futures 处理并发](https://segmentfault.com/a/1190000009819359)

0 commit comments

Comments
 (0)