类型检查参数Python [重复]

问题描述 投票:38回答:5

有时需要在Python中检查参数。例如我有一个函数,它接受网络中其他节点的地址作为原始字符串地址或类封装其他节点信息的类Node。

我使用type()函数,如:

    if type(n) == type(Node):
        do this
    elif type(n) == type(str)
        do this

这是一个很好的方法吗?

更新1:Python 3具有函数参数的注释。这些可用于使用工具进行类型检查:http://mypy-lang.org/

python typechecking
5个回答
109
投票

使用isinstance()。样品:

if isinstance(n, unicode):
    # do this
elif isinstance(n, Node):
    # do that
...

13
投票
>>> isinstance('a', str)
True
>>> isinstance(n, Node)
True

7
投票

不,Python中的类型检查参数不是必需的。这绝不是必要的。

如果您的代码接受地址为rawstring或Node对象,则您的设计会被破坏。

这是因为如果你不知道自己程序中对象的类型,那么你已经做错了。

Typechecking会损害代码重用并降低性能。具有根据传递的对象的类型执行不同事物的函数是容易出错的,并且具有难以理解和维护的行为。

您有以下更健全的选择:

  1. 创建一个接受rawstrings的Node对象构造函数,或者一个在Node对象中转换字符串的函数。让你的函数假设传递的参数是一个Node对象。这样,如果你需要将一个字符串传递给函数,你只需: myfunction(Node(some_string)) 这是您最好的选择,它干净,易于理解和维护。任何阅读代码的人都会立即理解正在发生的事情,而且您不必进行类型检查。
  2. 制作两个函数,一个接受Node对象,另一个接受rawstrings。你可以用最方便的方式在内部调用另一个(myfunction_str可以创建一个Node对象并调用myfunction_node,或者相反)。
  3. 使Node对象具有__str__方法,并在函数内部,在接收到的参数上调用str()。这样你总是通过强制获得一个字符串。

无论如何,请不要进行类型检查。这是完全没必要的,只有缺点。以您不需要进行类型检查的方式重构代码。无论是短期还是长期,您只能从中获益。


6
投票

如有必要,您还可以使用try catch键入检查:

def my_function(this_node):
    try:
        # call a method/attribute for the Node object
        if this_node.address:
             # more code here
             pass
    except AttributeError, e:
        # either this is not a Node or maybe it's a string, 
        # so behavior accordingly
        pass

您可以在Beginning Python中看到第二个关于生成器的示例(我的版本中的第197页),我相信Python Cookbook。很多时候捕捉AttributeErrorTypeError更简单,显然更快。此外,它可能以这种方式工作得最好,因为那时你不依赖于特定的继承树(例如,你的对象可能是一个Node,或者它可能是与Node具有相同行为的其他对象)。


6
投票

听起来像是在追随“泛型函数” - 一个根据给定的参数表现不同的函数。这有点像你在另一个对象上调用一个方法时会得到一个不同的函数,而不是仅使用第一个参数(对象/ self)来查找函数,而是使用所有参数。

Turbogears使用类似的东西来决定如何将对象转换为JSON - 如果我没记错的话。

an article from IBM使用调度程序包进行此类操作:

从那篇文章:

import dispatch
@dispatch.generic()
def doIt(foo, other):
    "Base generic function of 'doIt()'"
@doIt.when("isinstance(foo,int) and isinstance(other,str)")
def doIt(foo, other):
    print "foo is an unrestricted int |", foo, other
@doIt.when("isinstance(foo,str) and isinstance(other,int)")
def doIt(foo, other):
    print "foo is str, other an int |", foo, other
@doIt.when("isinstance(foo,int) and 3<=foo<=17 and isinstance(other,str)")
def doIt(foo, other):
    print "foo is between 3 and 17 |", foo, other
@doIt.when("isinstance(foo,int) and 0<=foo<=1000 and isinstance(other,str)")
def doIt(foo, other):
    print "foo is between 0 and 1000 |", foo, other
© www.soinside.com 2019 - 2024. All rights reserved.