Python Enhancement Proposal for List methods

Hey everyone, I am really new to Python contribution community want to propose below methods for List object. Forgive me if this is not the format to send an email. 1. *list.replace( item_to_be_replaced, new_item )*: which replaces all the occurrences of an element in the list instead of writing a new list comprehension in place. 2. *list.replace( item_to_be_replaced, new_item, number_of_occurrences )*: which replaces the occurrences of an element in the list till specific number of occurrences of that element. The number_of_occurrences can defaulted to 0 which will replace all the occurrences in place. 3. *list.removeall( item_to_be_removed )*: which removes all the occurrences of an element in a list in place. What do you think about these features? Are they PEP-able? Did anyone tried to implement these features before? Please let me know. Thank you, Sukumar

The list comprehensions are not very hard, and are more general. EXCEPT with the limited number of occurrences. We have this for str.replace(..., max=n), and it is useful fairly often. I'm +0.5 on .replace() with that capability. But -1 on .removeall() that adds nothing to an easy listcomp. On Sun, Oct 21, 2018, 9:01 AM Siva Sukumar Reddy <sukurcf@gmail.com wrote:

21.10.18 16:00, Siva Sukumar Reddy пише:
See the previous discussion about this three years ago: https://mail.python.org/pipermail/python-ideas/2015-October/036770.html The conclusion is that this feature is too niche. It works only with lists, and supports only one test predicate (equality to a specified value). filter() and comprehensions are more general.

On 10/21/2018 9:00 AM, Siva Sukumar Reddy wrote:
I am really new to Python contribution community want to propose below methods for List object.
For most classes, there is an infinite number of possible functions that could be made into methods. The Python philosophy is to include as methods the basic functions needed to write other functions. So number classes include the basic operations of +, -, *, /, and ** as methods. The math and cmath modules contain number functions that use these basic operations. The list class also has a fairly small set of methods. Nearly all are either original or were added before list.pop, about 20 years ago. list.clear was added more recently, in analogy with dict.clear, and there was some opposition because there are other ways to clear a list.
I presume these are somewhat in analogy with str.replace(old, new, count=-1), except for being limited to one sequence member and being done in place. Note that only 1 method is needed and the default count should be -1, not 0. However, the need for a built-in method is much, much less. Nearly all cases that need to be done inline code can be done like this. for i, item in enumerate(mylist): if item == old: mylist[i] = new As Serhiy noted from previous discussion, other conditions are possible, such as 'item in {old1, old2, old3}' or, given a list of numbers, if item > max: mylist[i] = max
3. *list.removeall( item_to_be_removed )*: which removes all the occurrences of an element in a list in place.
str.replace(old, '') does this (not in place) for strings. There are also str.translate and re.sub and re.subn. An indefinite number of in-place removes is a generally a bad idea unless done carefully. alist.remove is inherently O(n). alist.removeall implemented naively would be O(n*n)/ alist = [x for x in alist if x == old] or alist = list(x for x in alist if x == old) or alist = list(filter(lambda x: x == old)) is O(n). Again, as Serhiy noted, 'x == old' is only one possible condition. The last example illustrates another point. In Python 3, one can usually and often should avoid turning streams of objects into a concrete list until one needs one of the particular list operations. I noted above that we have only added 1 list method (that I know of) since .pop. On the other hand, we added generators and then the itertools module with multiple basic functions and multiple recipes based on those functions. Since lists are no longer the basic representation of sequences of items, adding list methods is somewhat obsolete. If possible, it is best to filter out multiple items when creating the list instead of later. Or to put it another way, it is best to avoid turning a stream into a list for as long as possible. If space and aliasing are not issues, replacing a list is easier and possibly faster that editing it in place. Note that editors for adding, replacing, and deleting items tend to use tree structures rather than a single linear sequence. An alternative to removing items is to replace them with a null value, such as None, '', 0, 1 (for multiplication), 'pass' (for code execution), or sentinal=object(). The choice depends on what is to be done later. In fact, temporary replacement is the key to efficient multiple removals. -- Terry Jan Reedy

On Mon, Oct 22, 2018 at 7:58 AM Terry Reedy <tjreedy@udel.edu> wrote:
That's actually a good reason to make it part of the language or stdlib - it's very easy to get it wrong. All of the above are not in-place. If I were to make a stdlib function to do removeall, it would be: seq[:] = [x for x in seq if x != removeme] (And that one probably missed some subtlety somewhere too.) So it'd be less buggy for people to reach for a standard solution than to try to craft their own. That said, though, I think this probably belongs as a recipe, not as a stdlib function or method. ChrisA

The list comprehensions are not very hard, and are more general. EXCEPT with the limited number of occurrences. We have this for str.replace(..., max=n), and it is useful fairly often. I'm +0.5 on .replace() with that capability. But -1 on .removeall() that adds nothing to an easy listcomp. On Sun, Oct 21, 2018, 9:01 AM Siva Sukumar Reddy <sukurcf@gmail.com wrote:

21.10.18 16:00, Siva Sukumar Reddy пише:
See the previous discussion about this three years ago: https://mail.python.org/pipermail/python-ideas/2015-October/036770.html The conclusion is that this feature is too niche. It works only with lists, and supports only one test predicate (equality to a specified value). filter() and comprehensions are more general.

On 10/21/2018 9:00 AM, Siva Sukumar Reddy wrote:
I am really new to Python contribution community want to propose below methods for List object.
For most classes, there is an infinite number of possible functions that could be made into methods. The Python philosophy is to include as methods the basic functions needed to write other functions. So number classes include the basic operations of +, -, *, /, and ** as methods. The math and cmath modules contain number functions that use these basic operations. The list class also has a fairly small set of methods. Nearly all are either original or were added before list.pop, about 20 years ago. list.clear was added more recently, in analogy with dict.clear, and there was some opposition because there are other ways to clear a list.
I presume these are somewhat in analogy with str.replace(old, new, count=-1), except for being limited to one sequence member and being done in place. Note that only 1 method is needed and the default count should be -1, not 0. However, the need for a built-in method is much, much less. Nearly all cases that need to be done inline code can be done like this. for i, item in enumerate(mylist): if item == old: mylist[i] = new As Serhiy noted from previous discussion, other conditions are possible, such as 'item in {old1, old2, old3}' or, given a list of numbers, if item > max: mylist[i] = max
3. *list.removeall( item_to_be_removed )*: which removes all the occurrences of an element in a list in place.
str.replace(old, '') does this (not in place) for strings. There are also str.translate and re.sub and re.subn. An indefinite number of in-place removes is a generally a bad idea unless done carefully. alist.remove is inherently O(n). alist.removeall implemented naively would be O(n*n)/ alist = [x for x in alist if x == old] or alist = list(x for x in alist if x == old) or alist = list(filter(lambda x: x == old)) is O(n). Again, as Serhiy noted, 'x == old' is only one possible condition. The last example illustrates another point. In Python 3, one can usually and often should avoid turning streams of objects into a concrete list until one needs one of the particular list operations. I noted above that we have only added 1 list method (that I know of) since .pop. On the other hand, we added generators and then the itertools module with multiple basic functions and multiple recipes based on those functions. Since lists are no longer the basic representation of sequences of items, adding list methods is somewhat obsolete. If possible, it is best to filter out multiple items when creating the list instead of later. Or to put it another way, it is best to avoid turning a stream into a list for as long as possible. If space and aliasing are not issues, replacing a list is easier and possibly faster that editing it in place. Note that editors for adding, replacing, and deleting items tend to use tree structures rather than a single linear sequence. An alternative to removing items is to replace them with a null value, such as None, '', 0, 1 (for multiplication), 'pass' (for code execution), or sentinal=object(). The choice depends on what is to be done later. In fact, temporary replacement is the key to efficient multiple removals. -- Terry Jan Reedy

On Mon, Oct 22, 2018 at 7:58 AM Terry Reedy <tjreedy@udel.edu> wrote:
That's actually a good reason to make it part of the language or stdlib - it's very easy to get it wrong. All of the above are not in-place. If I were to make a stdlib function to do removeall, it would be: seq[:] = [x for x in seq if x != removeme] (And that one probably missed some subtlety somewhere too.) So it'd be less buggy for people to reach for a standard solution than to try to craft their own. That said, though, I think this probably belongs as a recipe, not as a stdlib function or method. ChrisA
participants (5)
-
Chris Angelico
-
David Mertz
-
Serhiy Storchaka
-
Siva Sukumar Reddy
-
Terry Reedy