确定在Python中以字符串表示的值的类型

8 投票
7 回答
7993 浏览
提问于 2025-04-15 18:15

当我用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 个回答

2

从我所了解的来看,这个问题没有一个“真正的”答案,因为这些只是字符串。它们不是整数、浮点数或者其他类型。这些都是你自己决定的角色。比如说,1是整数还是浮点数呢?

不过,有几个想法可以分享。一个是进行某种模式匹配(比如说,如果包含小数点,那就是浮点数等等)。如果你想解析或猜测日期,可以试试这个或者这个

你也可以尝试把这个元素“转换”成你想要的类型,然后捕捉异常来尝试其他类型。你可以先试试整数,如果失败了,就试浮点数,如果再失败,就试日期等等。

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'>

关键在于测试的顺序,比如说整数的测试应该放在浮点数测试之前。对于日期,你可以添加更多的测试来支持你想要的格式,但显然你不可能覆盖所有可能的情况。

撰写回答