跳转至

脚本开发 / 代码规划编排

脚本集、脚本、函数应当按照一定逻辑编排组织,而不是将代码随意堆砌在一起。 合理编排脚本集和脚本有利于代码的维护以及系统运行效率。

1. 按照用途、类型合理划分脚本集和脚本

一般来说,推荐选用以下几种代码组织方式:

  • 为业务处理脚本按照行业、项目、组织等方式建立单独的脚本集,如:eShopIoTmonitorsalesmarketing
  • 代码量过多时,根据使用频率划分低频使用的脚本和高频使用的脚本,如predictionadvanced_prediction

2. 调用另一个脚本中的函数

脚本可以根据功能、用途等不同需求划分到不同的脚本或脚本集中,而位于不同脚本的代码可以相互调用。 需要调用另一个脚本中的函数时,只需要import对应脚本即可。

导入另一个脚本时,必须按照固定写法:

Python
1
2
3
4
5
6
# import <脚本集 ID>__<脚本 ID>
import demo__script

# 或使用别名缩短长度
# import <脚本集 ID>__<脚本 ID> as 别名
import demo__script as script

可以在脚本编辑器中,可以将鼠标指向左侧栏中的问号图表,直接复制相关语句

如果需要导出脚本集,那么,这个脚本集中依赖的其他脚本也需要一起导出。否则导出的脚本集会因为缺少函数而实际无法运行!

脚本或脚本集并不是 Python 模块,原本不能 import 导入

但 DataFlux Func 内部实现了动态加载机制,并允许使用 import 语句加载动态代码。因此,以下写法都是错误的。

Python
1
2
3
4
5
6
# 错误写法 1:将脚本集当作模块导入
import demo

# 错误写法 2:将脚本当作模块导入
import demo.script
from demo import script

此外,在导入脚本时,应当注意不要产生循环引用,如:

Python
1
2
3
4
5
6
7
8
# 脚本集 demo 下的脚本 script2
import demo__script2

# 脚本集 demo 下的脚本 script3
import demo__script3

# 脚本集 demo 下的脚本 script1
import demo__script1

注意,在同时编辑多个脚本时,如果当前导入了另一个脚本, 那么被引用的脚本实际会以已发布的版本执行, 系统在任何时候都不会导入草稿版本!

3. 单个脚本的代码量及依赖链

由于 DataFlux Func 运行脚本时,采用动态加载需要的脚本执行。 如果其中一个脚本导入了另一个脚本,被导入的脚本也会被动态加载。

因此,如果某个脚本中的某些函数会被特别频繁地调用,可以考虑将其单独提取为独立的脚本,减少加载消耗。 单个脚本大小建议控制在 1000 行以内。

此外,也要尽量避免过长的依赖链,导致无意义的性能损耗。如:

  • 脚本 1 依赖脚本 2
  • 脚本 2 依赖脚本 3
  • 脚本 3 依赖脚本 4
  • 脚本 4 依赖脚本 5
  • ...

Python 内置模块和第三方模块不受此限制影响

4. 不划分脚本的情况

上文虽然提到了脚本的合理规划以及脚本之间调用的方法, 但在某些特定情况下(如实际使用到的公共函数很少也很简单时), 可以考虑不划分脚本,将所有代码都放在同一个脚本中。

这种方式,虽然代码产生了一点冗余,但也额外带来了一些好处:

  • 单脚本即可运行,减少了加载消耗
  • 不会因为公共函数的改变而受到影响
  • 不用考虑脚本导出时的依赖关系

请根据实际情况选择最合理的方式规划脚本

5. 相同脚本集下脚本之间相互引用的简写

此功能于 1.1.0rc51`版本新增

在同一个脚本集下,脚本之间引用可以不写脚本集 ID 部分(即只写__开头部分)。

方便在脚本集克隆,改变了脚本集 ID 后,内部函数之间依然可以正确引用。

如:

Python
1
2
3
4
# 脚本:demo__utils

def echo(msg):
    return msg
Python
1
2
3
4
5
6
7
# 脚本:demo__test

# 等价于 import demo__utils as utils
import __utils as utils

def my_func(msg):
    return utils.echo(msg)

6. 避免过度封装

Python 是一门多范式的编程语言,可以使用简单的过程式编程,同样也能够使用面向对象的方式编程。

但在 DataFlux Func 中,为了方便调试,建议使用偏向过程式的编程方式编写代码,避免过度封装。

如,同样的功能,可以使用 2 中不同的方式实现:

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import requests

# 过程式
def query_some_api(url, params):
    r = requests.get(url, params)
    return r.json()

# 面向对象
class APIQuery(object):
    def __init__(self, url):
        self.url = url

    def do(self, params):
        r = requests.get(self.url, params)
        return r.json()

def test_api_query(url, params):
    api_query = APIQuery(url)
    api_query.do(params)

在上述例子中,虽然两者都能够实现同样的功能,但由于query_some_api(...)是一个可以直接调用的函数,因此在编辑器中,可以选择此函数后,直接填入参数运行。

而如果要调试运行APIQuery类的do(...)方法,必须先要实例化对象才能够调用,因此只能另外编写测试函数test_api_query(...)来调用。

具体使用何种方式,请根据实际情况酌情选择。