检查参数类型的 Pythonic 方法
Posted
技术标签:
【中文标题】检查参数类型的 Pythonic 方法【英文标题】:Pythonic Way To Check for A Parameter Type 【发布时间】:2014-01-07 12:19:12 【问题描述】:我正在为工作做一个小项目,并制作了一些类和方法。其中一个类别代表我们库存中的一个货架,另一个类别代表货架上的每个垃圾箱。我有一种方法可以将新箱添加到架子上,并且我添加了一些逻辑以确保在将其添加到架子之前将其传递给 Location 对象(现在我在将所有内容移动到数据库之前在开发时使用列表)。
但是,我刚刚在一本 Python 书籍中读到,通常最好在出现异常时处理它们,而不是添加额外的代码。我删除了逻辑以查看我会得到什么错误,但我没有得到任何允许使用字符串代替 Location 对象的内容。
有没有更 Pythonic 的方式来强制参数是什么类型?
我的书架上有什么:
class CrossDock:
locations = []
def add_location(self, location):
if isinstance(location, Location): #if this is commented out it will take what ever is passed to it
self.locations.append(location)
else:
print("location parameter must be of type: Location. Parameter is of type" + str(type(location)))
有没有办法使用 try/except 块来做到这一点?
【问题讨论】:
注意:您的locations
字段是类字段,而不是实例字段。所有CrossDock
实例将共享同一个副本。要解决此问题,请定义一个 __init__
方法并在其中设置 self.locations
。
只有一个 CrossDock 实例,我还应该将位置字段放在 init 方法中吗?
是的。它在概念上属于那个实例;如果您要制作更多 CrossDock
s,您会希望它们有单独的列表。
【参考方案1】:
向调用者传播异常。当他们滥用该类时,这会强制您的类的用户修复无效类型。打印没有用,因为它不强制执行接口契约。
class CrossDock(object):
def __init__(self):
self.locations = []
def add_location(self, location):
if isinstance(location, Location):
self.locations.append(location)
else:
raise TypeError("location must be Location, got: " +
repr(type(location)))
【讨论】:
我认为您有一些 Java 泄漏,并且您在__init__
上缺少括号。此外,这不是一个错误,但我建议让 CrossDock
继承自 object
,所以它是一个新型类。
我已根据@user2357112 的评论使其成为有效的 Python,并对其进行了更改以提出更惯用的TypeError
。随意回滚【参考方案2】:
最pythonic的方法是不检查类型...一切都是鸭子类型的。
What's the canonical way to check for type in python?
【讨论】:
【参考方案3】:当您尝试使用 Location 实例但在那里发现了其他东西时,您最终可能会在代码中的其他地方发生异常。当参数来自不可靠的来源时,检查参数并没有错。这会将异常置于问题的根源,而不是在代码中可能更难诊断的次要位置。
你可能会做你所拥有的,只是引发一个异常而不是打印错误。
def add_location(self, location):
if not isinstance(location, Location):
tmpl = "location parameter must be of type: Location, got %s"
raise TypeError(tmpl % str(type(location)))
... do other processing here after guarding check ...
如果您无法控制调用代码,这种类型的检查是最合适的。如果你只是想捕捉你自己犯的一个编程错误,你可以使用一个断言:
def add_location(self, location):
assert isinstance(location, Location), "location must be of type: Location"
... do other processing here
反对进行参数类型检查的建议是为了让您的代码具有最大的灵活性,例如如果有人想传入一个与 location 具有相同方法的对象。即使代码可以工作,检查硬编码类型也会引发异常。
【讨论】:
【参考方案4】:在 try/except 块中使用 assert
class Location():
pass
class CrossDock:
locations = []
def add_location(self, location):
try:
assert(isinstance(location, Location))
self.locations.append(location)
print("added")
except AssertionError:
print("error: Parameter is of type" + str(type(location)))
c = CrossDock()
loc = Location()
c.add_location("2")
c.add_location(loc)
第一次调用add_location
会失败
location parameter must be of type: Location. Parameter is of type<type 'str'>
added
【讨论】:
断言严格用于调试;它们不应该用于验证作为公共接口一部分的方法的先决条件,因为它们可以被禁用。此外,捕获异常并打印错误消息远不如让它传播有用。 OP 要求尝试/例外,这就是我发现异常的原因。打印是为了演示,符合 OP 问题中的操作。 我有什么作品,但我不确定这是否是阅读后的最佳方式。所以我有一些可行的方法,但我想知道它是否/什么是最好的前进方式。以上是关于检查参数类型的 Pythonic 方法的主要内容,如果未能解决你的问题,请参考以下文章
是否可以在 IntelliJ 中为私有方法禁用“可选用作字段或参数类型”检查?