ygo 1.0.11__tar.gz → 1.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ygo might be problematic. Click here for more details.

Files changed (38) hide show
  1. ygo-1.1.0/PKG-INFO +160 -0
  2. ygo-1.1.0/README.md +147 -0
  3. ygo-1.1.0/pyproject.toml +23 -0
  4. ygo-1.1.0/tests/test_ygo.py +171 -0
  5. {ygo-1.0.11 → ygo-1.1.0}/ygo/__init__.py +7 -4
  6. ygo-1.1.0/ygo/delay.py +89 -0
  7. ygo-1.0.11/ygo/ygo.py → ygo-1.1.0/ygo/pool.py +41 -215
  8. ygo-1.1.0/ygo/utils.py +137 -0
  9. ygo-1.1.0/ygo.egg-info/PKG-INFO +160 -0
  10. ygo-1.1.0/ygo.egg-info/SOURCES.txt +16 -0
  11. ygo-1.1.0/ygo.egg-info/requires.txt +3 -0
  12. {ygo-1.0.11 → ygo-1.1.0}/ygo.egg-info/top_level.txt +0 -1
  13. {ygo-1.0.11 → ygo-1.1.0}/ylog/__init__.py +2 -0
  14. ygo-1.0.11/PKG-INFO +0 -102
  15. ygo-1.0.11/README.md +0 -73
  16. ygo-1.0.11/pyproject.toml +0 -39
  17. ygo-1.0.11/ycat/__init__.py +0 -33
  18. ygo-1.0.11/ycat/client.py +0 -172
  19. ygo-1.0.11/ycat/parse.py +0 -64
  20. ygo-1.0.11/ycat/provider.py +0 -101
  21. ygo-1.0.11/ycat/qdf/__init__.py +0 -530
  22. ygo-1.0.11/ycat/qdf/errors.py +0 -65
  23. ygo-1.0.11/ycat/qdf/expr.py +0 -308
  24. ygo-1.0.11/ycat/qdf/qdf.py +0 -180
  25. ygo-1.0.11/ycat/qdf/udf/__init__.py +0 -14
  26. ygo-1.0.11/ycat/qdf/udf/base_udf.py +0 -145
  27. ygo-1.0.11/ycat/qdf/udf/cs_udf.py +0 -97
  28. ygo-1.0.11/ycat/qdf/udf/d_udf.py +0 -176
  29. ygo-1.0.11/ycat/qdf/udf/ind_udf.py +0 -202
  30. ygo-1.0.11/ycat/qdf/udf/ts_udf.py +0 -175
  31. ygo-1.0.11/ygo.egg-info/PKG-INFO +0 -102
  32. ygo-1.0.11/ygo.egg-info/SOURCES.txt +0 -27
  33. ygo-1.0.11/ygo.egg-info/requires.txt +0 -19
  34. {ygo-1.0.11 → ygo-1.1.0}/LICENSE +0 -0
  35. {ygo-1.0.11 → ygo-1.1.0}/setup.cfg +0 -0
  36. {ygo-1.0.11 → ygo-1.1.0}/ygo/exceptions.py +0 -0
  37. {ygo-1.0.11 → ygo-1.1.0}/ygo.egg-info/dependency_links.txt +0 -0
  38. {ygo-1.0.11 → ygo-1.1.0}/ylog/core.py +0 -0
ygo-1.1.0/PKG-INFO ADDED
@@ -0,0 +1,160 @@
1
+ Metadata-Version: 2.4
2
+ Name: ygo
3
+ Version: 1.1.0
4
+ Project-URL: homepage, https://github.com/link-yundi/ygo
5
+ Project-URL: repository, https://github.com/link-yundi/ygo
6
+ Requires-Python: >=3.12
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: joblib>=1.5.0
10
+ Requires-Dist: loguru>=0.7.3
11
+ Requires-Dist: tqdm>=4.67.1
12
+ Dynamic: license-file
13
+
14
+ # ygo
15
+ 一个轻量级 Python 工具包,底层基于 joblib 和 tqdm 、loguru 实现,支持
16
+ - 并发执行(带进度条)
17
+ - 延迟调用
18
+ - 链式绑定参数
19
+ - 函数信息获取
20
+ - 模块/函数动态加载...
21
+ - 并结合 ylog 提供日志记录能力
22
+
23
+ ### 安装
24
+ ```shell
25
+ pip install -U ygo
26
+ ```
27
+
28
+ ### 🧰 功能概览
29
+
30
+ | 模块 | 功能 |
31
+ | :----- | :----------------------------------------------------------- |
32
+ | `ygo` | 支持并发执行(带进度条)、延迟调用、函数信息获取以及模块/函数动态加载等功能 |
33
+ | `ylog` | 日志模块,提供统一的日志输出接口 |
34
+
35
+ ### 示例
36
+
37
+ ```
38
+ ├── a
39
+ │   ├── __init__.py
40
+ │   └── b
41
+ │   ├── __init__.py
42
+ │   └── c.py
43
+ └── test.py
44
+
45
+ c.py 中定义了目标函数
46
+ def test_fn(a, b=2):
47
+ return a+b
48
+ ```
49
+
50
+ #### 场景1: 并发执行
51
+
52
+ ```python
53
+ import ygo
54
+ import ylog
55
+ from a.b.c import test_fn
56
+
57
+ with ygo.pool(job_name="test parallel", show_progress=True) as go:
58
+ for i in range(10):
59
+ go.submit(test_fn)(a=i, b=2*i)
60
+ for res in go.do():
61
+ ylog.info(res)
62
+ ```
63
+
64
+ #### ✅ `ygo.pool` 支持的参数
65
+
66
+ | 参数名 | 类型 | 描述 |
67
+ | ------------- | ---- | ------------------------------------------------------------ |
68
+ | n_jobs | int | 并行任务数(<=1 表示串行) |
69
+ | show_progress | bool | 是否显示进度条 |
70
+ | backend | str | 执行后端(默认 'threading',可选 'multiprocessing' 或 'loky') |
71
+
72
+ #### 场景2: 延迟调用
73
+
74
+ ```
75
+ >>> fn = delay(test_fn)(a=1, b=2)
76
+ >>> fn()
77
+ 3
78
+ >>> # 逐步传递参数
79
+ >>> fn1 = delay(lambda a, b, c: a+b+c)(a=1)
80
+ >>> fn2 = delay(fn1)(b=2)
81
+ >>> fn2(c=3)
82
+ 6
83
+ >>> # 参数更改
84
+ >>> fn1 = delay(lambda a, b, c: a+b+c)(a=1, b=2)
85
+ >>> fn2 = delay(fn1)(c=3, b=5)
86
+ >>> fn2()
87
+ 9
88
+ ```
89
+
90
+ #### 场景3: 获取目标函数信息
91
+
92
+ ```
93
+ >>> ygo.fn_info(test_fn)
94
+ =============================================================
95
+ a.b.c.test_fn(a, b=2)
96
+ =============================================================
97
+ def test_fn(a, b=2):
98
+ return a+b
99
+ ```
100
+
101
+ #### 🔍 其他函数信息工具
102
+
103
+ | 方法名 | 描述 |
104
+ | ------------------------- | ---------------------------------------- |
105
+ | `fn_params(fn)` | 获取函数实参 |
106
+ | `fn_signature_params(fn)` | 获取函数定义的所有参数名 |
107
+ | `fn_code(fn)` | 获取函数源码字符串 |
108
+ | `fn_path(fn)` | 获取函数所属模块路径 |
109
+ | `fn_from_str(s)` | 根据字符串导入函数(如 "a.b.c.test_fn") |
110
+ | `module_from_str(s)` | 根据字符串导入模块 |
111
+
112
+ #### 场景4: 通过字符串解析函数并执行
113
+
114
+ ```
115
+ >>> ygo.fn_from_str("a.b.c.test_fn")(a=1, b=5)
116
+ 6
117
+ ```
118
+
119
+ ### 📝 日志记录(ylog)
120
+
121
+ ```python
122
+ import ylog
123
+
124
+ ylog.info("这是一个信息日志")
125
+ ylog.warning("这是一个警告日志")
126
+ ylog.error("这是一个错误日志", exc_info=True)
127
+
128
+
129
+
130
+ # 为不同的模块使用不同的logger
131
+ logger_app1 = ylog.get_logger("app1", )
132
+ logger_app2 = ylog.get_logger("app2", )
133
+ ```
134
+
135
+ #### 🔧 配置管理:`update_config`
136
+
137
+ 你可以通过 update_config 方法动态修改日志配置,例如设置日志级别、格式、是否启用颜色等。
138
+
139
+ ```python
140
+ # 开启调试模式
141
+ ylog.update_config(debug_mode=True)
142
+ ```
143
+
144
+ #### 🧩 获取独立的 Logger 实例:`get_logger`
145
+
146
+ 在大型项目中,你可能希望为不同模块或组件创建独立的 logger 实例以区分日志来源。
147
+
148
+ ```python
149
+ logger1 = ylog.get_logger("moduleA")
150
+ logger2 = ylog.get_logger("moduleB")
151
+
152
+ logger1.info("这是来自 moduleA 的日志")
153
+ logger2.warning("这是来自 moduleB 的警告")
154
+ ```
155
+
156
+ #### 📌 使用建议
157
+
158
+ - 生产环境建议关闭 `debug_mode`,避免产生过多调试日志。
159
+ - 对于复杂项目,推荐使用 `get_logger` 创建命名 logger,便于日志分类与分析。
160
+ - 使用 `exc_info=True` 参数时,可自动打印异常堆栈信息,适用于错误捕获场景。
ygo-1.1.0/README.md ADDED
@@ -0,0 +1,147 @@
1
+ # ygo
2
+ 一个轻量级 Python 工具包,底层基于 joblib 和 tqdm 、loguru 实现,支持
3
+ - 并发执行(带进度条)
4
+ - 延迟调用
5
+ - 链式绑定参数
6
+ - 函数信息获取
7
+ - 模块/函数动态加载...
8
+ - 并结合 ylog 提供日志记录能力
9
+
10
+ ### 安装
11
+ ```shell
12
+ pip install -U ygo
13
+ ```
14
+
15
+ ### 🧰 功能概览
16
+
17
+ | 模块 | 功能 |
18
+ | :----- | :----------------------------------------------------------- |
19
+ | `ygo` | 支持并发执行(带进度条)、延迟调用、函数信息获取以及模块/函数动态加载等功能 |
20
+ | `ylog` | 日志模块,提供统一的日志输出接口 |
21
+
22
+ ### 示例
23
+
24
+ ```
25
+ ├── a
26
+ │   ├── __init__.py
27
+ │   └── b
28
+ │   ├── __init__.py
29
+ │   └── c.py
30
+ └── test.py
31
+
32
+ c.py 中定义了目标函数
33
+ def test_fn(a, b=2):
34
+ return a+b
35
+ ```
36
+
37
+ #### 场景1: 并发执行
38
+
39
+ ```python
40
+ import ygo
41
+ import ylog
42
+ from a.b.c import test_fn
43
+
44
+ with ygo.pool(job_name="test parallel", show_progress=True) as go:
45
+ for i in range(10):
46
+ go.submit(test_fn)(a=i, b=2*i)
47
+ for res in go.do():
48
+ ylog.info(res)
49
+ ```
50
+
51
+ #### ✅ `ygo.pool` 支持的参数
52
+
53
+ | 参数名 | 类型 | 描述 |
54
+ | ------------- | ---- | ------------------------------------------------------------ |
55
+ | n_jobs | int | 并行任务数(<=1 表示串行) |
56
+ | show_progress | bool | 是否显示进度条 |
57
+ | backend | str | 执行后端(默认 'threading',可选 'multiprocessing' 或 'loky') |
58
+
59
+ #### 场景2: 延迟调用
60
+
61
+ ```
62
+ >>> fn = delay(test_fn)(a=1, b=2)
63
+ >>> fn()
64
+ 3
65
+ >>> # 逐步传递参数
66
+ >>> fn1 = delay(lambda a, b, c: a+b+c)(a=1)
67
+ >>> fn2 = delay(fn1)(b=2)
68
+ >>> fn2(c=3)
69
+ 6
70
+ >>> # 参数更改
71
+ >>> fn1 = delay(lambda a, b, c: a+b+c)(a=1, b=2)
72
+ >>> fn2 = delay(fn1)(c=3, b=5)
73
+ >>> fn2()
74
+ 9
75
+ ```
76
+
77
+ #### 场景3: 获取目标函数信息
78
+
79
+ ```
80
+ >>> ygo.fn_info(test_fn)
81
+ =============================================================
82
+ a.b.c.test_fn(a, b=2)
83
+ =============================================================
84
+ def test_fn(a, b=2):
85
+ return a+b
86
+ ```
87
+
88
+ #### 🔍 其他函数信息工具
89
+
90
+ | 方法名 | 描述 |
91
+ | ------------------------- | ---------------------------------------- |
92
+ | `fn_params(fn)` | 获取函数实参 |
93
+ | `fn_signature_params(fn)` | 获取函数定义的所有参数名 |
94
+ | `fn_code(fn)` | 获取函数源码字符串 |
95
+ | `fn_path(fn)` | 获取函数所属模块路径 |
96
+ | `fn_from_str(s)` | 根据字符串导入函数(如 "a.b.c.test_fn") |
97
+ | `module_from_str(s)` | 根据字符串导入模块 |
98
+
99
+ #### 场景4: 通过字符串解析函数并执行
100
+
101
+ ```
102
+ >>> ygo.fn_from_str("a.b.c.test_fn")(a=1, b=5)
103
+ 6
104
+ ```
105
+
106
+ ### 📝 日志记录(ylog)
107
+
108
+ ```python
109
+ import ylog
110
+
111
+ ylog.info("这是一个信息日志")
112
+ ylog.warning("这是一个警告日志")
113
+ ylog.error("这是一个错误日志", exc_info=True)
114
+
115
+
116
+
117
+ # 为不同的模块使用不同的logger
118
+ logger_app1 = ylog.get_logger("app1", )
119
+ logger_app2 = ylog.get_logger("app2", )
120
+ ```
121
+
122
+ #### 🔧 配置管理:`update_config`
123
+
124
+ 你可以通过 update_config 方法动态修改日志配置,例如设置日志级别、格式、是否启用颜色等。
125
+
126
+ ```python
127
+ # 开启调试模式
128
+ ylog.update_config(debug_mode=True)
129
+ ```
130
+
131
+ #### 🧩 获取独立的 Logger 实例:`get_logger`
132
+
133
+ 在大型项目中,你可能希望为不同模块或组件创建独立的 logger 实例以区分日志来源。
134
+
135
+ ```python
136
+ logger1 = ylog.get_logger("moduleA")
137
+ logger2 = ylog.get_logger("moduleB")
138
+
139
+ logger1.info("这是来自 moduleA 的日志")
140
+ logger2.warning("这是来自 moduleB 的警告")
141
+ ```
142
+
143
+ #### 📌 使用建议
144
+
145
+ - 生产环境建议关闭 `debug_mode`,避免产生过多调试日志。
146
+ - 对于复杂项目,推荐使用 `get_logger` 创建命名 logger,便于日志分类与分析。
147
+ - 使用 `exc_info=True` 参数时,可自动打印异常堆栈信息,适用于错误捕获场景。
@@ -0,0 +1,23 @@
1
+ [build-system]
2
+ requires = ["setuptools>=42", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "ygo"
7
+ version = "v1.1.0"
8
+ description = ""
9
+ readme = "README.md"
10
+ requires-python = ">=3.12"
11
+ dependencies = [
12
+ "joblib>=1.5.0",
13
+ "loguru>=0.7.3",
14
+ "tqdm>=4.67.1",
15
+ ]
16
+
17
+ [tool.setuptools.packages.find]
18
+ where = ["."]
19
+ include = ["ygo", "ygo.*", "ylog", "ylog.*", ]
20
+
21
+ [project.urls]
22
+ homepage = "https://github.com/link-yundi/ygo"
23
+ repository = "https://github.com/link-yundi/ygo"
@@ -0,0 +1,171 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ ---------------------------------------------
4
+ Created on 2025/5/27 09:14
5
+ @author: ZhangYundi
6
+ @email: yundi.xxii@outlook.com
7
+ ---------------------------------------------
8
+ """
9
+
10
+ import time
11
+
12
+ import ygo
13
+
14
+
15
+ def sample_task_add(a, b):
16
+ time.sleep(1)
17
+ return a + b
18
+
19
+
20
+ def sample_task_sub(a, b):
21
+ time.sleep(1)
22
+ return a - b
23
+
24
+
25
+ def warn_task():
26
+ raise ygo.WarnException("Test warning")
27
+
28
+
29
+ def error_task():
30
+ raise ValueError("Test error")
31
+
32
+
33
+ def test_pool_submit_and_do():
34
+ with ygo.pool() as go:
35
+ go.submit(sample_task_add, "task add")(a=1, b=2)
36
+ go.submit(sample_task_add, "task add")(a=2, b=3)
37
+ go.submit(sample_task_sub, "task sub")(a=5, b=1)
38
+
39
+ results = go.do()
40
+
41
+ assert len(results) == 3
42
+ assert results[0] == 3
43
+ assert results[1] == 5
44
+ assert results[2] == 4
45
+
46
+
47
+ def test_pool_error_handling():
48
+ with ygo.pool() as go:
49
+ go.submit(error_task, job_name="task_error")()
50
+
51
+ results = go.do()
52
+
53
+ assert len(results) == 1
54
+ assert results[0] is None
55
+
56
+
57
+ def test_pool_warn_exception_handled():
58
+ """测试 WarnException 是否被记录警告但继续执行"""
59
+ with ygo.pool(n_jobs=1) as go:
60
+ go.submit(warn_task, job_name="task_warn")()
61
+
62
+ results = go.do()
63
+
64
+ assert len(results) == 1
65
+ assert results[0] is None # WarnException 不中断流程
66
+
67
+
68
+ def test_pool_progress_bar_disabled():
69
+ """测试关闭进度条时的行为"""
70
+ with ygo.pool(n_jobs=2, show_progress=False) as go:
71
+ go.submit(sample_task_add, "test add")(a=1, b=2)
72
+ go.submit(sample_task_add, "test add")(a=3, b=4)
73
+
74
+ results = go.do()
75
+
76
+ assert len(results) == 2
77
+ assert 3 == results[0]
78
+ assert 7 == results[1]
79
+
80
+
81
+ def test_pool_with_one_jobs():
82
+ """测试 n_jobs=1 时是否退化为串行执行"""
83
+ with ygo.pool(n_jobs=1) as go:
84
+ go.submit(sample_task_add, "test add")(a=1, b=2)
85
+ go.submit(sample_task_add, "test add")(a=3, b=4)
86
+
87
+ results = go.do()
88
+
89
+ assert len(results) == 2
90
+ assert 3 == results[0]
91
+ assert 7 == results[1]
92
+
93
+
94
+ def test_delay_basic_usage():
95
+ """场景1:基本使用"""
96
+ fn = ygo.delay(lambda a, b: a + b)(a=1, b=2)
97
+ assert fn() == 3
98
+
99
+
100
+ def test_delay_partial_kwargs():
101
+ """场景2:逐步传递参数"""
102
+ fn1 = ygo.delay(lambda a, b, c: a + b + c)(a=1)
103
+ fn2 = ygo.delay(fn1)(b=2)
104
+ assert fn2(c=3) == 6
105
+
106
+
107
+ def test_delay_override_kwargs():
108
+ """场景3:参数更改"""
109
+ fn1 = ygo.delay(lambda a, b, c: a + b + c)(a=1, b=2)
110
+ fn2 = ygo.delay(fn1)(c=3, b=5) # 修改 b 的值
111
+ assert fn2() == 9
112
+
113
+
114
+ def test_delay_with_no_call():
115
+ """延迟函数在未调用时不会执行"""
116
+ called = False
117
+
118
+ def side_effect(*args, **kwargs):
119
+ nonlocal called
120
+ called = True
121
+ return None
122
+
123
+ delayed_fn = ygo.delay(side_effect)(x=1)
124
+ assert not called # 还未执行
125
+ delayed_fn()
126
+ assert called # 执行后标记为 True
127
+
128
+
129
+ def test_fn_signature_params():
130
+ assert ygo.fn_signature_params(sample_task_add) == ['a', 'b']
131
+
132
+
133
+ def test_fn_params_with_defaults():
134
+ delayed = ygo.delay(sample_task_add)(a=3)
135
+ print(ygo.fn_params(delayed))
136
+ assert dict(ygo.fn_params(delayed)) == {'a': 3, }
137
+
138
+
139
+ def test_fn_path_for_function():
140
+ fn_path = ygo.fn_path(sample_task_add)
141
+ assert 'tests.test_ygo' in fn_path or '__main__' in fn_path
142
+
143
+
144
+ def test_fn_code():
145
+ code = ygo.fn_code(sample_task_add)
146
+ assert "def sample_task_add(a, b):" in code
147
+ assert "return a+b" in code
148
+
149
+
150
+ def test_fn_info():
151
+ info = ygo.fn_info(sample_task_add)
152
+ assert "sample_task_add(a, b)" in info
153
+ assert "def sample_task_add(a, b):" in info
154
+
155
+
156
+ def test_fn_from_str():
157
+ func = ygo.fn_from_str("ygo.utils.fn_from_str")
158
+ assert func.__name__ == "fn_from_str"
159
+
160
+
161
+ def test_module_from_str():
162
+ mod = ygo.module_from_str("ygo.utils")
163
+ assert mod.__name__ == "ygo.utils"
164
+
165
+
166
+ def test_fn_params_with_no_defaults():
167
+ def no_defaults(x, y):
168
+ pass
169
+
170
+ delayed = ygo.delay(no_defaults)()
171
+ assert dict(ygo.fn_params(delayed)) == {}
@@ -7,9 +7,10 @@ Created on 2025/4/28 15:25
7
7
  ---------------------------------------------
8
8
  """
9
9
 
10
- from .exceptions import FailTaskError
11
- from .ygo import (
12
- delay,
10
+ from .exceptions import FailTaskError, WarnException
11
+ from .pool import pool
12
+ from .delay import delay
13
+ from .utils import (
13
14
  fn_params,
14
15
  fn_signature_params,
15
16
  fn_path,
@@ -17,12 +18,14 @@ from .ygo import (
17
18
  fn_info,
18
19
  module_from_str,
19
20
  fn_from_str,
20
- pool,
21
21
  )
22
22
 
23
+ __version__ = "v1.1.0"
24
+
23
25
  __all__ = [
24
26
  "FailTaskError",
25
27
  "delay",
28
+ "WarnException",
26
29
  "fn_params",
27
30
  "fn_signature_params",
28
31
  "fn_path",
ygo-1.1.0/ygo/delay.py ADDED
@@ -0,0 +1,89 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ ---------------------------------------------
4
+ Created on 2025/5/26 20:12
5
+ @author: ZhangYundi
6
+ @email: yundi.xxii@outlook.com
7
+ ---------------------------------------------
8
+ """
9
+
10
+ import functools
11
+ import inspect
12
+
13
+
14
+ class DelayedFunction:
15
+
16
+ def __init__(self, func):
17
+ self.func = func
18
+ self._fn_params_k = inspect.signature(self.func).parameters.keys()
19
+ self.stored_kwargs = self._get_default_args(func)
20
+ if hasattr(func, 'stored_kwargs'):
21
+ self.stored_kwargs.update(func.stored_kwargs)
22
+
23
+ def _get_default_args(self, func):
24
+ signature = inspect.signature(func)
25
+ return {
26
+ k: v.default
27
+ for k, v in signature.parameters.items()
28
+ if v.default is not inspect.Parameter.empty
29
+ }
30
+
31
+ def __call__(self, *args, **kwargs):
32
+ def delayed(*args, **_kwargs):
33
+ new_kwargs = {k: v for k, v in self.stored_kwargs.items()}
34
+ for k, v in _kwargs.items():
35
+ if k not in self._fn_params_k:
36
+ continue
37
+ new_kwargs[k] = v
38
+ return self.func(*args, **new_kwargs)
39
+
40
+ self._stored_kwargs(**kwargs)
41
+ new_fn = functools.wraps(self.func)(delayed)
42
+ new_fn.stored_kwargs = self.stored_kwargs
43
+ return new_fn
44
+
45
+ def _stored_kwargs(self, **kwargs):
46
+ for k, v in kwargs.items():
47
+ if k not in self._fn_params_k:
48
+ continue
49
+ self.stored_kwargs[k] = v
50
+
51
+
52
+ def delay(func):
53
+ """
54
+ 延迟执行
55
+ Parameters
56
+ ----------
57
+ func: Callable
58
+ 需要延迟执行的对象, 必须是一个Callable对象
59
+
60
+ Returns
61
+ -------
62
+ DelayedFunction
63
+ 将预先设置好的参数包装进原始的Callable对象中
64
+
65
+ Examples
66
+ --------
67
+
68
+ 场景1:基本使用
69
+
70
+ >>> fn = delay(lambda a, b: a+b)(a=1, b=2)
71
+ >>> fn()
72
+ 3
73
+
74
+ 场景2: 逐步传递参数
75
+
76
+ >>> fn1 = delay(lambda a, b, c: a+b+c)(a=1)
77
+ >>> fn2 = delay(fn1)(b=2)
78
+ >>> fn2(c=3)
79
+ 6
80
+
81
+ 场景3: 参数更改
82
+
83
+ >>> fn1 = delay(lambda a, b, c: a+b+c)(a=1, b=2)
84
+ >>> fn2 = delay(fn1)(c=3, b=5)
85
+ >>> fn2()
86
+ 9
87
+ """
88
+ return DelayedFunction(func)
89
+