一日一技:用一个奇技淫巧把字符串转成特定类型

语言: 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源代码: http://github.com/scrapy/scrapy/blob/master/scrapy/utils/conf.py#L50

END

我的爬虫架构课开课啦!

爬虫架构进阶就在这里

送未闻Code知识星球一年订阅!

未闻 Code·知识星球开放啦!

一对一答疑爬虫相关问题

职业生涯咨询

面试经验分享

每周直播分享

......

未闻 Code·知识星球期待与你相见~

一二线大厂在职员工

十多年码龄的编程老鸟

国内外高校在读学生

中小学刚刚入门的新人

“未闻 Code技术交流群” 等你来!

入群方式:添加微信“mekingname”,备注“粉丝群”(谢绝广告党,非诚勿扰!)

好文和朋友一起看~