2018-03-06 14:17 GMT+03:00 Steven D'Aprano < steve+comp.lang.pyt...@pearwood.info>:
> On Tue, 06 Mar 2018 11:52:22 +0300, Kirill Balunov wrote: > > > I propose to delete all references in the `filter` documentation that > > the first argument can be `None`, with possible depreciation of `None` > > as the the first argument - FutureWarning in Python 3.8+ and deleting > > this option in Python 4. > > Even if we agreed that it is unfortunate that filter accepts None as an > argument, since it does (and has done since Python 1.0) there is nothing > to be gained by deprecating and removing it. > > Deprecating and removing it will break code that currently works, for no > good reason; removing the documentation is unacceptable, as that makes it > too difficult for people to find out what `filter(None, values)` does. > As I wrote, __possible depreciation__, I also do not see the point of just breaking someone's code. But I didn't see any benefit to explicitly promote `filter(None, iterable)` form in the documentation as a good style. > > Instead, it is better to show an example with using > > `filter(bool, iterable)` which is absolutely > > equivalent, more readable, but a little bit slower. > > So long as `filter(None, ...)` is still documented, I don't mind what > example is given. > > But the idiom `filter(None, ...)` is an old, common idiom, very familiar > to many people who have a background in functional programming. > While this form familiar and common idiom for those who are familiar with Python from versions < 2.3, before `bool` type was introduced. It looks kinky for newcomers and not obvious at a glance. In functional programming we use a predicate, and `None` does not match predicate definition, while `bool` does! > It is unfortunate that filter takes the arguments in the order it does. > Perhaps it would have been better to write it like this: > > def filter(iterable, predicate=None): > ... > > > Then `filter(values, None)` would be a standard Python idiom, explicitly > saying to use the default predicate function. There is no difference to > `filter(None, values)` except the order is (sadly) reversed. > If such a form was in Python, I probably would agree with you. Although in its present form I like it a lot more and find it more intuitive. > Currently documentation for `None` case uses `identity function is > > assumed`, what is this `identity` and how it is consistent with > > truthfulness? > > The identity function is a mathematical term for a function that returns > its argument unchanged: > > def identity(x): > return x > > So `filter(func, values)` filters according to func(x); using None > instead filters according to x alone, without the expense of calling a do- > nothing function: > > # slow because it has to call the lambda function each time; > filter(lambda x: x, values) > > # fast because filter takes an optimized path > filter(None, values) > > Since filter filters according to the truthy or falsey value of x, it > isn't actually necessary to call bool(x). In Python, all values are > automatically considered either truthy or falsey. The reason to call > bool() is to ensure you have a canonical True/False value, and there's no > need for that here. I went over a bit with the question what is identity function :) But I have a feeling that I perceive all of the above quite the contrary in the context of a `filter` function. And since filter filters according to the truthy or falsey value of x. `None` and `bool` should behave totally equivalent under the hood and I'm 99% sure that it is so. > So the identity function should be preferred to bool, > for those who understand two things: > > - the identity function (using None as the predicate function) > returns x unchanged; > Sorry, but how does the above relates to the `filter` discussion? > > - and that x, like all values, automatically has a truthy value in a > boolean context (which includes filter). > > Yes, and that is why there is no point to `None` since they will do the same thing in context of `filter` function. > > In addition, this change makes the perception of `map` and `filter` more > > consistent,with the rule that first argument must be `callable`. > > I consider that a flaw in map. map should also accept None as the > identity function, so that map(None, iterable) returns the values of > iterable unchanged. > > def map(function=None, *iterables): > if len(iterables) == 0: > raise TypeError("map() must have at least two arguments.") > if function is None: > if len(iterables) > 1: > return zip(*iterables) > else: > assert len(iterables) == 1 > return iter(iterables[0]) > elif len(iterables) > 1: > return (function(*args) for args in zip(*iterables)) > else: > assert len(iterables) == 1 > return (function(arg) for arg in iterables[0]) > And what will be the practical reason to have this? :) With kind regards, -gdg -- https://mail.python.org/mailman/listinfo/python-list