一日一技:用一個奇技淫巧把字串轉成特定型別

語言: CN / TW / HK

攝影:產品經理

油炸肥腸

我們有時候可能會需要把一個字串轉換成對應的型別。例如,把 '123' 轉換為 int 型別的 123 ;或者把 '3.14' 轉成浮點數 3.14

前提條件是不能使用 eval 或者 exec

這是一個非常簡單的功能,常規做法直接使用 if 判斷就可以了:

def convert(data, target_type):
    if target_type == 'int':
        return int(data)
    elif target_type == 'float':
        return float(data)
    ...

有些同學覺得寫if判斷麻煩,也可能會用字典來處理:

def convert(data, target_type):
    type_map = {
        'int': int,
        'float': float,
         ...
    }
    return type_map.get(target_type, str)(data)

但是這樣做有個弊端,就是你需要把能夠轉換的格式都列出來。如果新增了一個格式,你還需要改動程式碼增加一個 elif 分支或者在字典新增一個鍵值對。

那麼有沒有什麼辦法,能夠在不改動程式碼的情況下,完成轉換呢?

一開始我也想不到什麼好辦法。直到今天看 Scrapy原始碼 [1] 的時候,發現了一段程式碼:

這段程式碼中的 type(custom)(convert(c) for c in custom) 看起來很奇怪,但是隻要解構一下,就會變得很簡單。今天我們要解決的問題,就是這一行程式碼的一部分。

先來看前半截的寫法: type(custom)() 。怎麼 type 後面有兩個括號?我們知道 type(xxx) 是返回 xxx 這個資料的型別:

有些人以為, type(xxx) 返回的是一個字串。但實際上,它返回的就是型別本身:

既然我們可以使用 int('123') 把字串轉換為int,那麼我們也可以使用 type(1)('123') ,把字串 '123' 轉換為int。

所以,今天我們的這個問題,解法就很簡單了:

def convert(data, sample):
    return type(sample)(data)

呼叫函式的時候,傳入兩個引數,第一個是需要轉換的字串,第二個引數,是任意目標型別的資料。執行效果如下圖所示:

本來文章到這裡就結束了。但考慮到有同學可能不明白上面程式碼 type(custom)(convert(c) for c in custom) 中的 convert(c) for c in custom 看起來像是列表推導式,卻少了方括號,我再解釋一下。

例如當你一個只含有數字的列表,你要把每一個數字乘以2,然後再傳到函式裡面,你一般會這樣寫:

def get_one_ele(data_list: List):
    print('具體的執行程式碼')

a = [1, 2, 3]
get_one_ele([x * 2 for x in a])

但是如果函式只有這一個引數時,你可以省略外層的方括號,簡寫為: get_one_ele(x * 2 for x in a) 。所以上面的程式碼 type(custom)(convert(c) for c in custom) 等效為:

a = [convert(c) for c in custom]
type(custom)(a)

參考資料

[1]

Scrapy原始碼: https://github.com/scrapy/scrapy/blob/master/scrapy/utils/conf.py#L50

END

我的爬蟲架構課開課啦!

爬蟲架構進階就在這裡

送未聞Code知識星球一年訂閱!

未聞 Code·知識星球開放啦!

一對一答疑爬蟲相關問題

職業生涯諮詢

面試經驗分享

每週直播分享

......

未聞 Code·知識星球期待與你相見~

一二線大廠在職員工

十多年碼齡的程式設計老鳥

國內外高校在讀學生

中小學剛剛入門的新人

“未聞 Code技術交流群” 等你來!

入群方式:新增微信“mekingname”,備註“粉絲群”(謝絕廣告黨,非誠勿擾!)

好文和朋友一起看~