用于验证函数参数的断言 [英] assertions to validate function parameters

查看:79
本文介绍了用于验证函数参数的断言的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近,我一直在编写这样的函数:


def f(a,b):


断言a in [1,2,3]

在[4,5,6]中断言b


重点是我正在检查类型和

参数的值。


我很好奇这是怎么做的或者不适合python'的鸭子打字

哲学。


我发现当我公开检测到无效参数时,我花费的时间更少

调试。

其他人这样做吗?任何相关的评论都是

欢迎。


马特


-

A运行一系列SAS程序的更好方法:
http://overlook.homelinux .net / wilson ... asAndMakefiles

解决方案

1月25日上午11:54,Matthew Wilson< m ... @tplus1.comwrote:


最近,我一直在编写这样的函数:


def f(a, b):


在[1,2,3]中断言a

在[4,5,6]中断言b

>
重点是我正在检查

参数的类型和值。


我很好奇这是怎么回事是不适合蟒蛇的鸭子打字

哲学。


我发现当我公开检测到无效参数时,我花的钱少了时间

调试。


Ar其他人做这样的事情?任何相关的评论都是

欢迎。


Matt



好​​吧,鸭子(甚至是静态的)对于那个问题)打字不能帮助你,如果你需要检查特定的*值*,而不是类型的
。真正的问题是

而不是f()意图用于外部世界。 (无论是

这可能是;另一个程序,图书馆,网络服务等)还是仅仅由你以非常可控的方式打电话给你?
? />

在第一种情况下,传递无效输入是*用户错误*,而不是

*编程错误*。断言应该用于编程错误

只能断言不变量,这些陈述应该是正确的,无论是什么,b $ b,什么;他们的违规行为意味着代码是错误的并且应该修复

尽快。


用户错误OTOH应该通过明确的检查和提升来处理

适当的例外,例如ValueError或它的子类。这有几个原因,但是一个非常实用的原因是用户可以通过运行带有''-O''或''的python来关闭断言 - OO''。

优化标志永远不应该改变程序的行为,所以

使用断言来表示正常程序行为的一部分

(验证用户提供的输入)是错误的。


George


1月25日星期四2007 16:54:05 +0000,Matthew Wilson写道:


最近,我一直在编写这样的函数:


def f(a,b):


在[1,2,3]中断言a

在[4,5,6]中断言b ]


重点是我正在检查

参数的类型和值。



如果有人传入了== MyNumericClass(2),除了断言之外,它可以完全正常工作
,你的代码是不必要的提出了一个

的例外情况。


其实这是一个不好的例子,因为肯定MyNumericClass(2)会将
测试等于int(2)为了有意义。因此,可以说,测试

值落在合适的范围内并不一定是个坏主意,但是

类型测试通常很糟糕。

另请注意,对于实际代码,像这样的裸断言是无用的

无信息:

< blockquote class =post_quotes>
>> x = 1
断言x == 3



回溯(最近一次调用最后一次):

文件"< stdin>",第1行,在?

AssertionError

这个更好:


>>断言x == 3,x必须是等于三,但是%s代替 %x



Traceback(最近一次调用最后一次):

文件"< stdin>" ;,第1行,在?

AssertionError:x必须等于3但是为1而不是

这甚至更好:


>> if x!= 3:



....提出ValueError(x必须等于3,但是%s代替%x)

....

回溯(最近一次调用最后一次):

文件"< stdin>",第1行,在?

ValueError:x必须等于3但是1代替

甚至更好的是将测试从代码中移出并将其放入单元测试中(如果可能的话)



我很好奇这是怎么做的,或者不适合python'的鸭子打字

哲学。



不适合,虽然范围测试可能还行。


I发现当我公开检测到无效参数时,我花费的时间更少

调试。



是的,可能。但是你得到的代码不那么有用:


def double(x):

""" return x doubled。""" ;

断言x == 2.0并输入(x)==浮点数

返回2 * x


现在我只需要测试一个案例,x == 2.0。看看我不需要做多少测试?
必须做什么? *眨眼*


这个笑话背后有一个严肃的点。你的功能越少,

就越受限制,你需要做的测试就越少 - 但是b / b
的用处越少,你投入的工作就越多对你的功能的用户。

而不是说像


a = MyNumericClass(1)

b = MyNumericClass(6)

#这里有更多代码......

#...

结果= f(a,b)

你迫使他们这样做:


a = MyNumericClass(1)

b = MyNumericClass(6)

#更多代码在这里...

#...

#type-cast a和b让你的功能保持愉快

result = f(int (a),int(b))

#并将结果输入到我想要的内容

result = MyNumericClass(result)


并且假设他们甚至可以在没有

丢失太多信息的情况下进行那种类型转换。


其他人这样做吗?任何相关的评论都是

欢迎。



一般来说,类型检查通常只是说我的

函数可以与任意数量的可能类型完美匹配 ,但是我

任意想让它只与这几个人合作,只是因为。


根据你想要做什么,那里有很多策略可以避免类型测试:例如最好使用isinstance()而不是类型,

,因为这将接受子类。但它不接受使用授权的课程。


有时候你可能会进行一系列的操作,而你想要的是

预先成功或失败,并且不会中途失败(比如说,你是修改一个列表并且不想做一半所需的更改)。

的解决方案是检查你的输入对象是否具有你需要的所有方法




def f(s ):

""用类似字符串的对象做某事。""

尝试:

upper = s.upper

split = s.split

除了AttributeError:

引发TypeError(''输入不够字符串''' )

返回上部()


好​​的单元测试将捕获任何类型和范围测试将捕获,加上

a全部其他错误,而类型测试和范围测试将只能捕获一小部分错误。因此,如果你依赖于类型和

范围测试,你可能没有做足够的测试。

-

史蒂文。


Steven D''Aprano< st *** @ REMOVE.THIS.cybersource.com.auwrote:


你的功能越少,它受到的限制就越多,你必须做的测试就越少 - 但它的用处越少,工作就越多

你给你的功能用户。而不是说某些东西



a = MyNumericClass(1)

b = MyNumericClass(6 )

#这里有更多代码...

#...

result = f(a,b)


你强迫他们这样做:


a = MyNumericClass(1)

b = MyNumericClass(6)

#这里有更多代码...

#...

#type-cast a和b保持你的功能快乐

result = f(int(a),int(b))

#并将结果输入到我想要的内容

result = MyNumericClass(result)



我有一个问题要问你。考虑这个函数:


def f(n):

"""返回2的最大自然权力,不超过n。 ;""

如果n< 1:

提高ValueError

i = 1

而i< = n:

j = i

i * = 2

返回j


如果我传递一个MyNumericClass实例,它将返回一个int或

长,不是MyNumericClass的实例。


在您看来,这是实施的弱点吗?该函数的

作者是否应该努力让它返回

相同类型的值?


-M-


Lately, I''ve been writing functions like this:

def f(a, b):

assert a in [1, 2, 3]
assert b in [4, 5, 6]

The point is that I''m checking the type and the values of the
parameters.

I''m curious how this does or doesn''t fit into python''s duck-typing
philosophy.

I find that when I detect invalid parameters overtly, I spend less time
debugging.

Are other people doing things like this? Any related commentary is
welcome.

Matt

--
A better way of running series of SAS programs:
http://overlook.homelinux.net/wilson...asAndMakefiles

解决方案

On Jan 25, 11:54 am, Matthew Wilson <m...@tplus1.comwrote:

Lately, I''ve been writing functions like this:

def f(a, b):

assert a in [1, 2, 3]
assert b in [4, 5, 6]

The point is that I''m checking the type and the values of the
parameters.

I''m curious how this does or doesn''t fit into python''s duck-typing
philosophy.

I find that when I detect invalid parameters overtly, I spend less time
debugging.

Are other people doing things like this? Any related commentary is
welcome.

Matt

Well, duck (or even static for that matter) typing can''t help you if
you''re checking for specific *values*, not types. The real question is
rather, is f() intended to be used in the "outside world" (whatever
this might be; another program, library, web service, etc.) or is it to
be called only by you in a very controlled fashion ?

In the first case, passing an invalid input is a *user error*, not a
*programming error*. Assertions should be used for programming errors
only to assert invariants, statements which should be correct no matter
what; their violations mean that the code is buggy and should be fixed
asap.

User errors OTOH should be handled by explicit checking and raising
appropriate exceptions, e.g. ValueError or a subclass of it. There are
several reasons for this but a very practical one is that a user can
turn off the assertions by running python with ''-O'' or ''-OO''.
Optimization flags should never change the behavior of a program, so
using assertions for what''s part of the normal program behavior
(validating user-provided input) is wrong.

George


On Thu, 25 Jan 2007 16:54:05 +0000, Matthew Wilson wrote:

Lately, I''ve been writing functions like this:

def f(a, b):

assert a in [1, 2, 3]
assert b in [4, 5, 6]

The point is that I''m checking the type and the values of the
parameters.

If somebody passes in a == MyNumericClass(2), which would have worked
perfectly fine except for the assert, your code needlessly raises an
exception.

Actually that''s a bad example, because surely MyNumericClass(2) would
test equal to int(2) in order to be meaningful. So, arguably, testing that
values fall within an appropriate range is not necessarily a bad idea, but
type-testing is generally bad.

Note also that for real code, a bare assert like that is uselessly
uninformative:

>>x = 1
assert x == 3

Traceback (most recent call last):
File "<stdin>", line 1, in ?
AssertionError
This is better:

>>assert x == 3, "x must be equal to three but is %s instead" % x

Traceback (most recent call last):
File "<stdin>", line 1, in ?
AssertionError: x must be equal to three but is 1 instead
This is even better still:

>>if x != 3:

.... raise ValueError("x must be equal to three but is %s instead" % x)
....
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ValueError: x must be equal to three but is 1 instead
And even better still is to move that test out of your code and put it
into unit tests (if possible).

I''m curious how this does or doesn''t fit into python''s duck-typing
philosophy.

Doesn''t fit, although range testing is probably okay.

I find that when I detect invalid parameters overtly, I spend less time
debugging.

Yes, probably. But you end up with less useful code:

def double(x):
"""Return x doubled."""
assert x == 2.0 and type(x) == float
return 2*x

Now I only need to test one case, x == 2.0. See how much testing I don''t
have to do? *wink*

There''s a serious point behind the joke. The less your function does, the
more constrained it is, the less testing you have to do -- but the less
useful it is, and the more work you put onto the users of your function.
Instead of saying something like

a = MyNumericClass(1)
b = MyNumericClass(6)
# more code in here...
# ...
result = f(a, b)
you force them to do this:

a = MyNumericClass(1)
b = MyNumericClass(6)
# more code in here...
# ...
# type-cast a and b to keep your function happy
result = f(int(a), int(b))
# and type-cast the result to what I want
result = MyNumericClass(result)

And that''s assuming that they can even do that sort of type-cast without
losing too much information.

Are other people doing things like this? Any related commentary is
welcome.

Generally speaking, type-checking is often just a way of saying "My
function could work perfectly with any number of possible types, but I
arbitrarily want it to only work with these few, just because."

Depending on what you''re trying to do, there are lots of strategies for
avoiding type-tests: e.g. better to use isinstance() rather than type,
because that will accept subclasses. But it doesn''t accept classes that
use delegation.

Sometimes you might have a series of operations, and you want the lot to
either succeed or fail up front, and not fail halfway through (say, you''re
modifying a list and don''t want to make half the changes needed). The
solution to that is to check that your input object has all the methods
you need:

def f(s):
"""Do something with a string-like object."""
try:
upper = s.upper
split = s.split
except AttributeError:
raise TypeError(''input is not sufficiently string-like'')
return upper()

Good unit tests will catch anything type and range tests will catch, plus
a whole lot of other errors, while type-testing and range-testing will
only catch a small percentage of bugs. So if you''re relying on type- and
range-testing, you''re probably not doing enough testing.
--
Steven.


Steven D''Aprano <st***@REMOVE.THIS.cybersource.com.auwrote:

The less your function does, the more constrained it is, the less
testing you have to do -- but the less useful it is, and the more work
you put onto the users of your function. Instead of saying something
like

a = MyNumericClass(1)
b = MyNumericClass(6)
# more code in here...
# ...
result = f(a, b)

you force them to do this:

a = MyNumericClass(1)
b = MyNumericClass(6)
# more code in here...
# ...
# type-cast a and b to keep your function happy
result = f(int(a), int(b))
# and type-cast the result to what I want
result = MyNumericClass(result)


I have a question for you. Consider this function:

def f(n):
"""Return the largest natural power of 2 which does not exceed n."""
if n < 1:
raise ValueError
i = 1
while i <= n:
j = i
i *= 2
return j

If I pass it an instance of MyNumericClass, it will return an int or a
long, not an instance of MyNumericClass.

In your view, is this a weakness of the implementation? Should the
author of the function make an effort to have it return a value of the
same type that it was passed?

-M-


这篇关于用于验证函数参数的断言的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆