确定在Python中以字符串表示的值的类型
当我用Python的csv解析器读取一个用逗号分隔的文件或字符串时,所有的项目都会被表示成字符串。下面是一个例子。
import csv
a = "1,2,3,4,5"
r = csv.reader([a])
for row in r:
d = row
d
['1', '2', '3', '4', '5']
type(d[0])
<type 'str'>
我想判断每个值是字符串、浮点数、整数还是日期。我该如何在Python中做到这一点呢?
7 个回答
7
这件事是无法可靠地完成的,这并不是因为Python或其他任何编程语言的限制。即使是人类,也无法在没有猜测和遵循一些规则的情况下,做到这一点(在这个上下文中,这些规则通常被称为启发式规则)。
所以我们先设计一些启发式规则,然后用Python来实现它们。需要考虑的事项有:
- 所有的值都是有效的字符串,我们知道这一点,因为这就是我们问题的基础,所以根本没有必要检查这一点。我们应该检查其他所有可能的内容,任何未能通过检查的内容就当作字符串处理。
- 日期是最明显的检查对象,如果它们的格式是可预测的,比如
[YYYY]-[MM]-[DD]
(ISO 8601日期格式),那么它们就很容易和其他包含数字的文本区分开来。如果日期的格式仅由数字组成,比如YYYYMMDD
,那么我们就会陷入困境,因为这些日期将无法与普通数字区分。 - 接下来我们检查整数,因为所有整数都是有效的浮点数,但并不是所有浮点数都是有效的整数。我们可以检查文本中是否包含数字(或者如果可能有十六进制数字,还可以包含字母A-F),如果是这种情况,就把这个值当作整数处理。
- 然后是浮点数,因为它们是带有某种格式(小数点)的数字。像
3.14159265
这样的数字很容易被识别为浮点数。然而,5.0
可以简单地写成5
,也是一个有效的浮点数,但在之前的步骤中可能会被当作整数处理,而无法被识别为浮点数,即使它本来是要这样处理的。 - 任何未被转换的值都可以当作字符串处理。
由于我上面提到的可能重叠的情况,这样的方案永远无法做到100%可靠。此外,任何你需要支持的新数据类型(比如复数)都需要自己的一套启发式规则,并且必须放在检查链中最合适的位置。检查越可能仅匹配所需的数据类型,它在检查链中的位置就应该越靠前。
现在让我们在Python中实现这个,以上提到的大部分启发式规则都已经由Python处理好了,我们只需要决定应用它们的顺序:
from datetime import datetime
heuristics = (lambda value: datetime.strptime(value, "%Y-%m-%d"),
int, float)
def convert(value):
for type in heuristics:
try:
return type(value)
except ValueError:
continue
# All other heuristics failed it is a string
return value
values = ['3.14159265', '2010-01-20', '16', 'some words']
for value in values:
converted_value = convert(value)
print converted_value, type(converted_value)
这将输出以下内容:
3.14159265 <type 'float'>
2010-01-20 00:00:00 <type 'datetime.datetime'>
16 <type 'int'>
some words <type 'str'>
15
你可以这样做:
from datetime import datetime
tests = [
# (Type, Test)
(int, int),
(float, float),
(datetime, lambda value: datetime.strptime(value, "%Y/%m/%d"))
]
def getType(value):
for typ, test in tests:
try:
test(value)
return typ
except ValueError:
continue
# No match
return str
>>> getType('2010/1/12')
<type 'datetime.datetime'>
>>> getType('2010.2')
<type 'float'>
>>> getType('2010')
<type 'int'>
>>> getType('2013test')
<type 'str'>
关键在于测试的顺序,比如说整数的测试应该放在浮点数测试之前。对于日期,你可以添加更多的测试来支持你想要的格式,但显然你不可能覆盖所有可能的情况。