Tutorial 1
Task: define a predicate expression that given a list of values, returns True if:
all values are either strings or integers
if the value is an integer, than it should be less than 5
if the value is a string, it should start with foo
This will show a couple of concepts and useful standard predicates.
Let’s start with the first requirement. We start first with the code and then explain it:
from predicate import all_p, is_int_p, is_str_p
predicate = all_p(is_int_p | is_str_p)
In the example above we import 3 predicates. The all_p
accepts one parameter, which is another predicate. The
is_int_p
checks if a value is an integer. And finally the is_str_p
checks if a value is a string.
We combine the is_int_p
and is_str_p
with the |
operator, resulting in a new predicate.
This is sufficient for the first requirement. Now lets restrict the allowed value of the integer to less than 5:
from predicate import all_p, is_int_p, is_str_p, lt_p
is_int_lt_5 = is_int_p & lt_p(5)
predicate = all_p(is_int_lt_5 | is_str_p)
As you can see, we imported the lt_p
predicate. This checks if a given value, is less than the parameter
(5 in this case). We could have made this a one-liner, but we assigned it to a new predicate variable
is_int_lt_5
. With this addition, we have implemented the second requirement.
Finally we turn to the third requirement, which says that if the value is a string, it should start with “foo”. This sounds like an ideal candidate for a regular expression, and indeed such a predicate is also available:
from predicate import all_p, is_int_p, is_str_p, lt_p, regex_p
is_int_lt_5 = is_int_p & lt_p(5)
is_str_foo = is_str_p & regex_p("^foo.*")
predicate = all_p(is_int_lt_5 | is_str_foo)
Now you are ready to check your new predicate against the requirements, for example:
predicate([1, "foo"]) # True
predicate([1, "foo", None]) # False, None is not valid
predicate([5, "foo"]) # False, 5 is to big
predicate([1, "bar"]) # False, "bar" doesn't begin with "foo"
Let’s now reuse this predicate to generate some sample values:
from predicate import generate_true
from more_itertools import take
result = take(10, generate_true(predicate))
Notice that this may take a few seconds. On my system the output was:
[
[],
(1, -1, "foo", "foo!", "foo!", 'foo"'),
{0, -5, "foo"},
["foo5xT", "foo5xT", "foo", "foo ", "foo!", -1],
(0, -1, -1, -1, "foo"),
{"fooU7", "fooRV8TMtF", "foor959aO5"},
[-9, "foo", "foojBA", "foo ", "foo "],
("foohqhdJr", "foou", "foo", 1, 1, 1, 1, 1, 2),
{1, "foo", "foo!", -1, 'foo"'},
["foo", -1, -1, "foo", "foo", "foo ", 0, 'foo"', 'foo"'],
]
If you don’t want to check manually if these values are correct, you can of course use a predicate:
validate = all_p(predicate)
validate(result)
This should result in True
. If not, please submit a bug report.