In Python, you'll constantly see code like this:
```python if x != y: raise ValueError('x != y!!') ```
or:
```python if not isinstance(x,SomeType): raise TypeError('x is not SomeType!') ```
Assertion help a bit:
```python assert isinstance(x,SomeType), 'x is not SomeType!' ```
Notice I said "a bit". If optimizations are on, they're disabled. In addition, the only type of error thrown is an AssertionError.
I propose a `raise_if` function. If the given condition is True, an exception is raised. So, the above examples would be shortened to:
```python
raise_if(x!=y, ValueError, 'x != y!!') raise_if(not isinstance(x,SomeType),TypeError, 'x is not SomeType!')
```
There could also be a raise_if_not function that does the opposite:
```python raise_if_not(isinstance(x,SomeType), TypeError, 'x is not SomeType!') ```
Thoughts?
On 2014-02-20 17:10, Ryan Gonzalez wrote:
In Python, you'll constantly see code like this:
if x != y: raise ValueError('x != y!!')
or:
if not isinstance(x,SomeType): raise TypeError('x is not SomeType!')
Assertion help a bit:
assert isinstance(x,SomeType), 'x is not SomeType!'
Notice I said "a bit". If optimizations are on, they're disabled. In addition, the only type of error thrown is an AssertionError.
I propose a `raise_if` function. If the given condition is True, an exception is raised. So, the above examples would be shortened to:
raise_if(x!=y, ValueError, 'x != y!!') raise_if(not isinstance(x,SomeType),TypeError, 'x is not SomeType!')
There could also be a raise_if_not function that does the opposite:
raise_if_not(isinstance(x,SomeType), TypeError, 'x is not SomeType!')
Thoughts?
So:
raise_if_not(isinstance(x, SomeType), TypeError, 'x is not SomeType!')
is equivalent to:
if not isinstance(x, SomeType): raise TypeError('x is not SomeType!')
?
It doesn't improve the language much, IMHO! :-)
On Feb 20, 2014, at 9:29, MRAB python@mrabarnett.plus.com wrote:
On 2014-02-20 17:10, Ryan Gonzalez wrote:
In Python, you'll constantly see code like this:
if x != y: raise ValueError('x != y!!')
or:
if not isinstance(x,SomeType): raise TypeError('x is not SomeType!')
Assertion help a bit:
assert isinstance(x,SomeType), 'x is not SomeType!'
Notice I said "a bit". If optimizations are on, they're disabled. In addition, the only type of error thrown is an AssertionError.
I propose a `raise_if` function. If the given condition is True, an exception is raised. So, the above examples would be shortened to:
raise_if(x!=y, ValueError, 'x != y!!') raise_if(not isinstance(x,SomeType),TypeError, 'x is not SomeType!')
There could also be a raise_if_not function that does the opposite:
raise_if_not(isinstance(x,SomeType), TypeError, 'x is not SomeType!')
Thoughts?
So:
raise_if_not(isinstance(x, SomeType), TypeError, 'x is not SomeType!')
is equivalent to:
if not isinstance(x, SomeType): raise TypeError('x is not SomeType!')
?
It doesn't improve the language much, IMHO! :-)
And if you really want it in your project, it's a trivial one-liner, so just write it and use it.
On 02/20/2014 06:29 PM, MRAB wrote:
On 2014-02-20 17:10, Ryan Gonzalez wrote:
In Python, you'll constantly see code like this:
if x != y: raise ValueError('x != y!!')
or:
if not isinstance(x,SomeType): raise TypeError('x is not SomeType!')
Assertion help a bit:
assert isinstance(x,SomeType), 'x is not SomeType!'
Notice I said "a bit". If optimizations are on, they're disabled. In addition, the only type of error thrown is an AssertionError.
I propose a `raise_if` function. If the given condition is True, an exception is raised. So, the above examples would be shortened to:
raise_if(x!=y, ValueError, 'x != y!!') raise_if(not isinstance(x,SomeType),TypeError, 'x is not SomeType!')
There could also be a raise_if_not function that does the opposite:
raise_if_not(isinstance(x,SomeType), TypeError, 'x is not SomeType!')
Thoughts?
So:
raise_if_not(isinstance(x, SomeType), TypeError, 'x is not SomeType!')
is equivalent to:
if not isinstance(x, SomeType): raise TypeError('x is not SomeType!')
?
And: raise_if(x!=y, ValueError, 'x != y!!') is equivalent to: if x != y: raise ValueError('x != y!!')
It doesn't improve the language much, IMHO! :-)
Ditto.
But I would like to be able to add an error type to assertions (in addition to the optional message). This is particularly useful for people (like me) who systematically check func inputs (for client debugging comfort), using assert's. It would be mainly ValueError and TypeError.
Example: assert x > 0, "x should be positive", ValueError gives: ValueError: x should be positive instead of: AssertionError: x should be positive
This is very similar to the proposal above, semantically and practically, except we are here just reusing the builtin 'assert' instruction with an additional parameter. (Seems backward-compatible to me, at first sight, provided the new param comes last. Maybe an issue is the hypothetical mention of an error type, without message.)
d
Wouldn't that cause problems if the exception specified takes more than one parameter?
It's a nice idea, though. I can't believe I didn't think of that.
On Thu, Feb 20, 2014 at 2:44 PM, spir denis.spir@gmail.com wrote:
On 02/20/2014 06:29 PM, MRAB wrote:
On 2014-02-20 17:10, Ryan Gonzalez wrote:
In Python, you'll constantly see code like this:
if x != y: raise ValueError('x != y!!')
or:
if not isinstance(x,SomeType): raise TypeError('x is not SomeType!')
Assertion help a bit:
assert isinstance(x,SomeType), 'x is not SomeType!'
Notice I said "a bit". If optimizations are on, they're disabled. In addition, the only type of error thrown is an AssertionError.
I propose a `raise_if` function. If the given condition is True, an exception is raised. So, the above examples would be shortened to:
raise_if(x!=y, ValueError, 'x != y!!') raise_if(not isinstance(x,SomeType),TypeError, 'x is not SomeType!')
There could also be a raise_if_not function that does the opposite:
raise_if_not(isinstance(x,SomeType), TypeError, 'x is not SomeType!')
Thoughts?
So:
raise_if_not(isinstance(x, SomeType), TypeError, 'x is not SomeType!')
is equivalent to:
if not isinstance(x, SomeType): raise TypeError('x is not SomeType!')
?
And:
raise_if(x!=y, ValueError, 'x != y!!')
is equivalent to:
if x != y: raise ValueError('x != y!!')
It doesn't improve the language much, IMHO! :-)
Ditto.
But I would like to be able to add an error type to assertions (in addition to the optional message). This is particularly useful for people (like me) who systematically check func inputs (for client debugging comfort), using assert's. It would be mainly ValueError and TypeError.
Example: assert x > 0, "x should be positive", ValueError gives: ValueError: x should be positive instead of: AssertionError: x should be positive
This is very similar to the proposal above, semantically and practically, except we are here just reusing the builtin 'assert' instruction with an additional parameter. (Seems backward-compatible to me, at first sight, provided the new param comes last. Maybe an issue is the hypothetical mention of an error type, without message.)
d _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Painting the bikeshed, i'd rather have the syntax
assert x > 0, ValueError("x should be positive")
-- Markus
On 20 February 2014 21:44:57 CET, spir denis.spir@gmail.com wrote:
On 02/20/2014 06:29 PM, MRAB wrote:
On 2014-02-20 17:10, Ryan Gonzalez wrote:
In Python, you'll constantly see code like this:
if x != y: raise ValueError('x != y!!')
or:
if not isinstance(x,SomeType): raise TypeError('x is not SomeType!')
Assertion help a bit:
assert isinstance(x,SomeType), 'x is not SomeType!'
Notice I said "a bit". If optimizations are on, they're disabled. In addition, the only type of error thrown is an AssertionError.
I propose a `raise_if` function. If the given condition is True, an exception is raised. So, the above examples would be shortened to:
raise_if(x!=y, ValueError, 'x != y!!') raise_if(not isinstance(x,SomeType),TypeError, 'x is not SomeType!')
There could also be a raise_if_not function that does the opposite:
raise_if_not(isinstance(x,SomeType), TypeError, 'x is not
SomeType!')
Thoughts?
So:
raise_if_not(isinstance(x, SomeType), TypeError, 'x is not
SomeType!')
is equivalent to:
if not isinstance(x, SomeType): raise TypeError('x is not SomeType!')
?
And: raise_if(x!=y, ValueError, 'x != y!!') is equivalent to: if x != y: raise ValueError('x != y!!')
It doesn't improve the language much, IMHO! :-)
Ditto.
But I would like to be able to add an error type to assertions (in addition to the optional message). This is particularly useful for people (like me) who systematically check func inputs (for client debugging comfort), using assert's. It would be mainly ValueError and TypeError.
Example: assert x > 0, "x should be positive", ValueError gives: ValueError: x should be positive instead of: AssertionError: x should be positive
This is very similar to the proposal above, semantically and practically, except we are here just reusing the builtin 'assert' instruction with an additional parameter. (Seems backward-compatible to me, at first sight, provided the new param comes last. Maybe an issue is the hypothetical mention of an error type, without message.)
d _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
On Fri, Feb 21, 2014 at 02:47:17AM +0100, spir wrote:
On 02/20/2014 10:13 PM, Markus Unterwaditzer wrote:
Painting the bikeshed, i'd rather have the syntax
assert x > 0, ValueError("x should be positive")
Looks good as well; (but maybe slightly more job to implement, due to change of syntax?)
You might not be aware that this piece of code already works in Python and shouldn't be changed due to backwards compatibility.
py> assert False, ValueError("x should be positive") Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError: x should be positive
On 20/02/2014 20:44, spir wrote:
But I would like to be able to add an error type to assertions (in addition to the optional message). This is particularly useful for people (like me) who systematically check func inputs (for client debugging comfort), using assert's. It would be mainly ValueError and TypeError.
Example: assert x > 0, "x should be positive", ValueError gives: ValueError: x should be positive instead of: AssertionError: x should be positive
This is very similar to the proposal above, semantically and practically, except we are here just reusing the builtin 'assert' instruction with an additional parameter. (Seems backward-compatible to me, at first sight, provided the new param comes last. Maybe an issue is the hypothetical mention of an error type, without message.)
d
I think this is a dreadful idea. There's enough confusion for newbies now as to when to use assert and when to use raise. Having a half way house like this is to me the worst of both worlds, so let's settle for one or the other.
On Thu, Feb 20, 2014 at 09:44:57PM +0100, spir wrote:
But I would like to be able to add an error type to assertions (in addition to the optional message). This is particularly useful for people (like me) who systematically check func inputs (for client debugging comfort), using assert's.
Then your code is systematically broken, and badly so. All anyone needs to do to disable your checking is pass -O to the Python interpreter.
assert is not a short-cut for lazy programmers to avoid having to write an explicit "if cond: raise SomethingAppropriate(message)". Assertions have specific uses. You should read this post I made last November:
https://mail.python.org/pipermail/python-list/2013-November/660401.html
It would be mainly ValueError and TypeError.
Example: assert x > 0, "x should be positive", ValueError
-1
Apart from the optimization-disables-asserts issue, this breaks the readers expectation for what assertions are used for and what they will do. Here, you are actually using an assert for a critical piece of error checking, but you are disguising it as a checked comment or piece of less critical defensive programming.
On 02/20/2014 10:28 PM, Steven D'Aprano wrote:
On Thu, Feb 20, 2014 at 09:44:57PM +0100, spir wrote:
But I would like to be able to add an error type to assertions (in addition to the optional message). This is particularly useful for people (like me) who systematically check func inputs (for client debugging comfort), using assert's.
Then your code is systematically broken, and badly so.
Why do you speak _that_ negatively? (or should I say: _that_ violently?) And this, maybe not _that_ logically? Do you own the (copy)rights on proper usage of assert's?
All anyone needs to do to disable your checking is pass -O to the Python interpreter.
assert is not a short-cut for lazy programmers to avoid having to write an explicit "if cond: raise SomethingAppropriate(message)". Assertions have specific uses. You should read this post I made last November:
https://mail.python.org/pipermail/python-list/2013-November/660401.html
I think you are wrong, at least in this very case. Assert's for me are a debugging tool (or maybe more generally a tool for improving reliability). Such checks help finding errors and correcting them (thank to hopefully clear error messages), with a higher chance these corrections happen before "too late", meaning before users pay for our bugs. What else is the proper usage of assertions?
If not checked on function input, either with assert's or an if-raise combination, execution will break anyway, just later (later in time, and slightly further in code), because some input variable's value or type is wrong. Assert's placed that way are not strictly necessary (it's like duck typing: you don't need to check), instead they're a helpful tool for all users of your "service".
def average (numbers): n = len(numbers) assert n != 0, "Cannot compute average of 'zero number'.", ValueError return sum(numbers) / n
On the proposal: having a correct error type instead of "AssertionError" just helps a bit making the error report clearer for developpers.
I note in your post that, according to you, "assertions should be used for" (among other cases): "* checking contracts (e.g. pre-conditions and post-conditions);" This is precisely what I do (pre-conditions).
If you don't use assert's for checking assertions which are logical truths if the code is correct, then what for?
[Side-note: I do not use here assertions for exception handling (properly speaking) at all; instead for catching errors (properly speaking). It's just that, in python and a long list of other languages, there is a complete confusion between exceptions (which belong to the app's logic, but need to be processed specially) and errors (which don't, and are our fault and our problem). Is this topic clear?]
d
On Feb 20, 2014, at 18:23, spir denis.spir@gmail.com wrote:
On 02/20/2014 10:28 PM, Steven D'Aprano wrote:
On Thu, Feb 20, 2014 at 09:44:57PM +0100, spir wrote:
But I would like to be able to add an error type to assertions (in addition to the optional message). This is particularly useful for people (like me) who systematically check func inputs (for client debugging comfort), using assert's.
Then your code is systematically broken, and badly so.
Why do you speak _that_ negatively? (or should I say: _that_ violently?) And this, maybe not _that_ logically? Do you own the (copy)rights on proper usage of assert's?
All anyone needs to do to disable your checking is pass -O to the Python interpreter.
assert is not a short-cut for lazy programmers to avoid having to write an explicit "if cond: raise SomethingAppropriate(message)". Assertions have specific uses. You should read this post I made last November:
https://mail.python.org/pipermail/python-list/2013-November/660401.html
I think you are wrong, at least in this very case. Assert's for me are a debugging tool (or maybe more generally a tool for improving reliability). Such checks help finding errors and correcting them (thank to hopefully clear error messages), with a higher chance these corrections happen before "too late", meaning before users pay for our bugs. What else is the proper usage of assertions?
If not checked on function input, either with assert's or an if-raise combination, execution will break anyway, just later (later in time, and slightly further in code), because some input variable's value or type is wrong. Assert's placed that way are not strictly necessary (it's like duck typing: you don't need to check), instead they're a helpful tool for all users of your "service".
def average (numbers): n = len(numbers) assert n != 0, "Cannot compute average of 'zero number'.", ValueError return sum(numbers) / n
I think you're actually suffering from the confusion you accused Steven of. His post explains the difference between internal preconditions and external value checks. Then difference has nothing to do with the form of the function, but with how it's used.
If average is only called by your own code with your own values, so you know it can never be called with an empty list unless there's a bug somewhere, then you're asserting a precondition, which is exactly what asserts are for--but in that case this should be an AssertionError, not a ValueError.
If average is part of an external API, or is called with user data, so you're testing for something that could fail because of user error rather than a bug in your code, then this is a perfect case for a ValueError--but it's not an assertion, it's an error check.
The fact that assertions happen to work by exception handling doesn't mean you should ignore the difference between them.
On the proposal: having a correct error type instead of "AssertionError" just helps a bit making the error report clearer for developpers.
I note in your post that, according to you, "assertions should be used for" (among other cases): "* checking contracts (e.g. pre-conditions and post-conditions);" This is precisely what I do (pre-conditions).
Checking contracts _between parts of your code_ is the paradigm case for assert. Checking contracts _between your code and your user_ is not the same thing, and you shouldn't be conflating the two.
If you don't use assert's for checking assertions which are logical truths if the code is correct, then what for?
[Side-note: I do not use here assertions for exception handling (properly speaking) at all; instead for catching errors (properly speaking). It's just that, in python and a long list of other languages, there is a complete confusion between exceptions (which belong to the app's logic, but need to be processed specially) and errors (which don't, and are our fault and our problem). Is this topic clear?]
d _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
On 02/21/2014 07:11 AM, Andrew Barnert wrote:
On Feb 20, 2014, at 18:23, spir denis.spir@gmail.com wrote:
On 02/20/2014 10:28 PM, Steven D'Aprano wrote:
On Thu, Feb 20, 2014 at 09:44:57PM +0100, spir wrote:
But I would like to be able to add an error type to assertions (in addition to the optional message). This is particularly useful for people (like me) who systematically check func inputs (for client debugging comfort), using assert's.
Then your code is systematically broken, and badly so.
Why do you speak _that_ negatively? (or should I say: _that_ violently?) And this, maybe not _that_ logically? Do you own the (copy)rights on proper usage of assert's?
All anyone needs to do to disable your checking is pass -O to the Python interpreter.
assert is not a short-cut for lazy programmers to avoid having to write an explicit "if cond: raise SomethingAppropriate(message)". Assertions have specific uses. You should read this post I made last November:
https://mail.python.org/pipermail/python-list/2013-November/660401.html
I think you are wrong, at least in this very case. Assert's for me are a debugging tool (or maybe more generally a tool for improving reliability). Such checks help finding errors and correcting them (thank to hopefully clear error messages), with a higher chance these corrections happen before "too late", meaning before users pay for our bugs. What else is the proper usage of assertions?
If not checked on function input, either with assert's or an if-raise combination, execution will break anyway, just later (later in time, and slightly further in code), because some input variable's value or type is wrong. Assert's placed that way are not strictly necessary (it's like duck typing: you don't need to check), instead they're a helpful tool for all users of your "service".
def average (numbers): n = len(numbers) assert n != 0, "Cannot compute average of 'zero number'.", ValueError return sum(numbers) / n
I think you're actually suffering from the confusion you accused Steven of. His post explains the difference between internal preconditions and external value checks. Then difference has nothing to do with the form of the function, but with how it's used.
If average is only called by your own code with your own values, so you know it can never be called with an empty list unless there's a bug somewhere, then you're asserting a precondition, which is exactly what asserts are for--but in that case this should be an AssertionError, not a ValueError.
If average is part of an external API, or is called with user data, so you're testing for something that could fail because of user error rather than a bug in your code, then this is a perfect case for a ValueError--but it's not an assertion, it's an error check.
The fact that assertions happen to work by exception handling doesn't mean you should ignore the difference between them.
See below.
[Side-note: I do not use here assertions for exception handling (properly speaking) at all; instead for catching errors (properly speaking). It's just that, in python and a long list of other languages, there is a complete confusion between exceptions (which belong to the app's logic, but need to be processed specially) and errors (which don't, and are our fault and our problem). Is this topic clear?]
I think this is the _relevant_ difference.
You and Steven point at the difference between illogical facts proper to my code, say internal, and ones due to client (user) code, say external. This is a true difference, indeed, but maybe not that relevant here. If this is an external interface, meaning in my example the function 'average' is to be used by clients, then calling it with an empty array of numbers is an error in any case. Or rather, it is an obvious _anomaly_ on the side of the procedure, which i can detect, and it is certainly a *symptom* of a true error on their side. (The detected anomaly is but an effect of an error, which is the cause, _somewhere else_ in their code.) The reason is obvious: average of no-number-at-all makes no sense. [And this precisely is what the error message should say, and the improvement I wish to make, instead of a potential division-by-zero error which is just a consequence.]
Whether this error is in their code or mine does not change it signicantly, I guess. It is an error. [And is is a value error in fact, reason why I wish to change the feature to have a better message.] Note that an error is a _break_ of the the application logic; it is actual semantics of the program that does not belong to the app's logic.
In any case, it is certainly _not_ an exception. That it were an exception would mean that this case (the array of numbers is empty) _belongs to_ the application logic. If so, the client code should just deal with this special case specially. Right? And certainly not call average (blindly). In fact, there are good chances that this exceptional case is not only not properly dealt with _here_, where we are about to call 'average', but also elsewhere in code; and probably we should not reach this very point in code at all, but instead have branched on another code path earlier.
Exception handling, exception catching precisely, should (in my view) only be used for such exceptional situations that (1) nevertheless belong to the application logic, so should be dealt with properly (2) are impredictable on the client side, unlike the example case.
Such cases happen for instance with search/find procedures (we don't know whether the searched item is there before trying to find it) or in relation with elements external to the app's "world", such as the file system or the user. This is the proper usage of exception machinaries in my view (and I only use them for that). [1]
d
[1] Side-note: I have come to think that the common exception handling mechanisms (again, to be used only in impredictable exception cases) are wrong. The reason is that only clients know whether a case of anomaly (which would cause the procedure to "throw", to "raise") is actually an unknown error (the collection should hold this item) or instead an exception (the item may not be there). Thus, clients should be in control of exception handling, not service procedures. Presently, the latter just lauch the exception machinary (big, complicated, with longjumps and stack unwinding mechanisms). Instead, what we need is allow clients to tell that this is an exceptional, but impredictable, case, and no throwing and catching should happen at all. Some coding practices end up with a similar result by adding an "optional" param to such procedures; in which case if an anomaly happens they just say it, somehow, instead of failing.
def item_index (col, item, opt=false): ... search item ... if index: return index
if opt: return None # or -1 raise ...
This means, for me, that in a sufficiently flexible language (read: dynamic or sophisticated), a programming community could live without exception handling features, instead just promote a coding style for such particular service procedures (a limited list). One possible view is that languages where this is impracticle (too rigid) are otherwise wrongly-designed, but things are not that simple, maybe. Or, we could have a builtin feature making such handling clear & simple. In case of predictable exceptions, the simple (and imo right) way is just to use an if/else branching. if numbers: avg = average(numbers) else: # deal with exception Similarly, an alternative construct may simply allow not failing in case of unpredictable exceptions: maybe: idx = item_index(col, item) else: # deal with exception
This superficially looks like typical try/except or try/catch, but in fact here no throwing & catching happen at all. The failure is just signaled to the caller side, somehow (a plain flag). We may refine the construct with discrimination of error types, just like except/catch branches (may be good, indeed, but requires proper usage by client, which is not always well done). But in any case clients control the exception handling mechanism, everything is far simpler and easier, and there are no unneeded processes behing the stage.
On 02/21/2014 07:11 AM, Andrew Barnert wrote:
On Feb 20, 2014, at 18:23, spir denis.spir@gmail.com wrote:
On 02/20/2014 10:28 PM, Steven D'Aprano wrote:
On Thu, Feb 20, 2014 at 09:44:57PM +0100, spir wrote:
But I would like to be able to add an error type to assertions (in addition to the optional message). This is particularly useful for people (like me) who systematically check func inputs (for client debugging comfort), using assert's.
Then your code is systematically broken, and badly so.
Why do you speak _that_ negatively? (or should I say: _that_ violently?) And this, maybe not _that_ logically? Do you own the (copy)rights on proper usage of assert's?
All anyone needs to do to disable your checking is pass -O to the Python interpreter.
assert is not a short-cut for lazy programmers to avoid having to write an explicit "if cond: raise SomethingAppropriate(message)". Assertions have specific uses. You should read this post I made last November:
https://mail.python.org/pipermail/python-list/2013-November/660401.html
I think you are wrong, at least in this very case. Assert's for me are a debugging tool (or maybe more generally a tool for improving reliability). Such checks help finding errors and correcting them (thank to hopefully clear error messages), with a higher chance these corrections happen before "too late", meaning before users pay for our bugs. What else is the proper usage of assertions?
If not checked on function input, either with assert's or an if-raise combination, execution will break anyway, just later (later in time, and slightly further in code), because some input variable's value or type is wrong. Assert's placed that way are not strictly necessary (it's like duck typing: you don't need to check), instead they're a helpful tool for all users of your "service".
def average (numbers): n = len(numbers) assert n != 0, "Cannot compute average of 'zero number'.", ValueError return sum(numbers) / n
I think you're actually suffering from the confusion you accused Steven of. His post explains the difference between internal preconditions and external value checks. Then difference has nothing to do with the form of the function, but with how it's used.
If average is only called by your own code with your own values, so you know it can never be called with an empty list unless there's a bug somewhere, then you're asserting a precondition, which is exactly what asserts are for--but in that case this should be an AssertionError, not a ValueError.
If average is part of an external API, or is called with user data, so you're testing for something that could fail because of user error rather than a bug in your code, then this is a perfect case for a ValueError--but it's not an assertion, it's an error check.
The fact that assertions happen to work by exception handling doesn't mean you should ignore the difference between them.
side-note: from wikipedia [https://en.wikipedia.org/wiki/Assertion_%28software_development%29]:
Assertions during the development cycle
During the development cycle, the programmer will typically run the program with assertions enabled. When an assertion failure occurs, the programmer is immediately notified of the problem. Many assertion implementations will also halt the program's execution: this is useful, since if the program continued to run after an assertion violation occurred, it might corrupt its state and make the cause of the problem more difficult to locate. Using the information provided by the assertion failure (such as the location of the failure and perhaps a stack trace, or even the full program state if the environment supports core dumps or if the program is running in a debugger), the programmer can usually fix the problem. Thus assertions provide a very powerful tool in debugging.
This is what I do. Note that whether assertion instructions were written by the client developper (who gets assertion errors) or by the author of a tool used for this project, does not change anything: in both cases, the client is properly notified of his/her errors. In fact, there is no other border between internal and external components (modules, libs...) than a purely practical one. Semantically, it makes no sense (for me). The very same component can be written for a given project and distributed together with the rest, or written by someone else and installed apart. What is important is _coherence_ (or meaningfulness); this is what assertions check.
d
On 2014-02-20 18:10, Ryan Gonzalez wrote:
I propose a `raise_if` function. If the given condition is True, an exception is raised. So, the above examples would be shortened to:
raise_if(x!=y, ValueError, 'x != y!!') raise_if(not isinstance(x,SomeType),TypeError, 'x is not SomeType!')
There could also be a raise_if_not function that does the opposite:
raise_if_not(isinstance(x,SomeType), TypeError, 'x is not SomeType!')
Thoughts?
I don't see what is wrong with using `if`-statements. They're IMO more readable and obviously they have more usecases.
-- Markus
On Thu, Feb 20, 2014 at 11:10:58AM -0600, Ryan Gonzalez wrote:
In Python, you'll constantly see code like this:
if x != y: raise ValueError('x != y!!')
or:
if not isinstance(x,SomeType): raise TypeError('x is not SomeType!')
Assertion help a bit:
assert isinstance(x,SomeType), 'x is not SomeType!'
Notice I said "a bit". If optimizations are on, they're disabled. In addition, the only type of error thrown is an AssertionError.
Which is why asserts do not help at all. If somebody is using an assertion merely to save typing out
if cond: raise MoreAppropriateError(message)
then their code is poorly-written and probably broken.
I propose a `raise_if` function. If the given condition is True, an exception is raised. So, the above examples would be shortened to:
Put this at the top of your module:
def raise_if(condition, exception, message): if condition: raise exception(message)
Not every three line function needs to be a built-in.