有时需要在Python中检查参数.例如,我有一个函数接受网络中其他节点的地址作为原始字符串地址或接收封装其他节点信息的类Node.
我使用type(0函数,如:
if type(n) == type(Node): do this elif type(n) == type(str) do this
这是一个很好的方法吗?
更新1: Python 3具有函数参数的注释.这些可用于使用工具进行类型检查:http://mypy-lang.org/
使用isinstance()
.样品:
if isinstance(n, unicode): # do this elif isinstance(n, Node): # do that ...
>>> isinstance('a', str) True >>> isinstance(n, Node) True
不,Python中的类型检查参数不是必需的.这绝不是 必要的.
如果您的代码接受地址为rawstring或Node
对象,则您的设计会被破坏.
这是因为如果你不知道自己程序中对象的类型,那么你已经做错了.
Typechecking会损害代码重用并降低性能.具有根据传递的对象的类型执行不同事物的函数是容易出错的,并且具有难以理解和维护的行为.
您有以下更健全的选择:
创建一个Node
接受rawstrings 的对象构造函数,或一个转换Node
对象中的字符串的函数.使您的函数假设传递的参数是一个Node
对象.这样,如果你需要将一个字符串传递给函数,你只需:
myfunction(Node(some_string))
这是您最好的选择,它干净,易于理解和维护.任何阅读代码的人都会立即理解正在发生的事情,而且您不必进行类型检查.
创建两个函数,一个接受Node
对象,另一个接受rawstrings.您可以以最方便的方式在内部调用另一个(myfunction_str
可以创建Node
对象和调用
myfunction_node
,或者相反).
使Node
对象有一个__str__
方法并在函数内部调用str()
接收到的参数.这样你总是通过强制获得一个字符串.
无论如何,请不要进行类型检查.这是完全没必要的,只有缺点.以您不需要进行类型检查的方式重构代码.无论是短期还是长期,您只能从中获益.
听起来像是在追随"泛型函数" - 一个根据给定的参数表现不同的函数.这有点像你在另一个对象上调用方法时会得到不同的函数,而不是仅使用第一个参数(对象/ self)来查找函数,而是使用所有参数.
Turbogears使用类似的东西来决定如何将对象转换为JSON - 如果我没记错的话.
有来自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
如有必要,您还可以使用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.很多时候捕捉AttributeError
或TypeError
更简单,显然更快.此外,它可能以这种方式工作得最好,因为那时你不依赖于特定的继承树(例如,你的对象可能是一个Node
或者它可能是与a具有相同行为的其他对象Node
).