python / cpython

The Python programming language
https://www.python.org
Other
63.48k stars 30.39k forks source link

Add .lastitem attribute to takewhile instances #63021

Closed a35477f8-71c1-46d8-a00e-b2f89ce712bf closed 11 years ago

a35477f8-71c1-46d8-a00e-b2f89ce712bf commented 11 years ago
BPO 18821
Nosy @rhettinger, @PCManticore, @serhiy-storchaka
Files
  • itertools_takewhile.patch
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields: ```python assignee = 'https://github.com/rhettinger' closed_at = created_at = labels = ['type-feature', 'library'] title = 'Add .lastitem attribute to takewhile instances' updated_at = user = 'https://bugs.python.org/oscarbenjamin' ``` bugs.python.org fields: ```python activity = actor = 'oscarbenjamin' assignee = 'rhettinger' closed = True closed_date = closer = 'rhettinger' components = ['Library (Lib)'] creation = creator = 'oscarbenjamin' dependencies = [] files = ['31647'] hgrepos = [] issue_num = 18821 keywords = ['patch'] message_count = 5.0 messages = ['195962', '197167', '197171', '197311', '197317'] nosy_count = 4.0 nosy_names = ['rhettinger', 'Claudiu.Popa', 'serhiy.storchaka', 'oscarbenjamin'] pr_nums = [] priority = 'normal' resolution = 'rejected' stage = None status = 'closed' superseder = None type = 'enhancement' url = 'https://bugs.python.org/issue18821' versions = ['Python 3.4'] ```

    a35477f8-71c1-46d8-a00e-b2f89ce712bf commented 11 years ago

    I've often wanted to be able to query a takewhile object to discover the item that failed the predicate but the item is currently discarded.

    A usage example:

    def sum(items):
        it = iter(items)
        ints = takewhile(Integral.__instancecheck__, it)
        subtotal = sum(ints)
        if not hasattr(ints.lastitem):
            return subtotal
        floats = takewhile(float.__instancecheck__, it)
        subtotalf = fsum(floats)
        if not hasattr(floats.lastitem):
            return subtotal + subtotalf
        # Deal with more types
        ...

    Loosely what I'm thinking is this but perhaps with different attribute names:

    class takewhile(pred, iterable):
        def __init__(self):
            self.pred = pred
            self.iterable = iterable
            self.failed = False
        def __iter__(self):
            for item in self.iterable:
                if self.pred(item):
                    yield item
                else:
                    self.failed = True
                    self.lastitem = item
                    return
    5df057ac-c83d-447e-8c45-910556b17608 commented 11 years ago

    Hello. Here's a basic patch with tests which accomplishes your request. Currently, it defaults to None if no item failed, but probably it can be set only when something fails the predicate (and the user will check using hasattr(t, 'last') ).

    serhiy-storchaka commented 11 years ago

    Oscar, did you considered itertools.groupby()? Perhaps it better meets your needs.

    rhettinger commented 11 years ago

    Oscar, the solution proposed by Serhiy looks like a better choice.

    I'm wary of increasing the API complexity of the itertools. Right now, their learnability is aided by having simple signatures and no side-values.

    The itertools are modeled on functional tools in other languages with mature APIs. I look to those languages to provide an indication of whether proposed features are needed in practice. AFAICT, there is no precedent for a takewhile-with-failed-value combo.

    I appreciate your request (especially because it was accompanied by a use case) but am going to decline. IMO, the module as a whole is better served by keeping the tools simple and clean.

    If an individual itertool doesn't have an exact fit to a particular use case, it may indicate that the programmer would be better served by a simple generator which can express the logic more cleanly than a tricked-out itertool with side-values.

    a35477f8-71c1-46d8-a00e-b2f89ce712bf commented 11 years ago

    Thank you Claudiu very much for writing a patch; I was expecting to have to do that myself!

    Serhiy, you're right groupby is a better fit for this. It does mean a bit of reworking for the (more complicated) sum function I'm working on but I've just checked with timeit and it performs very well using the type function as a predicate. I think it might make the function a few times faster than takewhile in my common cases for reasons that are particular to this problem.

    Raymond, thanks for taking the time to consider this. I agree that it should now be closed.