检查Python变量类型的最佳(惯用)方法是什么?

我需要知道Python中的变量是字符串还是字典。下面的代码有问题吗?

if type(x) == type(str()):
do_something_with_a_string(x)
elif type(x) == type(dict()):
do_somethting_with_a_dict(x)
else:
raise ValueError

更新:我接受了avisser的答案(尽管如果有人解释为什么isinstance优于type(x) is,我会改变主意)。

但是感谢nakedfanatic提醒我,使用dict(作为case语句)通常比使用if/elif/else系列更简洁。

让我详细说明我的用例。如果一个变量是一个字符串,我需要把它放在一个列表中。如果是字典,我需要一个唯一值的列表。这是我想到的:

def value_list(x):
cases = {str: lambda t: [t],
dict: lambda t: list(set(t.values()))}
try:
return cases[type(x)](x)
except KeyError:
return None

如果首选isinstance,你将如何编写这个value_list()函数?

378807 次浏览

这应该可以工作-所以,不,您的代码没有任何问题。然而,它也可以用dict来完成:

{type(str()): do_something_with_a_string,
type(dict()): do_something_with_a_dict}.get(type(x), errorhandler)()

更简洁,更精辟,你说呢?


编辑. .听从了Avisser的建议,代码也是这样工作的,而且看起来更好:

{str: do_something_with_a_string,
dict: do_something_with_a_dict}.get(type(x), errorhandler)()

Python中的内置类型有内置名称:

>>> s = "hallo"
>>> type(s) is str
True
>>> s = {}
>>> type(s) is dict
True

顺便说一句,注意操作符。然而,类型检查(如果你想这么称呼它)通常是通过在try-except子句中包装特定于类型的测试来完成的,因为重要的不是变量的类型,而是你是否可以用它做某些事情。

type(dict())表示“创建一个新字典,然后找出它的类型”。直接说dict会更快。 但如果你只是想检查类型,更习惯的方法是isinstance(x, dict).

注意,isinstance还包括子类(感谢达斯汀):

class D(dict):
pass


d = D()
print("type(d) is dict", type(d) is dict)  # -> False
print("isinstance (d, dict)", isinstance(d, dict))  # -> True

我觉得还是去做比较好

if isinstance(x, str):
do_something_with_a_string(x)
elif isinstance(x, dict):
do_somethting_with_a_dict(x)
else:
raise ValueError

另一种形式,取决于你的代码,一种或另一种甚至可能被认为是更好的。一是三思而后行

try:
one, two = tupleOrValue
except TypeError:
one = tupleOrValue
two = None

另一种方法来自Guido,它是函数重载的一种形式,使您的代码更加开放。

http://www.artima.com/weblogs/viewpost.jsp?thread=155514

如果有人将unicode字符串传递给你的函数会发生什么?还是从dict派生的类?还是一个实现字典式接口的类?下面的代码涵盖了前两种情况。如果你使用的是Python 2.6,你可能想要使用collections.Mapping而不是dict,就像ABC PEP

def value_list(x):
if isinstance(x, dict):
return list(set(x.values()))
elif isinstance(x, basestring):
return [x]
else:
return None

isinstance比type更可取,因为当你比较对象实例和它的超类时,它的值也为True,这基本上意味着你不必为dict或str子类使用它而对旧代码进行特殊处理。

例如:

 >>> class a_dict(dict):
...     pass
...
>>> type(a_dict()) == type(dict())
False
>>> isinstance(a_dict(), dict)
True
>>>

当然,在某些情况下,您可能不希望出现这种行为,但希望这些情况比您确实希望出现这种行为的情况要少得多。

我一直在用另一种方法:

from inspect import getmro
if (type([]) in getmro(obj.__class__)):
# This is a list, or a subclass of...
elif (type{}) in getmro(obj.__class__)):
# This one is a dict, or ...

我不记得我为什么用this而不是isinstance了。

我想我会采用鸭子打字的方法——“如果它走路像鸭子,它呱呱叫得像鸭子,它就是鸭子”。这样就不需要担心字符串是unicode还是ascii。

以下是我要做的:

In [53]: s='somestring'


In [54]: u=u'someunicodestring'


In [55]: d={}


In [56]: for each in s,u,d:
if hasattr(each, 'keys'):
print list(set(each.values()))
elif hasattr(each, 'lower'):
print [each]
else:
print "error"
....:
....:
['somestring']
[u'someunicodestring']
[]

欢迎这里的专家对这种类型的鸭子类型的用法发表评论,我一直在使用它,但最近才被介绍到它背后的确切概念,我对它非常兴奋。所以我想知道这样做是不是太过分了。

*sigh*

不,python中不需要类型检查参数。它是never 必要的。< / p >

如果您的代码接受字符串或dict对象,那么您的设计就坏了。

这是因为如果你不知道一个对象的类型 在你自己的程序中,你已经做了一些错误的事情 类型检查损害代码重用并降低性能。具有这样的功能 根据传递的对象类型执行不同的操作

.错误倾向,行为更难理解和维护

你有以下更理智的选择:

1)创建一个函数unique_values,将字典转换为唯一的值列表:

def unique_values(some_dict):
return list(set(some_dict.values()))

让你的函数假设传递的参数总是一个列表。这样,如果你需要传递一个字符串给函数,你只需要这样做:

myfunction([some_string])

如果你需要传递一个字典,你可以这样做:

myfunction(unique_values(some_dict))
这是你最好的选择,它很干净,容易理解和维护。任何人 阅读代码可以立即理解发生了什么,而您没有 typecheck。< / p > 创建两个函数,一个接受字符串列表,另一个接受字符串列表 字典。您可以在最方便的情况下,在内部打电话给另一个 myfunction_dict可以创建一个字符串列表并调用myfunction_list)

在任何情况下,不要typecheck。这是完全不必要的,只有 缺点。以一种不需要类型检查的方式重构代码。 从短期和长期来看,你这样做只会得到好处

你可能想检查typcheck。 http://pypi.python.org/pypi/typecheck < / p >

Python类型检查模块

这个包为Python函数、方法和生成器提供了强大的运行时类型检查工具。不需要自定义预处理器或改变语言,类型检查包允许程序员和质量保证工程师对他们的代码的输入和输出做出精确的断言。