Witnesses and Counterexamples
00:00
Witnesses and counterexamples. In the examples you’ve seen so far, the assignment expression operator does essentially the same job as the assignment operator in your old code. You’ve seen how to simplify code, and now you’ll learn about a different type of use case that’s made possible by this new operator. In this section, you’ll learn how you can find witnesses when calling any()
by using a clever trick that isn’t possible without using the walrus operator.
00:29
A witness in this context is an element that satisfies the check and causes any()
to return True
. By applying similar logic, you’ll also learn how you can find counterexamples when working with all()
. A counterexample in this context is an element that doesn’t satisfy the check and causes all()
to return False
.
00:50 In order to have some data to work with, start out by defining a list of city names.
01:08
You can then use any()
and all()
to answer questions about your data.
01:46
In each of these cases, any()
and all()
give you a plain True
or False
answer. What if you’re also interested in seeing an example or a counterexample of the city names? It could be nice to see what’s causing the True
or False
result.
02:02
Does any city name start with "H"
. Well, yes, because "Houston"
starts with "H"
. Do all city names start with "H"
?
02:10
Well, no, because "Oslo"
doesn’t. In other words, you want a witness or a counterexample to justify the answer. Capturing a witness to an any()
expression has not been intuitive in earlier versions of Python.
02:23
If you were calling any()
on a list and then realized you also wanted a witness, you’d typically need to rewrite your code.
03:00
Here, you first capture all city names that start with "H"
. Then, if there’s at least one such city name, you print out the first city name starting with "H"
. Note that here you’re not actually using any()
, even though you’re doing a similar operation with a list comprehension. By using the walrus operator, you can find witnesses directly in your any()
expressions.
03:49
You can capture a witness inside the any()
expression. The reason this works is a bit subtle and relies on the fact that any()
and all()
use short-circuit evaluation.
03:59
They only check as many items as necessary to determine the result. If you want to check whether all city names start with the letter "H"
, then you can look for a counterexample by replacing any()
with all()
and updating the print()
functions to report the first item that doesn’t pass the check.
04:17
You can see what’s happening more clearly by wrapping .startswith()
in a function that also prints out the item that’s being checked.
04:53
Now you can clearly see that any()
doesn’t actually check all items in cities
. It only checks items until it finds one that satisfies the condition.
05:02
Combining the walrus operator and any()
works by iteratively assigning each item that’s being checked to witness
. However, only the last such item survives and shows which item was last checked by any()
.
05:15
Even when any()
returns False
, a witness is found.
05:32 However, in this case, the witness doesn’t give any insight. It doesn’t contain more than ten characters, and it only shows which item happened to be evaluated last.
05:44 In the next chapter of the course, you’ll take a closer look at the syntax needed around the walrus operator.
Become a Member to join the conversation.