iT邦幫忙

2024 iThome 鐵人賽

DAY 20
0

昨天上傳回 Github 後,如果接下來要繼續在本地端開發,會建議先 checkoutmain,然後再從 origin 把昨天更新的從 Github 拉回本地端,所以指令就會從 git pull 變成 git pull origin main,這樣就能把本地端的程式碼更新成最新版的 main

Utils

今天繼續更新我們的 functions,在 Day 18 - 用 requests 取得 Raw Data 後使用 pandas 轉成 DataFrame 的最後,我有提到在處理 params 的時候目前還太粗糙,要有更精確的值如果寫在同一個 function 又會讓該 function 太過龐大,所以這時候就會另外開 utils 資料夾存放這些處理 params 的 functions。這有另外一個好處就是在我們開發 Minor Statcast Search,也就是小聯盟的 statcast 數據搜尋的時候也可以使用到這些 utils。

season

首先處理得多選是 season,關於這些參數的敘述可以參考 Day 15 - Statcast Search Filters Part 1Day 16 - Statcast Search Filters Part 2
因為是多選的關係,所以會需要的型態是 strlist,我們可以先做型態的檢查,如果不是這兩個的話就可以用 raise 來回傳錯誤給使用者。寫法會像是:

def get_season_param_str(season: str | list[str]) -> str:
    if (type(season) != str and type(season) != list):
        raise ValueError(f"Invalid type for season: {season}")

接下來處理如果是傳入 list 的情況,因為可以使用的球季只有 2008 - 現在,我們可以寫個常數紀錄總共有哪些年份,再來會檢查我們傳入的 list 裡的輸入年份是否存在在規定的範圍內。會用 any 這個函數來判斷,any 的用法就是判斷一個 list 裡面,除非是全部 True,不然都會回傳 False。所以我們可以用 List Comprehensionsin 來判斷我們傳入的 list 裡的 element 是否在範圍內,得到各個 elementTrue/False 之後用 any 判斷這個 list 是否合法,如果是合法的就用 join 拼好 params,否的話就回傳錯誤

CURRENT_SEASON = 2024
START_SEASON = 2008
ALL_SEASONS = [str(year) for year in range(START_SEASON, CURRENT_SEASON)]

def get_season_param_str(season: str | list[str]) -> str:
    if (type(season) != str and type(season) != list):
        raise ValueError(f"Invalid type for season: {season}")

    if (type(season) == list):
        if any(season not in ALL_SEASONS for season in season):
            raise ValueError(f"Invalid seasons: {season}")
        return '|'.join(season)

list 處理完,再來處理 str 型態的值,在前面文章有提到,我們可以用 allstatcast 來一次多選,因此也許要用 if 來處理這兩個情況。statcast 是從 2015 年開始的,會另外處理,最後整個 util function 會寫成:

def get_season_param_str(season: str | list[str]) -> str:
    if (type(season) != str and type(season) != list):
        raise ValueError(f"Invalid type for season: {season}")

    if (type(season) == list):
        if any(season not in ALL_SEASONS for season in season):
            raise ValueError(f"Invalid seasons: {" | ".join(season)}")
        return '|'.join(season)

    if (season == "all"):
        return '|'.join(ALL_SEASONS)
    if (season == "statcast"):
        return '|'.join(STATCAST_SEASONS)

    if (season not in ALL_SEASONS):
        raise ValueError(f"Invalid season: {season}")

    return season

game_type

再來是 game_type 這個參數,這個在 list 處理前面都一樣,唯一要注意的是,他需要最後面再加一個 | 才會搜尋的到結果,所以就會用 f-string 在最後面接,會寫成 f"{'|'.join(game_type)}|",剩下就變得差不多,一樣用常數儲存所有的可能值:

GAME_TYPES = ["R", "PO", "F", "D", "L", "W", "S", "A"]


def get_game_type_param_str(game_type: str | list[str]) -> str:
    if (type(game_type) != str and type(game_type) != list):
        raise ValueError(f"Invalid type for game_type: {game_type}")

    if (type(game_type) == list):
        if any(game_type not in GAME_TYPES for game_type in game_type):
            raise ValueError(f"Invalid game types: {" | ".join(game_type)}")
        return f"{'|'.join(game_type)}|"

    if (game_type == "all"):
        return f"{'|'.join(GAME_TYPES)}|"

    if (game_type not in GAME_TYPES):
        raise ValueError(f"Invalid game type: {game_type}")

    return f"{game_type}|"

本日小結

剩下的參數的處理方式都差不多,不過可以發現,有些數值的代號可能會沒那麼清楚,可能之後會需要用到 Enum 的方式來呈現,使用者在使用的時候也可以用 Enum 來選擇自己要使用的選項。這個就留到後面的天數介紹了。
最後一樣感謝耐心地看完今天的文章,有任何問題或是有更好的寫法歡迎留言給我(我自己覺得可能用太多 if),明天見,掰掰。


上一篇
Day 19 - 創建 Github Pull Request
下一篇
Day 21 - 使用 Enum 來更完善 Utils
系列文
上次介紹的棒球套件很少更新了,那就只好自己寫一個!?31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言