我有一个函数,该函数需要根据所接受参数的类型而有所不同。我的第一个冲动是包含一些对 isinstance 的调用,但我一直在 stackoverflow 上看到答案,说这是错误的形式和非 Pythonic 但没有太多理由它的形式不好且不合时宜。对于后者,我想它与鸭式打字有关,但检查你的论点是否属于特定类型有什么大不了的?安全地玩不是更好吗?
4 回答
参考这个很棒的帖子
我对此事的看法是这样的:
- 如果您要限制代码,请不要这样做。
- 如果您使用它来指导您的代码,那么将其限制在非常具体的情况下。
好例子:(这没关系)
def write_to_file(var, content, close=True):
if isinstance(var, str):
var = open(var, 'w')
var.write(content)
if close:
var.close()
不好的例子:(这很糟糕)
def write_to_file(var, content, close=True):
if not isinstance(var, file):
raise Exception('expected a file')
var.write(content)
if close:
var.close()
使用isinstance
限制可以传递给函数的对象。例如:
def add(a,b):
if isinstance(a,int) and isinstance(b,int):
return a + b
else:
raise ValueError
现在你可以尝试调用它:
add(1.0,2)
期望得到3
但你得到一个错误,因为1.0
它不是整数。显然,isinstance
在这里使用会阻止我们的函数尽可能有用。归根结底,如果我们烤的东西尝起来像鸭子,只要它们能正常工作,我们就不管它们是从什么类型开始的。
但是,有些情况正好相反:
def read(f):
if isinstance(f,basestring):
with open(f) as fin
return fin.read()
else:
return f.read()
关键是,您需要确定您希望函数具有的 API。您的函数应该根据类型表现不同的情况存在,但很少见(检查字符串以打开文件是我所知道的更常见的用途之一)。
有时使用 isinstance 只是重新实现了多态调度。看str(...)
,它调用object.__str__(..)
了每个类型分别实现的。通过实现__str__
,您可以重用依赖于str
扩展该对象的代码,而不必操作内置方法str(...)
。
基本上这是 OOP 的高潮。你想要多态行为,你不想拼出类型。
不过,使用它是有正当理由的。
因为这样做明确地防止了鸭子打字。
这是一个例子。该csv
模块允许我将数据写入 CSV 格式的文件。因此,该函数接受一个文件作为参数。但是,如果我不想写入实际文件,而是写入StringIO
对象之类的东西怎么办?这是一个非常好的使用它,因为StringIO
实现了必要的读写方法。但是,如果csv
明确检查 type 的实际对象file
,那将被禁止。
一般来说,Python 认为我们应该尽可能多地允许事情发生——这与类中缺少真正的私有变量背后的原因相同。