What is the best (idiomatic) way to check the type of a Python variable?
我需要知道python中的变量是字符串还是dict。下面的代码有什么问题吗?
1 2 3 4 5 6 | 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 |
更新:我接受了阿维瑟的回答(不过如果有人解释为什么
但是感谢NakedFanatic提醒我,使用dict(作为案例陈述)比使用if/elif/else系列更干净。
让我详细介绍一下我的用例。如果一个变量是一个字符串,我需要把它放在一个列表中。如果是dict,我需要一个唯一值的列表。我想到的是:
1 2 3 4 5 6 7 | 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 |
如果首选
如果有人将Unicode字符串传递给您的函数,会发生什么?或者从dict派生的类?或者实现类似dict的接口的类?以下代码涵盖前两种情况。如果您使用的是python 2.6,那么根据abc pep,您可能希望使用
1 2 3 4 5 6 7 | def value_list(x): if isinstance(x, dict): return list(set(x.values())) elif isinstance(x, basestring): return [x] else: return None |
注意,
1 2 3 4 5 6 | class D(dict): pass d = D() print("type(d) is dict", type(d) is dict) # -> False print("isinstance (d, dict)", isinstance(d, dict)) # -> True |
python中的内置类型具有内置名称:
1 2 3 4 5 6 | >>> s ="hallo" >>> type(s) is str True >>> s = {} >>> type(s) is dict True |
顺便说一句,是操作员。但是,类型检查(如果您想调用它)通常是通过在try-except子句中包装一个特定于类型的测试来完成的,因为它不是非常重要的变量类型,而是您是否可以对它做某些事情。
IsInstance比Type更可取,因为当您将对象实例与它的超类进行比较时,它的计算结果也为true,这基本上意味着您将不必为将它与dict或str子类一起使用而对旧代码进行特殊区分。
例如:
1 2 3 4 5 6 7 8 | >>> class a_dict(dict): ... pass ... >>> type(a_dict()) == type(dict()) False >>> isinstance(a_dict(), dict) True >>> |
当然,有些情况下你可能不想这样做,但这些情况——希望——比你想这样做的情况要少得多。
我想我会采用鸭子打字的方法——"如果它像鸭子一样走路,它会像鸭子一样嘎嘎叫,它就是鸭子"。这样,您就不必担心字符串是Unicode还是ASCII。
我要做的是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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'] [] |
欢迎这里的专家对鸭嘴兽的这种用法发表评论,我一直在使用它,但最近被介绍到它背后的确切概念,我对此非常兴奋。所以我想知道这是否是一个过度杀戮。
我想这可能更适合实际操作
1 2 3 4 5 6 | if isinstance(x, str): do_something_with_a_string(x) elif isinstance(x, dict): do_somethting_with_a_dict(x) else: raise ValueError |
2个替代形式,取决于您的代码,一个或另一个可能被认为比这甚至更好。一是跳跃前不看
1 2 3 4 5 | try: one, two = tupleOrValue except TypeError: one = tupleOrValue two = None |
另一种方法来自guido,是函数重载的一种形式,它使代码更加开放。
http://www.artima.com/weblogs/viewpost.jsp?线程=155514
您可能需要签出typecheck。http://pypi.python.org/pypi/typecheck
python的类型检查模块
这个包为Python函数、方法和生成器提供了强大的运行时类型检查工具。在不需要自定义预处理器或对语言进行修改的情况下,类型检查包允许程序员和质量保证工程师对代码的输入和输出做出精确的断言。
这应该有效-所以不,你的代码没有任何问题。但是,也可以通过口述来完成:
1 2 | {type(str()): do_something_with_a_string, type(dict()): do_something_with_a_dict}.get(type(x), errorhandler)() |
再简洁一点,你不觉得是Python吗?
编辑…遵循Avisser的建议,代码也可以这样工作,并且看起来更好:
1 2 | {str: do_something_with_a_string, dict: do_something_with_a_dict}.get(type(x), errorhandler)() |
我一直在使用不同的方法:
1 2 3 4 5 | 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 ... |
我不记得为什么我用这个代替了IsInstance,尽管…
不,不需要python中的类型检查参数。它永远不会必要的。
如果您的代码接受字符串或dict对象,那么您的设计就会被破坏。
这是因为如果你还不知道对象的类型在你自己的程序中,那么你已经做错了什么。
类型检查会损害代码重用并降低性能。具有这样的功能根据传递的对象的类型执行不同的操作易出错,并且行为难以理解和维护。
您有以下更明智的选择:
1)生成一个函数
1 2 | def unique_values(some_dict): return list(set(some_dict.values())) |
使函数假定传递的参数始终是一个列表。这样,如果需要向函数传递字符串,只需执行以下操作:
1 | myfunction([some_string]) |
如果你需要通过口述,你需要:
1 | myfunction(unique_values(some_dict)) |
这是你最好的选择,它干净,易于理解和维护。任何人立即阅读代码就能理解发生了什么,而你没有打字检查。
2)生成两个函数,一个接受字符串列表,另一个接受字典。在最方便的情况下,您可以在内部打一个电话给另一个方法(
无论如何,不要打字检查。这是完全不必要的,只有缺点。以不需要类型检查的方式重构代码。从短期和长期来看,这样做只能带来好处。