跳轉至

腳本開發 / 代碼規劃編排

腳本集、腳本、函數應當按照一定邏輯編排組織,而不是將代碼隨意堆砌在一起。 合理編排腳本集和腳本有利於代碼的維護以及系統運行效率。

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(...) 來調用。

具體使用何種方式,請根據實際情況酌情選擇。