Hi, people. In the `heapq' module, I'm a little bothered by the fact modules names have `heap' as a prefix in their name. If the methods have been installed as standard list methods, it would be quite understandable, but it has been decided otherwise. The most usual way of using a module is: import MODULE ... MODULE.METHOD(ARGUMENTS) rather than: from MODULE import METHOD ... METHOD(ARGUMENTS) and we should name METHODs accordingly, not repeating the MODULE as prefix. This is a rather common usage, almost everywhere in the Python library. So my suggestion of changing now, before `heapq' gets released for real: heappush -> push heappop -> pop heapreplace -> replace I guess that `heapify' is OK as it stands. The example should be changed accordingly, that is, using `import heapq' instead of `from heapq import such-and-such', using `heapq.push' instead of `heappush' and `heapq.pop' instead of `heappop'. -- François Pinard http://www.iro.umontreal.ca/~pinard
In the `heapq' module, I'm a little bothered by the fact modules names have `heap' as a prefix in their name. If the methods have been installed as standard list methods, it would be quite understandable, but it has been decided otherwise.
The most usual way of using a module is:
import MODULE ... MODULE.METHOD(ARGUMENTS)
rather than:
from MODULE import METHOD ... METHOD(ARGUMENTS)
and we should name METHODs accordingly, not repeating the MODULE as prefix. This is a rather common usage, almost everywhere in the Python library.
So my suggestion of changing now, before `heapq' gets released for real:
heappush -> push heappop -> pop heapreplace -> replace
I guess that `heapify' is OK as it stands.
The example should be changed accordingly, that is, using `import heapq' instead of `from heapq import such-and-such', using `heapq.push' instead of `heappush' and `heapq.pop' instead of `heappop'.
-1. The nmes 'push', 'pop' and 'replace' are too generic. The module seems to "invite" the ``from heapq import heappush, heappop'' syntax, and I'd like to honor that. --Guido van Rossum (home page: http://www.python.org/~guido/)
[Guido van Rossum]
So my suggestion of changing now, before `heapq' gets released for real:
heappush -> push heappop -> pop heapreplace -> replace
-1. The nmes 'push', 'pop' and 'replace' are too generic. The module seems to "invite" the ``from heapq import heappush, heappop'' syntax, and I'd like to honor that.
May I invite you to reconsider? We are going to live with that one for a loong time, you know... Quite granted, as it stands, the module invites the long form of import (from MODULE import LIST-OF-NAMES). This _is_ what I question. Writing `heapq.heapXXX' is kind of ugly, people are going to spontaneously avoid it, especially given that the documentation says to do so. Yet, the long import line is uselessly tedious to write. I would not think the author really wrote `heappush' and `heappop' with the intent that they could sit in a module and be imported with the long form, but rather as inlinable `def', or maybe rather as built-in methods for `list' objects. That intent changing, the method names are then asking to be revised. There are not much cases in the Python library where the `from ... import' is forced upon users in practice. The `BaseHTTPServer' module and friends are the only examples that come to mind, and I find these import lines especially cumbersome to write: hopefully, these are not to be used often. The `heapq' module is different, as for some programmers, it might be used often, and I do not see a real reason for making it tedious or different. As for `push' etc. being too generic, there are used in the context of a specialised module, which gives these word there specialised meaning, so genericity is not a real argument. Other modules already qualify simple words. Has it been a problem? Even, would it be that some people really want to write `from MODULE import *' or `from MODULE import SUCH-AND-SUCH' for a lot of modules at global scope, something which is not to be encouraged anyway, these users still have `from ... import ... as' to help them. Please consider altering the current `heapq' module so to _not_ invite a different importing style. Make it more similar to the rest of the library, there is probably no real need for a difference. Let it be nicer to use! -- François Pinard http://www.iro.umontreal.ca/~pinard
sön 2002-08-25 klockan 14.04 skrev François Pinard:
As for `push' etc. being too generic, there are used in the context of a specialised module, which gives these word there specialised meaning, so genericity is not a real argument. Other modules already qualify simple words. Has it been a problem? Even, would it be that some people really want to write `from MODULE import *' or `from MODULE import SUCH-AND-SUCH' for a lot of modules at global scope, something which is not to be encouraged anyway, these users still have `from ... import ... as' to help them.
Please consider altering the current `heapq' module so to _not_ invite a different importing style. Make it more similar to the rest of the library, there is probably no real need for a difference. Let it be nicer to use!
I agree completely. And as for the names being too generic. Well, gee, they *are* usually used for putting an element in the data structure, removing an element from the data structure, et.c. Often regardless of the data structure/ADT. I've always used push, pop (and peek et.c.) for heaps, as well as stacks. If anything, I think that the pop method of lists is confusing :-) Regards, Martin
Note that it's common to use the bisect module in the from bisect import bisect_right, bisect, insort way too, rather than spell out bisect.bisect (etc) each time. That's "the other" module that (conceptually) adds new methods to lists. If you want simpler names, I'm finding this little module quite pleasant to use: """ import heapq class Heap(list): def __init__(self, iterable=[]): self.extend(iterable) push = heapq.heappush popmin = heapq.heappop replace = heapq.heapreplace heapify = heapq.heapify """ That is, it creates a Heap type that's just a list with some extra methods. Note that the "pop" method can't be named "pop"! If you try, you'll soon get unbounded recursion because the heapq functions need list.pop to access the list meaning of "pop". Guido suggested a long time ago that such a class could be added to heapq, and I like it a lot in real life.
[Tim Peters]
Note that it's common to use the bisect module in the
from bisect import bisect_right, bisect, insort
way too, rather than spell out bisect.bisect (etc) each time. That's "the other" module that (conceptually) adds new methods to lists.
Wow! You just put the finger on it... I wondered a few times why this module never attracted me! :-) :-)
If you want simpler names, I'm finding this little module quite pleasant to use: [...] That is, it creates a Heap type that's just a list with some extra methods.
Very elegant indeed. Something like this was discussed earlier, but faded out of my memory. Thanks for the tip, Tim!
Note that the "pop" method can't be named "pop"! If you try, you'll soon get unbounded recursion because the heapq functions need list.pop to access the list meaning of "pop".
Sold! `popmin' is adequate and clear. -- François Pinard http://www.iro.umontreal.ca/~pinard
"TP" == Tim Peters <tim.one@comcast.net> writes:
TP> That is, it creates a Heap type that's just a list with some TP> extra methods. Note that the "pop" method can't be named "pop"! TP> If you try, you'll soon get unbounded recursion because the TP> heapq functions need list.pop to access the list meaning of TP> "pop". TP> Guido suggested a long time ago that such a class could be added TP> to heapq, and I like it a lot in real life. You can't use all of the regular list methods, right? If I'd called append() an a Heap(), it wouldn't maintain the heap invariant. I would think the same is true of insert() and lots of other methods. If we add a Heap class, which seems quite handy, maybe we should disable methods that don't work. Interesting to note that if you disable the invalid methods of list, then you've got a subclass of list that is not a subtype. Jeremy
[Jeremy Hylton]
You can't use all of the regular list methods, right? If I'd called append() an a Heap(), it wouldn't maintain the heap invariant. I would think the same is true of insert() and lots of other methods.
Well, you *can* use all list methods, just as you can already call heapq.heappop and pass any old list. heapify exists so that you can repair the heap invariant if you have reason to believe you may have broken it.
If we add a Heap class, which seems quite handy, maybe we should disable methods that don't work.
If it were called PriorityQueue, definitely, but "a heap" is a specific implementation and heap users can exploit the list representation in lots of interesting ways.
Interesting to note that if you disable the invalid methods of list, then you've got a subclass of list that is not a subtype.
It is an interesting case this way! There's a related case that's perhaps of more pressing interest: Raymond Hettinger has pointed out that, e.g., 3 in Set is much slower than 3 in dict This is because Set.__contains__ is a Python-level call. I sped up almost all the binary set operations yesterday by factors of 2 to 5, mostly via just using the underlying dict.__contains__ under the covers instead of appealing to Set.__contains__. For "simple sets" (sets that don't magically try to convert mutable objects-- like sets --into immutable objects), the speed of 3 in Set could be restored by subclassing from dict and inheriting its __contains__. But Set is trying not to make any promises about representation, so this is a clearer case for some form of "(only) implementation inheritance". The desire is driven only by speed, but that can be a legit concern too (I'm not sure it's a killer concern in this particular case).
From: "Tim Peters" <tim.one@comcast.net>
If you want simpler names, I'm finding this little module quite pleasant to use:
""" import heapq
class Heap(list): def __init__(self, iterable=[]): self.extend(iterable) push = heapq.heappush popmin = heapq.heappop replace = heapq.heapreplace heapify = heapq.heapify """
And perhaps: def __iter__(self): while True: yield self.popmin() Raymond Hettinger
[Raymond Hettinger, on """ import heapq class Heap(list): def __init__(self, iterable=[]): self.extend(iterable) push = heapq.heappush popmin = heapq.heappop replace = heapq.heapreplace heapify = heapq.heapify """ ]
And perhaps: def __iter__(self): while True: yield self.popmin()
If we were trying to hide the list nature, yes, but I don't think so if the intent is that a heapq heap *is* a list with a few extra methods. For example, I know I've already done max(h) at least once for a Heap of this type, with the list meaning in mind, and it would have been at best irritating if that had emptied the heap as a side effect. Renaming __iter__ to heapiter would be cool, though!
May I invite you to reconsider? We are going to live with that one for a loong time, you know...
I know. I have read and re-read your arguments, but I see nothing to change my mind. Somehow the short names you suggest just seem wrong to me. We can agree to disagree, but I feel strongly that the names should not be changed. --Guido van Rossum (home page: http://www.python.org/~guido/)
[Guido van Rossum]
May I invite you to reconsider? We are going to live with that one for a loong time, you know...
I know. I have read and re-read your arguments, but I see nothing to change my mind. Somehow the short names you suggest just seem wrong to me. We can agree to disagree, but I feel strongly that the names should not be changed.
As you did read my arguments (from your first reply, I thought you missed them, and this is why I tried explaining them better), and that I have nothing substantially new to offer, that closes this discussion... We are solidly set on the current documentation. To be or not to be, ... etc. :-) Have a good day, and keep happy! -- François Pinard http://www.iro.umontreal.ca/~pinard
participants (6)
-
Guido van Rossum -
Jeremy Hylton -
Martin Sjögren -
pinard@iro.umontreal.ca -
Raymond Hettinger -
Tim Peters