Module attributes make sense; make them attributes of object has the unfortunate side effect that they will be attributes of *all* objects and that doesn't seem a good idea.
The math module is only appropriate if this is primarily about float numbers. And see PEP 747 in that case.
You mean PEP 754, right? Just like creating an arbitrarily large integer, floating point infinity is also arbitrary, and may not be big enough.
I just got a comment from another user suggesting modifying the min/max.__cmp__ so that they are the actual minimum and maximum.
An interesting approach, which makes some sense to me.
[[ I apologize in advance for not carrying along the In-Reply-To and References headers, I just finally got around to subscribing to this list. ]] This was my suggestion. I am for this PEP and am willing to write the reference implementation for the new min and max builtins if there's enough interest. I have, like some others here, used my own One True Large Object. I think the best reason to have One True Large Object is because you can't really compare two implementations of the One True Large Object and expect to get a meaningful result out of it. For the record, my use case had to do with a giant sorted list of tuples and the bisect module. The first element of a tuple was a timestamp, the rest of the tuple isn't worth explaining but I never wanted to compare against it. The "database" had two primary operations, inserting records *after* a timestamp, and finding every record between two timestamps. Let's take a look:
from random import randrange from pprint import pprint from bisect import bisect_left, bisect_right lst = [(randrange(10), randrange(10)) for i in xrange(10)] lst.sort() pprint(lst) [(0, 2), (0, 7), (0, 9), (4, 6), (6, 5), (6, 8), (6, 9), (7, 7), (8, 6), (9, 5)] bisect_left(lst, (6,)) 4 bisect_right(lst, (6,)) 4
Well, that doesn't look too useful does it? In order for bisect_right to have a meaningful return value in this case, I need to build an object such that it compares greater than any (6, *foo).
class MaxObject: ... def __cmp__(self, other): ... return int(not self is other) ... maxobject = MaxObject() bisect_right(lst, (6, maxobject)) 7 lst[4:7] [(6, 5), (6, 8), (6, 9)]
In this particular contrived case, sys.maxint would have worked, but the general case needs One True Large Object. I think One True Large Object should be in builtins and should be called 'max'. Similarly, there are probably use cases for One True Small Object, but none that I've personally ran into. However, since 'min' is already in builtins, might as well do it for symmetry. -bob
I just got a comment from another user suggesting modifying the min/max.__cmp__ so that they are the actual minimum and maximum.
An interesting approach, which makes some sense to me.
Not to me. Random reuses like this would make Python into a mysterious language.
This was my suggestion. I am for this PEP and am willing to write the reference implementation for the new min and max builtins if there's enough interest.
Not from me -- don't waste your time.
I have, like some others here, used my own One True Large Object. I think the best reason to have One True Large Object is because you can't really compare two implementations of the One True Large Object and expect to get a meaningful result out of it.
For the record, my use case had to do with a giant sorted list of tuples and the bisect module. The first element of a tuple was a timestamp, the rest of the tuple isn't worth explaining but I never wanted to compare against it. The "database" had two primary operations, inserting records *after* a timestamp, and finding every record between two timestamps. Let's take a look:
Your example (snipped here) seems to ask for a different kind of data structure, rather than an object larger than everything else. --Guido van Rossum (home page: http://www.python.org/~guido/)
Not to me. Random reuses like this would make Python into a mysterious language.
The reuse isn't random. It would be random if int compared smaller than everything and float compared larger than everything, or even if the strings "little" and "big" did the same. Using min and max to be the smallest and largest objects, as well as being functions that can be called to find the smallest or largest value in a sequence, seems to be intuitive. But lets get past that for a moment. Let us just pretend, for sake of argument, that min and max were to become the smallest and largest values. The only place this would effect pre-existing code is if someone were ordering functions based on '<' or '>' comparisons, IE: they would have to be sorting functions, specifically, min and max. If it is desireable to warn programmers who have been doing this, it would be relatively easy to produce a warning when this happens (to warn those that had been previously sorting functions). Making the warning removable by using a __future__ import for those of us who know about this behavior: from __future__ import minmax And subsequently removing the warnings in later Python versions.
Not from me -- don't waste your time.
Are you against the *idea* of a top and bottom value, its location, or both? - Josiah
Not to me. Random reuses like this would make Python into a mysterious language.
The reuse isn't random. It would be random if int compared smaller than everything and float compared larger than everything, or even if the strings "little" and "big" did the same.
Using min and max to be the smallest and largest objects, as well as being functions that can be called to find the smallest or largest value in a sequence, seems to be intuitive. But lets get past that for a moment.
If that's "intuitive" to you, our ideas about language design must be so different that I have low hopes for something useful coming out of this.
Let us just pretend, for sake of argument, that min and max were to become the smallest and largest values. The only place this would effect pre-existing code is if someone were ordering functions based on '<' or '>' comparisons, IE: they would have to be sorting functions, specifically, min and max.
That is *not* the point at all. The point is that using min() and max() as functions is several orders of magnitude more common than using an infinity value. Most people quickly forget features or details they don't need. So it is likely that many Python users would only be familiar with the function usage, and if they say code that passed max in the meaning of infinity, they'd scratch their head and wonder whether it was used as a callback, or whether there was a local variable max, or whether it was simply a bug.
If it is desireable to warn programmers who have been doing this, it would be relatively easy to produce a warning when this happens (to warn those that had been previously sorting functions). Making the warning removable by using a __future__ import for those of us who know about this behavior: from __future__ import minmax And subsequently removing the warnings in later Python versions.
Not from me -- don't waste your time.
Are you against the *idea* of a top and bottom value, its location, or both?
So far *all* of the names that have been proposed for the concept suck, starting with "Some" and "Any", and now various ways to abuse builtins. I am not against the concept of a universal extreme by itself, but IMO their use is fairly infrequent (except in your mind perhaps, because you've clearly become obsessed with it), so it should not be a builtin, nor disguised as a builtin. How about you write the Python code to implement proper universal extremes, put it in a module, and submit that module for inclusion of the standard library. Then my resistence would be a lot less (until Raymond Hettinger offers to reimplement it in C :-). Hey, universalextremes.py seems a fine name for that module, and UniversalMaximum and UniversalMinimum seem fine names for the two objects in that module. If you find those names too long, you can always write from universalextremes import UnivsersalMaximum as UMax --Guido van Rossum (home page: http://www.python.org/~guido/)
If that's "intuitive" to you, our ideas about language design must be so different that I have low hopes for something useful coming out of this.
I don't know about that; until this thread, I've basically agreed with every direction Python has gone in the 5 years since I started using it, but that is a one-way relationship. Overloading min and max was one option, among quite a few, that would have resulted in min and max being what they do. You seem to hate it, so those of us who desire the functionality will seek other alternatives...
Are you against the *idea* of a top and bottom value, its location, or both?
So far *all* of the names that have been proposed for the concept suck, starting with "Some" and "Any", and now various ways to abuse builtins.
I am not against the concept of a universal extreme by itself, but IMO their use is fairly infrequent (except in your mind perhaps, because you've clearly become obsessed with it), so it should not be a builtin, nor disguised as a builtin.
Just so you know, I'm not obsessed with it. As my wife just pointed out, anything that I believe in, I go "balls-to-the-walls" arguing for regardless of consequences. Sometimes it alienates people; seemingly I have alienated you. I'm sorry if this is the case.
How about you write the Python code to implement proper universal extremes, put it in a module, and submit that module for inclusion of the standard library. Then my resistence would be a lot less (until Raymond Hettinger offers to reimplement it in C :-).
Hey, universalextremes.py seems a fine name for that module, and UniversalMaximum and UniversalMinimum seem fine names for the two objects in that module.
Sounds reasonable. Until my changes are available from CVS, you can catch the latest revision here http://josiahcarlson.no-ip.org/pep-0326.html which includes a sample implementation that could be easily placed into a universalextremes.py. Off list, Andrew Lentvorski has suggested operator.Min/Max as a location, which also sounds reasonable, but I don't know others feel about locating it in operators. - Josiah
I don't know about that; until this thread, I've basically agreed with every direction Python has gone in the 5 years since I started using it, but that is a one-way relationship.
I think this shouldn't be added to the standard library at all, for a few reasons: - All given examples in the PEP are easily rewritable with existent logic (and I disagree that the new method would be easier to understand); - I can't think about any real usage cases for such object which couldn't be easily done without it; - The "One True Large Object" isn't "True Large" at all, since depending on the comparison order, another object might belive itself to be larger than this object. If this was to be implemented as a supported feature, Python should special case it internally to support the "True" in the given name. - It's possible to implement that object with a couple of lines, as you've shown; - Any string is already a maximum object for any int/long comparison (IOW, do "cmp.high = 'My One True Large Object'" and you're done). - Your Dijkstra example is a case of abusement of tuple's sorting behavior. If you want readable code as you suggest, try implementing a custom object with a comparison operator, instead of writting "foo = (a,b,c,d)", and "(a,b,c,d) = foo", and "foo[x][y]" all over the place. -- Gustavo Niemeyer http://niemeyer.net
- All given examples in the PEP are easily rewritable with existent logic (and I disagree that the new method would be easier to understand);
You are free to disagree that two objects, which clearly state that they are either the largest or smallest objects, are not clear. I don't know how to address your concern. In terms of the names for such objects, as well as their locations being good and descriptive, that is still an open issue, and is listed as such in the latest version of the PEP, which is available at http://www.python.org/peps/pep-0326.html
- I can't think about any real usage cases for such object which couldn't be easily done without it;
It is not whether "if we don't have it we can do it easy", it is about "if we have it, we can do it easier". The Queue module, just recently brought up, is one of those examples where having it for interthread communication is invaluable. Sure, everyone could write their own threaded Queue class when needed, but having it there to use is nice. Arguably, there aren't any usage cases where None is necessary. But yet we have None. Which is preferable: _mynone = [] def foo(arg=_mynone): if id(arg) == id(_mynone): #equivalent to None pass def goo(arg=None): if arg is None: pass Again, it is not about "can we do it easy without", it is "can we do it easier with".
- The "One True Large Object" isn't "True Large" at all, since depending on the comparison order, another object might belive itself to be larger than this object. If this was to be implemented as a supported feature, Python should special case it internally to support the "True" in the given name.
I don't know how difficult modifying the comparison function to test whether or not one object in the comparison is the universal max or min, so cannot comment. I'm also don't know if defining a __rcmp__ method would be sufficient.
- It's possible to implement that object with a couple of lines, as you've shown;
I don't see how the length of the implementation has anything to do with how useful it is. I (and others) have provided examples of where they would be useful. If you care to see more, we can discuss this further off-list.
- Any string is already a maximum object for any int/long comparison (IOW, do "cmp.high = 'My One True Large Object'" and you're done).
That also ignores the idea of an absolute minimum. There are two parts of the proposal, a Maximum and a Minimum. The existance of which has already been agreed upon as being useful. Whether they are in the standard library, standard language, or otherwise, and what name they will have, are all currently open issues. A few options are listed in the `Open Issues` portion of the PEP, in not so many words.
- Your Dijkstra example is a case of abusement of tuple's sorting behavior. If you want readable code as you suggest, try implementing a custom object with a comparison operator, instead of writting "foo = (a,b,c,d)", and "(a,b,c,d) = foo", and "foo[x][y]" all over the place.
I don't see how using the features of a data structure already in the standard language is "abuse". Perhaps I should have created my own custom class that held all the relevant information, included a __cmp__ method, added attribute access and set rutines ...OR... maybe it was reasonable that I used a tuple and saved people the pain of looking through twice as much source, just to see a class, that has nothing to do with the PEP. - Josiah
[has this message hit the list? I haven't received it]
- All given examples in the PEP are easily rewritable with existent logic (and I disagree that the new method would be easier to understand);
You are free to disagree that two objects, which clearly state that they are either the largest or smallest objects, are not clear. I don't know how to address your concern.
Both of them.
- I can't think about any real usage cases for such object which couldn't be easily done without it;
It is not whether "if we don't have it we can do it easy", it is about "if we have it, we can do it easier". The Queue module, just recently
Understood, but not agreed.
Arguably, there aren't any usage cases where None is necessary. But yet we have None. [...]
Please, let's not ignore how these usage cases differ in wideness.
- The "One True Large Object" isn't "True Large" at all, since depending on the comparison order, another object might belive itself to be larger than this object. If this was to be implemented as a supported feature, Python should special case it internally to support the "True" in the given name.
I don't know how difficult modifying the comparison function to test whether or not one object in the comparison is the universal max or min,
It's not hard at all. It's just a matter of being worth.
so cannot comment. I'm also don't know if defining a __rcmp__ method would be sufficient.
How would two objects with rcmp react?
- It's possible to implement that object with a couple of lines, as you've shown;
I don't see how the length of the implementation has anything to do with how useful it is.
Let me explain. If you have code that is useful very ocasionally and is implemented with three or four lines of code, the standard library is not the place for it.
I (and others) have provided examples of where they would be useful. If you care to see more, we can discuss this further off-list.
The best place to put useful examples is in the PEP itself. If you have further examples of this, please include there. So far I haven't seen any examples which are worth such implementation, as I've presented.
- Any string is already a maximum object for any int/long comparison (IOW, do "cmp.high = 'My One True Large Object'" and you're done).
That also ignores the idea of an absolute minimum. There are two parts
Neither of these points are isolated. They just sum to each other to make my own opinion.
of the proposal, a Maximum and a Minimum. The existance of which has already been agreed upon as being useful. Whether they are in the
I'd like to be presented with some case where None is not enough, preferably with some other argument besides "that's one or two lines shorter", since having dozens of "shorter features" contradicts the Python oposition to the Perl model.
- Your Dijkstra example is a case of abusement of tuple's sorting behavior. If you want readable code as you suggest, try implementing a custom object with a comparison operator, instead of writting "foo = (a,b,c,d)", and "(a,b,c,d) = foo", and "foo[x][y]" all over the place.
I don't see how using the features of a data structure already in the standard language is "abuse". Perhaps I should have created my own [...]
Sorry. I'll try to explain that with softer words to avoid polluting our discussion. You're trying to introduce a new structure in the language just to turn these usage cases into slightly more readable code (in your opinion) but at the same time you don't want to use the features already in the language which would turn your own example into more readable code and would kill the need for the new presented structures.
custom class that held all the relevant information, included a __cmp__ method, added attribute access and set rutines ...OR... maybe it was reasonable that I used a tuple and saved people the pain of looking through twice as much source, just to see a class, that has nothing to do with the PEP.
Using examples which are better written in a more clear way inside a PEP which is purposing a structure for better readability of code is not a good way to convince people. -- Gustavo Niemeyer http://niemeyer.net
[has this message hit the list? I haven't received it]
[the message hit the list on the afternoon of January 9]
You are free to disagree that two objects, which clearly state that they are either the largest or smallest objects, are not clear. I don't know how to address your concern.
Both of them.
Both of what? Are both the objects not clear? Again, you are free to believe that objects that self-document are not clear. Would a better name or location suffice? I'm open for suggestions.
It is not whether "if we don't have it we can do it easy", it is about "if we have it, we can do it easier". The Queue module, just recently
Understood, but not agreed.
Having the objects can make certain kinds of algorithms easier and clearer to implement. Not having them is what we've had for years. The only question is where is a location we can put them without polluting a random namespace with objects that don't fit. Math is out (Min and Max aren't floating point numbers, which you can read more about in the PEP), cmp.Min/Max are awkward, min.Min and max.Max seem strange, operator.Min/Max seems like a reasonable location, but no one has any feedback on that one yet. Again, I'm open for suggestions.
Arguably, there aren't any usage cases where None is necessary. But yet we have None. [...]
Please, let's not ignore how these usage cases differ in wideness.
Imagine for a moment that None didn't exist. You could create a singleton instance of an object that represents the same idea as None and make its boolean false. It would take <10 lines, and do /everything/ that None does. Take a look at the first few examples in the 'Max Examples' section of the PEP: http://www.python.org/peps/pep-0326.html#max-examples Notice the reduction in code from using only numbers, to using None, to using Max? Notice how each implementation got clearer? That is what the PEP is about, making code clearer.
so cannot comment. I'm also don't know if defining a __rcmp__ method would be sufficient.
How would two objects with rcmp react?
A better question would be, "How would the comparison between two objects behave if the object on the left has __cmp__, and the object on the right has __rcmp__?" Checking the docs, I notice that __rcmp__ is no longer supported, and hasn't been for a few releases, so never mind. An even better question would be, "How would two objects with __cmp__ react?" Checking a few examples, it is whoever is on the left side of the comparison operator.
- It's possible to implement that object with a couple of lines, as you've shown;
I don't see how the length of the implementation has anything to do with how useful it is.
Let me explain. If you have code that is useful very ocasionally and is implemented with three or four lines of code, the standard library is not the place for it.
The entire itertools module is filled with examples where just a few lines of code can save time and effort in re-coding something that should be there in the first place. The PEP argues the case that a minimum and maximum value should be placed somewhere accessable. As stated in the PEP: "Independent implementations of the Min/Max concept by users desiring such functionality are not likely to be compatible, and certainly will produce inconsistent orderings. The following examples seek to show how inconsistent they can be." (read the PEP for the examples)
I (and others) have provided examples of where they would be useful. If you care to see more, we can discuss this further off-list.
The best place to put useful examples is in the PEP itself. If you have further examples of this, please include there. So far I haven't seen any examples which are worth such implementation, as I've presented.
The only thing you've "presented" so far is that you think that the objects are fundamentally useless. On the other hand, no less than 10 people here on python-dev and c.l.py (I didn't even announce it there) have voiced that the objects themselves are useful if given a proper name and location.
of the proposal, a Maximum and a Minimum. The existance of which has already been agreed upon as being useful. Whether they are in the
I'd like to be presented with some case where None is not enough, preferably with some other argument besides "that's one or two lines shorter", since having dozens of "shorter features" contradicts the Python oposition to the Perl model.
Both list comprehensions (Python 2.0) and generator expressions (Python 2.4) have been introduced to reduce code length. Heck, generators themselves reduce the length of code required to create an iterator object. I remember creating iterators before generators existed in the base language, talk about a pain in the ass.
- Your Dijkstra example is a case of abusement of tuple's sorting behavior. If you want readable code as you suggest, try implementing a custom object with a comparison operator, instead of writting "foo = (a,b,c,d)", and "(a,b,c,d) = foo", and "foo[x][y]" all over the place.
I don't see how using the features of a data structure already in the standard language is "abuse". Perhaps I should have created my own [...]
Sorry. I'll try to explain that with softer words to avoid polluting our discussion.
You're trying to introduce a new structure in the language just to turn these usage cases into slightly more readable code (in your opinion) but at the same time you don't want to use the features already in the language which would turn your own example into more readable code and would kill the need for the new presented structures.
The minimum and maximum objects are not structures. They are singleton instances with specific behavior when compared against other objects. No more, no less. Hiding the special cases inside a class, doesn't remove the special cases, it just moves them somewhere else. I could have certainly just given the class, which would have contained __cmp__ functions that looked something like this: class DijkstraSPElement_Max: #initialization def __cmp__(self, other): return cmp(self.distance, other.distance) class DijkstraSPElement_None: #initialization def __cmp__(self, other): if self.distance is None: if other.distance is None: return 0 return 1 elif other.distance is None: return -1 return cmp(self.distance, other.distance) Hey, it makes a good case for the PEP; maybe I'll stick it in there if I have time this afternoon. Thank you for the sugestion.
custom class that held all the relevant information, included a __cmp__ method, added attribute access and set rutines ...OR... maybe it was reasonable that I used a tuple and saved people the pain of looking through twice as much source, just to see a class, that has nothing to do with the PEP.
Using examples which are better written in a more clear way inside a PEP which is purposing a structure for better readability of code is not a good way to convince people.
Are you saying that I should place comments describing what the algorithm is doing inside the examples? Perhaps. Thank you for the ideas and suggestions, - Josiah
[...]
The only question is where is a location we can put them without polluting a random namespace with objects that don't fit. Math is out (Min and Max aren't floating point numbers, which you can read more about in the PEP), cmp.Min/Max are awkward, min.Min and max.Max seem strange, operator.Min/Max seems like a reasonable location, but no one has any feedback on that one yet. Again, I'm open for suggestions.
My suggestion is to not introduce these objects at all, and if they're going to be introduced, there should be internal support for them in the interpreter, or they're meaningless. Every object with a custom cmp method would have to take care not to be greater than your objects.
Arguably, there aren't any usage cases where None is necessary. But yet we have None. [...]
Please, let's not ignore how these usage cases differ in wideness.
Imagine for a moment that None didn't exist. You could create a singleton instance of an object that represents the same idea as None and make its boolean false. It would take <10 lines, and do /everything/ that None does. [...]
Please, let's not ignore how these usage cases differ in wideness.
Take a look at the first few examples in the 'Max Examples' section of the PEP: http://www.python.org/peps/pep-0326.html#max-examples Notice the reduction in code from using only numbers, to using None, to using Max? Notice how each implementation got clearer? That is what the PEP is about, making code clearer.
Comments about the "Max Examples": - If the objects in the sequence implement their own cmp operator, you can't be sure your example will work. That turns these structures (call them as you want) into something useless. - "Max" is a possible return from this function. It means the code using your "findmin_Max" will have to "if foo == Max" somewhere, so it kills your argument of less code as well. [...]
An even better question would be, "How would two objects with __cmp__ react?" Checking a few examples, it is whoever is on the left side of the comparison operator.
Exactly. That's the point. Your "Top" value is not really "Top", unless every object with custom comparison methods take care about it. [...]
The entire itertools module is filled with examples where just a few lines of code can save time and effort in re-coding something that should be there in the first place. The PEP argues the case that a minimum and maximum value should be placed somewhere accessable.
Understood.
As stated in the PEP: "Independent implementations of the Min/Max concept by users desiring such functionality are not likely to be compatible, and certainly will produce inconsistent orderings. The following examples seek to show how inconsistent they can be." (read the PEP for the examples)
Independent implementations are not compatible for the same reason why your implementation is not compatible with the rest of the world. IOW, an indepent implementation would not respect your Max, just like any object with a custom comparison may not respect it. [...]
The only thing you've "presented" so far is that you think that the objects are fundamentally useless. On the other hand, no less than 10
Sorry, but you're blind. Review my messages.
people here on python-dev and c.l.py (I didn't even announce it there) have voiced that the objects themselves are useful if given a proper name and location.
The fact that other people agree with your suggestion doesn't affect my own opinion. [...]
You're trying to introduce a new structure in the language just to turn these usage cases into slightly more readable code (in your opinion) but at the same time you don't want to use the features already in the language which would turn your own example into more readable code and would kill the need for the new presented structures.
The minimum and maximum objects are not structures. They are singleton instances with specific behavior when compared against other objects. No more, no less.
Heh.. pointless.
Hiding the special cases inside a class, doesn't remove the special cases, it just moves them somewhere else. I could have certainly just given the class, which would have contained __cmp__ functions that looked something like this:
class DijkstraSPElement_Max: #initialization def __cmp__(self, other): return cmp(self.distance, other.distance)
class DijkstraSPElement_None: #initialization def __cmp__(self, other): if self.distance is None: if other.distance is None: return 0 return 1 elif other.distance is None: return -1 return cmp(self.distance, other.distance)
Hey, it makes a good case for the PEP; maybe I'll stick it in there if I have time this afternoon. Thank you for the sugestion.
Ouch! It's getting worse. :-) Put *that* example in your PEP, please: class Node: def __init__(self, node, parent=None, distance=None, visited=False): self.node = node self.parent = parent self.distance = distance self.visited = visited def __cmp__(self, other): pair = self.distance, other.distance if None in pair: return cmp(*pair)*-1 return cmp(*pair) def DijkstraSP_table(graph, S, T): table = {} for node in graph.iterkeys(): table[node] = Node(node) table[S] = Node(S, distance=0) cur = min(table.values()) while (not cur.visited) and cur.distance != None: node.visited = True for cdist, child in graph[node]: ndist = node.distance+cdist childnode = table[child] if not childnode.visited and \ (childnode.distance is None or ndist < childnode.distance): childnode.distance = ndist cur = min(table.values()) if not table[T].visited: return None cur = T path = [T] while table[cur].parent is not None: path.append(table[cur].parent) cur = path[-1] path.reverse() return path [...]
Using examples which are better written in a more clear way inside a PEP which is purposing a structure for better readability of code is not a good way to convince people.
Are you saying that I should place comments describing what the algorithm is doing inside the examples? Perhaps.
No, I meant you should do something towards what I've presented above. -- Gustavo Niemeyer http://niemeyer.net
[...]
My suggestion is to not introduce these objects at all, and if they're going to be introduced, there should be internal support for them in the interpreter, or they're meaningless. Every object with a custom cmp method would have to take care not to be greater than your objects.
Interpretation: You are -1 on the PEP in general. If it does get introduced, then you are +1 on there being a special case in the interpreter for when Min or Max are in the comparison. If given the proper values for PyMinObject and PyMaxObject (quite the large 'if given'), it is an 5 line modification to PyObject_Compare in object.c: int PyObject_Compare(PyObject *v, PyObject *w) { PyTypeObject *vtp; int result; if (v == NULL || w == NULL) { PyErr_BadInternalCall(); return -1; } if (v == w) return 0; vtp = v->ob_type;
if (v == PyMinObject || w == PyMaxObject) return -1; else if (v == PyMaxObject || w == PyMinObject) return 1; else if (Py_EnterRecursiveCall(" in cmp")) return -1; result = do_cmp(v, w); Py_LeaveRecursiveCall(); return result < 0 ? -1 : result; }
Unfortunately the above seems to imply that Min and Max would need to be builtins (I may be wrong here, please correct me if I am), and new builtins have been frowned upon by most everyone since the beginning. [...]
Take a look at the first few examples in the 'Max Examples' section of the PEP: http://www.python.org/peps/pep-0326.html#max-examples Notice the reduction in code from using only numbers, to using None, to using Max? Notice how each implementation got clearer? That is what the PEP is about, making code clearer.
Comments about the "Max Examples":
- If the objects in the sequence implement their own cmp operator, you can't be sure your example will work. That turns these structures (call them as you want) into something useless.
Those who want to use Max and/or Min, and want to implement their own cmp operator - which uses non-standard behavior when comparing against Max and/or Min - may have to deal with special cases involving Max and/or Min. This makes sense because it is the same deal with any value or object you want to result in non-standard behavior. If people want a special case, then they must write the special case.
- "Max" is a possible return from this function. It means the code using your "findmin_Max" will have to "if foo == Max" somewhere, so it kills your argument of less code as well.
No, it doesn't. min(a, Max) will always return a. I should have included a test for empty sequences as an argument in order to differentiate between empty sequences and sequences that have (0, None, Max) as their actual minimum values (in the related code snippets). This results in the simplification of the (0, None) examples into one, but introduces an index variable and sequence lookups for the general case: def findmin_General(seq): if not len(seq): raise TypeError("Sequence is empty") cur = seq[0] for i in xrange(1, len(seq)): cur = min(seq[i], cur) return cur def findmin_Max(seq): if not len(seq): raise TypeError("Sequence is empty") cur = Max for obj in seq: cur = min(obj, cur) return cur Now they both have the same number of lines, but I find the second one a bit clearer due its lack of sequence indexing.
[...]
An even better question would be, "How would two objects with __cmp__ react?" Checking a few examples, it is whoever is on the left side of the comparison operator.
Exactly. That's the point. Your "Top" value is not really "Top", unless every object with custom comparison methods take care about it.
Certainly anyone who wants to use Max/Min may have to take care to use it properly. How is this any different from the way we program with any other special values? Just to point things out, when comparing two standard python data types (int, float, None, dict, list, tuple, str), cmp calls the left data type's cmp operator. When comparing an object that is not a standard python data type to anything else, cmp calls the leftmost non-standard object's existant cmp operator. The described behavior looks to be consistant with current CVS for object.c, in which the various cmp functions are defined. Perhaps this behavior should be documented in the customization documentation. [...]
As stated in the PEP: "Independent implementations of the Min/Max concept by users desiring such functionality are not likely to be compatible, and certainly will produce inconsistent orderings. The following examples seek to show how inconsistent they can be." (read the PEP for the examples)
Independent implementations are not compatible for the same reason why your implementation is not compatible with the rest of the world. IOW, an indepent implementation would not respect your Max, just like any object with a custom comparison may not respect it.
One of 3 cases would occur: 1. If Max and Min are in the standard distribution, then the people who use it, would write code that is compatible with it (ok). 2. Those that have no need for such extreme values will never write code that /could/ be incompatible with it (ok). 3. Those that don't know about Max/Min, or write their own implementations that overlap with included Python functionality, would not be supported (ok) (I hope the reasons for this are obvious, if they are not, I will clarify). In any case, the PEP describes the behavior and argues about the creation of the "One True Implementation of the One True Maximum Value and One True Minimum Value", and including it in the standard Python distribution in a reasonable location, with a name that is intuitive.
[...]
The only thing you've "presented" so far is that you think that the objects are fundamentally useless. On the other hand, no less than 10
Sorry, but you're blind. Review my messages.
My mistake, you've also said that the examples were not good enough, have recently given modifications to the examples that may make them better, and have stated that if Max/Min were to be included, they should have interpreter special cases.
The fact that other people agree with your suggestion doesn't affect my own opinion.
Indeed it doesn't. I was attempting to point out that though you think (in general) that the inclusion of Max and Min values in Python are useless, others (beyond myself) find that they do have uses, and would actually use them. See this thread (ugly url ahead): http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&safe=off&threadm=mailman.667.1074799564.12720.python-list%40python.org&rnum=1&prev=/groups%3Fhl%3Den%26lr%3D%26ie%3DISO-8859-1%26safe%3Doff%26q%3D326%26btnG%3DGoogle%2BSearch%26meta%3Dgroup%253Dcomp.lang.python.* [...]
Hey, it makes a good case for the PEP; maybe I'll stick it in there if I have time this afternoon. Thank you for the sugestion.
Ouch! It's getting worse. :-)
Put *that* example in your PEP, please: [...]
I like your optimization of comparisons to None, but the real difference between using None and Max in the node elements are the following: class DijkstraSPElement_Max: #initialization def __cmp__(self, other): return cmp(self.distance, other.distance) class DijkstraSPElement_None: #initialization def __cmp__(self, other): pair = self.distance, other.distance if None in pair: return cmp(*pair)*-1 return cmp(*pair) I'll modify the Dijkstra example to include the objects. Really, they show that for structures that have a comparison key and some additional meta-information attached, Max and Min still win (if only because they don't create and search a two-tuple). Out of curiosity, why did you use cmp(*pair)*-1 and not -cmp(*pair)? - Josiah
On Mon, Jan 26, 2004 at 04:47:43PM -0800, Josiah Carlson wrote:
This results in the simplification of the (0, None) examples into one, but introduces an index variable and sequence lookups for the general case:
def findmin_General(seq): if not len(seq): raise TypeError("Sequence is empty") cur = seq[0] for i in xrange(1, len(seq)): cur = min(seq[i], cur) return cur
def findmin_Max(seq): if not len(seq): raise TypeError("Sequence is empty") cur = Max for obj in seq: cur = min(obj, cur) return cur
Now they both have the same number of lines, but I find the second one a bit clearer due its lack of sequence indexing.
I'd avoid the sequence indexing by writing the following: def findmin_Iter(seq): seq = iter(seq) cur = seq.next() for i in seq: cur = min(i, cur) return cur This code will raise StopIteration, not TypeError, if the sequence is empty. Jeff
[...]
My suggestion is to not introduce these objects at all, and if they're going to be introduced, there should be internal support for them in the interpreter, or they're meaningless. Every object with a custom cmp method would have to take care not to be greater than your objects.
Interpretation: You are -1 on the PEP in general. If it does get introduced, then you are +1 on there being a special case in the interpreter for when Min or Max are in the comparison.
That's it.
If given the proper values for PyMinObject and PyMaxObject (quite the large 'if given'), it is an 5 line modification to PyObject_Compare in object.c: [...]
I know it's easy, I just don't think it's worth. Anyway, you've explained it in the above sentence.
Comments about the "Max Examples":
- If the objects in the sequence implement their own cmp operator, you can't be sure your example will work. That turns these structures (call them as you want) into something useless.
Those who want to use Max and/or Min, and want to implement their own cmp operator - which uses non-standard behavior when comparing against Max and/or Min - may have to deal with special cases involving Max and/or Min.
This makes sense because it is the same deal with any value or object you want to result in non-standard behavior. If people want a special case, then they must write the special case.
What I mean is that I'd have to review every generic class I ever wrote which is supposed to be compatible with the standard library to check if they're compatible with Min/Max. I don't like this approach, but that's just my opinion.
- "Max" is a possible return from this function. It means the code using your "findmin_Max" will have to "if foo == Max" somewhere, so it kills your argument of less code as well.
No, it doesn't. min(a, Max) will always return a.
Interesting, you say that it doesn't, but...
I should have included a test for empty sequences as an argument in order to differentiate between empty sequences and sequences that have (0, None, Max) as their actual minimum values (in the related code snippets).
This results in the simplification of the (0, None) examples into one, but introduces an index variable and sequence lookups for the general case: [...] Now they both have the same number of lines, but I find the second one a bit clearer due its lack of sequence indexing.
... you actually agree. :-)
[...]
An even better question would be, "How would two objects with __cmp__ react?" Checking a few examples, it is whoever is on the left side of the comparison operator.
Exactly. That's the point. Your "Top" value is not really "Top", unless every object with custom comparison methods take care about it.
Certainly anyone who wants to use Max/Min may have to take care to use it properly. How is this any different from the way we program with any other special values?
I don't want to use them, but I'd have to be careful so that other people might use them. Again, I don't like this approach. [...]
One of 3 cases would occur: 1. If Max and Min are in the standard distribution, then the people who use it, would write code that is compatible with it (ok).
Wrong. People which use Max/Min might be unaware that they must take care when building __cmp__ so that their classes are compatible with Min/Max.
2. Those that have no need for such extreme values will never write code that /could/ be incompatible with it (ok).
Wrong. Those that have no need for such extreme values will have even more chances to do that.
3. Those that don't know about Max/Min, or write their own implementations that overlap with included Python functionality, would not be supported (ok) (I hope the reasons for this are obvious, if they are not, I will clarify).
Same case.
In any case, the PEP describes the behavior and argues about the creation of the "One True Implementation of the One True Maximum Value and One True Minimum Value", and including it in the standard Python distribution in a reasonable location, with a name that is intuitive.
Ok, and I thank you for you patience defending the matter. Opinions diverge, and the divergences should be explained. Once everyone is aware about the issues, someone will have to decide if it is implemented or not (I'm glad it's not my job :-).
I like your optimization of comparisons to None, but the real difference between using None and Max in the node elements are the following: [...]
Oops.. the real difference is exposed with any alternative implementation. Introducing code which "emulates" your own scheme is pretty tendentious.
Out of curiosity, why did you use cmp(*pair)*-1 and not -cmp(*pair)?
Because that's the first implementation that came into my mind. -- Gustavo Niemeyer http://niemeyer.net
Josiah Carlson wrote:
Using min and max to be the smallest and largest objects, as well as being functions that can be called to find the smallest or largest value in a sequence, seems to be intuitive.
Only in the sense that "min" and "max" are intuitive *names* for these objects, to English speakers. On the other hand, I wouldn't mind having "min()" and "max()" (currently TypeErrors) return the minimal and maximal objects. Cheers, Evan @ 4-am
participants (6)
-
Bob Ippolito -
Evan Simpson -
Guido van Rossum -
Gustavo Niemeyer -
Jeff Epler -
Josiah Carlson