-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
leap: Change tests assertIs(..., True)
for assertTrue(...)
#419
Conversation
Predicate functions shouldn't convert its implementation based on logic expressions (combinations of `not`, `and` and `or`). I.e. The following should be correct: def is_NOT_divisible_by_4(n): return n % 4 assert is_NOT_divisible_by_4(10) But as the TestCases for this exercise are using `assertIs(..., True) instead of `assertTrue(...)`, implementations cointing on the numbers behaviour on boolean contexts will Fail. What this mean, is that for the given definition of `is_NOT_divisible_by_4`, the folloging assertion will Fail: assert is_NOT_divisible_by_4(10) == True I think it is meaningless to check for `True` as it is naive to write: if predicate(x) == True: do_something(x) Instead of: if predicate(x): do_something(x)
I strongly disagree. But maybe we can get more feedback on this. /cc @rootulp @pheanex @treyhunner The history is that C back in 1972 didn't have a Boolean type and to this day they are commonly represented by integers in C programs. Also Python started without Boolean and added it with 2.3 if I remember correctly. So, that A predicate maps every argument to either true or false and a function maps every argument to a value. So perfect examples for a predicate functions like |
I'd go with the PEP8 suggestion: "Don't compare boolean values to True or False using ==". |
@behrtam I feel you, but remember that Python defines boolean_contexts. So # Altough ...
if [1,2,3]: print("will be printed")
# This ...
if [1,2,3] == True: print("this will not be printed :'(")
if [1,2,3] is True: print("and this neither :'(") I've seen this practice not as a baggage from ancient times, but a Python way of reducing code, avoiding stuffs like: if boolean([1,2,3]): print("will be printed") Altough good in one way, any one could argue it is bad in the sense that it promotes the if len([1,2,3]) > 0: ... But in any case, it is just another discussion that does nothing with the fact that in Python not only you can test truthfulness directly from some objects which implement a boolean context, but it is actually encouraged. |
I'm torn on this. I encourage students/peers to rely on truthiness to test for emptiness. numbers = [1, 2, 3]
if numbers:
print("numbers is not empty") But I don't typically encourage relying on truthiness for testing for non-zeroness though. I'd usually rather see However, I'm not sure how common this behavior is in other code and I don't know whether we should assume that the function returns Here's a semi-related StackOverflow question with answers from Alex Martelli and Guido van Rossum. Unfortunately it doesn't answer this specific question directly (should this function return a truthy value or specifically |
I think the key is in this question you do:
And it is easy: how do you imagine client code using the function if is_leap_year(1996):
do_something() or if is_leap_year(1996) is True:
do_something() |
You could always write Okay, let's try to look at this from another angle. How would a solution to leap year look like that returns a truthy value instead of True/False? |
In that case, I would say then that the tests should accept solutions that return truthy values instead of True/False.
This is an example. It returns for the year For def is_leap_year(year):
return not year%4 and year % 100 or not year % 400 This example would be accepted if the tests would check with I would add another point of view also.
There is a recommendation in the same documentation on Well, then, we could argue the same for As a curiosity, note how the implementation of |
>>> def is_leap_year(year):
... return not year % 4 and year % 100 or not year % 400
...
>>> [is_leap_year(y) for y in [1996, 1997, 1998, 2004, 2400]]
[96, False, False, 4, True]
>>> I also tried to come up with an truthy example and only found solutions like yours that only sometimes return truthy values. So is our intention to encourage ugly solutions that return Booleans and Integers? The error messages only differ in one character which is either upper or lower case:
Note: I just try to play devil's advocate to find out what the consequences are of this change, but maybe I'm overdoing it. All existing solutions would still be green and those that would newly be accepted would also be doing the right thing. So, maybe we should just merge it. |
I think this test: self.assertTrue(is_leap_year(1996)) is clearer than this test: self.assertIs(is_leap_year(1996), True) Unfortunately, using def is_leap_year(year):
return not year % 4 and year % 100 or not year % 400 is far less easy to reason about than an implementation that explicitly returns |
I totally agree with @rootulp. Normally |
Predicate functions shouldn't convert its implementation based on
logic expressions (combinations of
not
,and
andor
).I.e. The following should be correct:
But as the TestCases for this exercise are using
assertIs(..., True) instead of
assertTrue(...)`, implementations cointing on the numbersbehaviour on boolean contexts will Fail.
What this mean, is that for the given definition of
is_NOT_divisible_by_4
, the folloging assertion will Fail:I think it is meaningless to check for
True
as it is naive to write:Instead of: