如何避免对Python函数的类型检查参数

How to avoid type checking arguments to Python function

我正在创建一个类foo的实例,我希望能够以一种通用的方式从各种类型实例化这些实例。你不能通过口述或列表。请注意,foo来自第三方代码库-我无法更改foo的代码。

我知道python中的类型检查函数参数被认为是不好的形式。有没有比写下面的函数更简单的方法(例如,不进行类型检查)?

1
2
3
4
5
6
7
def to_foo(arg):
  if isinstance(arg, dict):
    return dict([(key,to_foo(val)) for key,val in arg.items()])
  elif isinstance(arg, list):
    return [to_foo(i) for i in arg]
  else:
    return Foo(arg)

编辑:可以使用Try/Except块。例如,您可以执行以下操作:

1
2
3
4
5
6
7
def to_foo(arg):
  try:
    return Foo(arg)
  except ItWasADictError:
    return dict([(key,to_foo(val)) for key,val in arg.items()])
  except ItWasAListError:
    return [to_foo(i) for i in arg]

我对此并不完全满意,原因有两个:第一,类型检查似乎更直接地解决了所需的功能,而这里的try/except块似乎是到达了相同的位置,但不太直接。第二,如果错误不能像这样清晰地映射呢?(例如,如果传递列表或dict,则会引发类型错误)

编辑:第三个我不太喜欢Try/Except方法的原因是我需要去找出foo在这些情况下会抛出什么异常,而不是预先编码它。


如果您使用的是python 3.4,那么您可以使用functools.singledispatch,或者为不同的python版本使用backport。

1
2
3
4
5
6
7
8
9
10
11
12
13
from functools import singledispatch

@singledispatch
def to_foo(arg):
    return Foo(arg)

@to_foo.register(list)
def to_foo_list(arg):
    return [Foo(i) for i in arg]

@to_foo.register(dict)
def to_foo_dict(arg):
    return {key: Foo(val) for key, val in arg.items()}

这是一个非常新的Python结构,但在其他语言中是一个常见的模式。我不确定你是否会称之为Python,但它确实比在任何地方写isinstances感觉更好。不过,在实践中,单调度可能只是在内部为您执行ISInstance检查。


处理你的问题的方法是假设(第一)argFoo,除了任何错误:

1
2
3
4
try:
    x = Foo(arg)
except NameError:
    #do other things

这个想法的短语是"duck-typing",这是Python中的一个流行模式。