关于鸭子打字:
通过惯用性地不测试方法和函数体中的自变量类型,依靠文档,清晰的代码和测试来确保正确使用,可以帮助进行鸭子键入。
关于论证验证(EAFP:比宽恕更容易获得宽恕)。来自这里的改编示例:
...被认为是更pythonic的:
def my_method(self, key):
try:
value = self.a_dict[member]
except TypeError:
# do something else
这意味着使用您的代码的其他任何人都不必使用真正的字典或子类-他们可以使用实现映射接口的任何对象。
不幸的是,实际上并不是那么简单。如果上述示例中的member可能是整数怎么办?整数是不可变的-因此将它们用作字典键是完全合理的。但是,它们也用于索引序列类型对象。如果member恰好是整数,则示例二可以让列表,字符串以及字典通过。
关于断言编程:
断言是检查程序内部状态是否符合程序员期望的一种系统方法,目的是捕获错误。特别是,它们非常适合捕获编写代码时做出的错误假设,或捕获其他程序员滥用接口的情况。此外,通过使程序员的假设显而易见,它们可以在一定程度上充当内联文档。(“显式优于隐式。”)
提到的概念有时会发生冲突,因此在选择是否完全不进行任何数据验证,进行强力验证或使用断言时,我会依靠以下因素:
强力验证。通过强力验证,我的意思是引发自定义Exception(
ApiError
例如)。如果我的函数/方法是公共API的一部分,则最好验证参数以显示有关意外类型的良好错误消息。通过检查类型,我并不是指仅使用isinstance
,而是通过的对象是否支持所需的接口(鸭子输入)。当我记录API并指定期望的类型并且用户可能想以意外方式使用我的函数时,在检查这些假设时,我会感到更加安全。我通常使用isinstance
,如果以后要支持其他类型或鸭子,则可以更改验证逻辑。断言编程。如果我的代码是新的,我会使用很多断言。您对此有何建议?以后是否从代码中删除断言?
如果我的函数/方法不是API的一部分,而是将其某些参数传递给我未编写,研究或测试的其他代码,则我会根据被调用的接口执行很多断言。我的逻辑背后-最好在我的代码中失败,然后在堆栈跟踪中加深10个级别,出现难以理解的错误,这迫使进行大量调试,然后无论如何都将断言添加到我的代码中。
断言,关于何时使用或不使用类型/值验证的评论和建议?很抱歉,问题不是最好的表述。
例如,考虑以下函数,其中Customer
是SQLAlchemy声明性模型:
def add_customer(self, customer):
"""Save new customer into the database.
@param customer: Customer instance, whose id is None
@return: merged into global session customer
"""
# no validation here at all
# let's hope SQLAlchemy session will break if `customer` is not a model instance
customer = self.session.add(customer)
self.session.commit()
return customer
因此,有几种处理验证的方法:
def add_customer(self, customer):
# this is an API method, so let's validate the input
if not isinstance(customer, Customer):
raise ApiError('Invalid type')
if customer.id is not None:
raise ApiError('id should be None')
customer = self.session.add(customer)
self.session.commit()
return customer
要么
def add_customer(self, customer):
# this is an internal method, but i want to be sure
# that it's a customer model instance
assert isinstance(customer, Customer), 'Achtung!'
assert customer.id is None
customer = self.session.add(customer)
self.session.commit()
return customer
您何时以及为何在鸭子输入,类型检查和数据验证的上下文中使用它们?