Re: [Python-Dev] Not-a-Number (was PyObject_RichCompareBool identity shortcut)
On Sat, Apr 30, 2011 at 3:11 AM, Guido van Rossum gu...@python.org wrote: Decimal, for that reason, has a context that lets one specify different behaviors when a NaN is produced. Would it make sense to add a float context that also lets one specify what should happen? That could include returning Inf for 1.0/0.0 (for experts), or raising exceptions when NaNs are produced (for the numerically naive like myself). I could see a downside too, e.g. the correctness of code that passingly uses floats might be affected by the context settings. There's also the question of whether the float context should affect int operations; floats vs. ints is another can of worms since (in Python 3) we attempt to tie them together through 1/2 == 0.5, but ints have a much larger range than floats. Given that we delegate most float() behaviour to the underlying CPU and C libraries (and then the math module tries to cope with any cross-platform discrepancies), introducing context handling isn't easy, and would likely harm the current speed advantage that floats hold over the decimal module. We decided that losing the speed advantage of native integers was worthwhile in order to better unify the semantics of int and long for Py3k, but both the speed differential and the semantic gap between float() and decimal.Decimal() are significantly larger. However, I did find Terry's suggestion of using the warnings module to report some of the floating point corner cases that currently silently produce unexpected results to be an interesting one. If those operations issued a FloatWarning, then users could either silence them or turn them into errors as desired. Cheers, Nick. -- Nick Coghlan | ncogh...@gmail.com | Brisbane, Australia ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Not-a-Number (was PyObject_RichCompareBool identity shortcut)
On 5/1/2011 7:27 AM, Nick Coghlan wrote: However, I did find Terry's suggestion of using the warnings module to report some of the floating point corner cases that currently silently produce unexpected results to be an interesting one. If those operations issued a FloatWarning, then users could either silence them or turn them into errors as desired. I would like to take credit for that, but I was actually seconding Alexander's insight and idea. I may have added the specific name after looking at the currently list and seeing UnicodeWarning and BytesWarning, so why not a FloatWarning. I did read the warnings doc more carefully to verify that it would really put the user in control, which was apparently the intent of the committee. I am not sure whether FloatWarnings should ignored or printed by default. Ignored would, I guess, match current behavior, unless something else is changed as part of a more extensive overhaul. -f and -ff are available to turn ignored FloatWarning into print or raise exception, as with BytesWarning. I suspect that these would get at lease as much usage as -b and -bb. So I see 4 questions: 1. Add FloatWarning? 2. If yes, default disposition? 3. Add command line options? 4. Use the addition of FloatWarning as an opportunity to change other defaults, given that user will have more options? -- Terry Jan Reedy ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Not-a-Number (was PyObject_RichCompareBool identity shortcut)
Terry Reedy writes: Python treats it as if it were a number: As I said, so did the committee, and that was its mistake that we are more or less stuck with. The committee didn't really have a choice. You could ask that they call NaNs something else, but some bit pattern is going to appear in the result register after each computation, and further operations may (try to) use that bit pattern. Seems reasonable to me to apply duck- typing and call those patterns numbers for the purpose of IEEE 754, and to define them in such a way that operating on them produces a non-NaN only when *all* numbers (including infinity) produce the same non-NaN. The alternative is to raise an exception whenever a NaN would be generated (but something is still going to appear in the register; I don't know any number that should be put there, do you?) That is excessively punishing to Python users and programmers, though, since Python handles exceptions by terminating the computation. (Kahan points out that signaling NaNs are essentially never used for this reason.) Other aspects of NaN behavior may be a mistake. But it's not clear to me, even after all the discussion in this thread. ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Not-a-Number (was PyObject_RichCompareBool identity shortcut)
On Fri, Apr 29, 2011 at 12:10 AM, Stephen J. Turnbull step...@xemacs.org wrote: Other aspects of NaN behavior may be a mistake. But it's not clear to me, even after all the discussion in this thread. ISTM that the current behavior of NaN (never mind the identity issue) helps numeric experts write better code. For naive users, however, it causes puzzlement if they ever run into it. Decimal, for that reason, has a context that lets one specify different behaviors when a NaN is produced. Would it make sense to add a float context that also lets one specify what should happen? That could include returning Inf for 1.0/0.0 (for experts), or raising exceptions when NaNs are produced (for the numerically naive like myself). I could see a downside too, e.g. the correctness of code that passingly uses floats might be affected by the context settings. There's also the question of whether the float context should affect int operations; floats vs. ints is another can of worms since (in Python 3) we attempt to tie them together through 1/2 == 0.5, but ints have a much larger range than floats. -- --Guido van Rossum (python.org/~guido) ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Not-a-Number (was PyObject_RichCompareBool identity shortcut)
On Fri, Apr 29, 2011 at 1:11 PM, Guido van Rossum gu...@python.org wrote: … Would it make sense to add a float context that also lets one specify what should happen? That could include returning Inf for 1.0/0.0 (for experts), or raising exceptions when NaNs are produced (for the numerically naive like myself). ISTM, this is approaching py4k territory. Adding contexts will not solve backward compatibility problem unless you introduce a quirks contexts that would preserve current warts and make it default. For what it's worth, I think the next major version of Python should use decimal as its main floating point type an leave binary floats to numerical experts. ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
[Python-Dev] Not-a-Number (was PyObject_RichCompareBool identity shortcut)
Related to the discussion on Not a Number can I point out a few things that have not be explicitly addressed so far. The IEEE standard is about hardware and bit patterns, rather than types and values so may not be entirely appropriate for high-level language like Python. NaN is *not* a number (the clue is in the name). Python treats it as if it were a number: import numbers isinstance(nan, numbers.Number) True Can be read as 'Not a Number' is a Number ;) NaN does not have to be a float or a Decimal. Perhaps it should have its own class. The default comparisons will then work as expected for collections. (No doubt, making NaN a new class will cause a whole new set of problems) As pointed out by Meyer: NaN == NaN is False is no more logical than NaN != NaN is False Although both NaN == NaN and NaN != NaN could arguably be a maybe value, the all important reflexivity (x == x is True) is effectively part of the language. All collections rely on it and Python wouldn't be much use without dicts, tuples and lists. To summarise: NaN is required so that floating point operations on arrays and lists do not raise unwanted exceptions. NaN is Not a Number (therefore should be neither a float nor a Decimal). Making it a new class would solve some of the problems discussed, but would create new problems instead. Correct behaviour of collections is more important than IEEE conformance of NaN comparisons. Mark. ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Not-a-Number (was PyObject_RichCompareBool identity shortcut)
Mark Shannon wrote: NaN does not have to be a float or a Decimal. Perhaps it should have its own class. Perhaps, but that wouldn't solve anything on its own. If this new class compares reflexively, then it still violates IEE754. Conversely, existing NaNs could be made to compare reflexively without making them a new class. -- Greg ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Not-a-Number (was PyObject_RichCompareBool identity shortcut)
On Thu, Apr 28, 2011 at 7:17 PM, Greg Ewing greg.ew...@canterbury.ac.nz wrote: Mark Shannon wrote: NaN does not have to be a float or a Decimal. Perhaps it should have its own class. Perhaps, but that wouldn't solve anything on its own. If this new class compares reflexively, then it still violates IEE754. Conversely, existing NaNs could be made to compare reflexively without making them a new class. And 3rd party NaNs can still do whatever the heck they want :) Cheers, Nick. -- Nick Coghlan | ncogh...@gmail.com | Brisbane, Australia ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Not-a-Number (was PyObject_RichCompareBool identity shortcut)
Mark Shannon wrote: Related to the discussion on Not a Number can I point out a few things that have not be explicitly addressed so far. The IEEE standard is about hardware and bit patterns, rather than types and values so may not be entirely appropriate for high-level language like Python. I would argue that the implementation of NANs is irrelevant. If NANs are useful in hardware floats -- and I think they are -- then they're just as equally useful as objects, or as strings in languages like REXX or Hypertalk where all data is stored as strings, or as quantum wave functions in some future quantum computer. NaN is *not* a number (the clue is in the name). Python treats it as if it were a number: import numbers isinstance(nan, numbers.Number) True Can be read as 'Not a Number' is a Number ;) I see your wink, but what do you make of these? class NotAnObject(object): pass nao = NotAnObject() assert isinstance(nao, object) class NotAType(object): pass assert type(NotAType) is type NaN does not have to be a float or a Decimal. Perhaps it should have its own class. Others have already pointed out this won't make any difference. Fundamentally, the problem is that some containers bypass equality tests for identity tests. There may be good reasons for that shortcut, but it leads to problems with *any* object that does not define equality to be reflexive, not just NANs. class Null: ... def __eq__(self, other): ... return False ... null = Null() null == null False [null] == [null] True The default comparisons will then work as expected for collections. (No doubt, making NaN a new class will cause a whole new set of problems) As pointed out by Meyer: NaN == NaN is False is no more logical than NaN != NaN is False I don't agree with this argument. I think Meyer is completely mistaken there. The question of NAN equality is that of a vacuous truth, quite similar to the Present King of France: http://en.wikipedia.org/wiki/Present_King_of_France Meyer would have us accept that: The present King of France is a talking horse and The present King of France is not a talking horse are equally (pun not intended) valid. No, no they're not. I don't know much about who the King of France would be if France had a king, but I do know that he wouldn't be a talking horse. Once you accept that NANs aren't equal to anything else, it becomes a matter of *practicality beats purity* to accept that they can't be equal to themselves either. A NAN doesn't represent a specific thing. It's a signal that your calculation has generated an indefinite, undefined, undetermined value. NANs aren't equal to anything. The fact that a NAN happens to have an existence as a bit-pattern at some location, or as a distinct object, is an implementation detail that is irrelevant. If you just happen by some fluke to compare a NAN to itself, that shouldn't change the result of the comparison: The present King of France is the current male sovereign who rules France is still false, even if you happen to write it like this: The present King of France is the present King of France This might seem surprising to those who are used to reflexivity. Oh well. Just because reflexivity holds for actual things, doesn't mean it holds for, er, things that aren't things. NANs are things that aren't things. Although both NaN == NaN and NaN != NaN could arguably be a maybe value, the all important reflexivity (x == x is True) is effectively part of the language. All collections rely on it and Python wouldn't be much use without dicts, tuples and lists. Perhaps they shouldn't rely on it. Identity tests are an implementation detail. But in any case, reflexivity is *not* a guarantee of Python. With rich comparisons, you can define __eq__ to do anything you like. -- Steven ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Not-a-Number (was PyObject_RichCompareBool identity shortcut)
Steven D'Aprano wrote: Mark Shannon wrote: Related to the discussion on Not a Number can I point out a few things that have not be explicitly addressed so far. The IEEE standard is about hardware and bit patterns, rather than types and values so may not be entirely appropriate for high-level language like Python. I would argue that the implementation of NANs is irrelevant. If NANs are useful in hardware floats -- and I think they are -- then they're just as equally useful as objects, or as strings in languages like REXX or Hypertalk where all data is stored as strings, or as quantum wave functions in some future quantum computer. So, Indeed, so its OK if type(NaN) != type(0.0) ? NaN is *not* a number (the clue is in the name). Python treats it as if it were a number: import numbers isinstance(nan, numbers.Number) True Can be read as 'Not a Number' is a Number ;) I see your wink, but what do you make of these? class NotAnObject(object): pass nao = NotAnObject() assert isinstance(nao, object) Trying to make something not an object in a language where everything is an object is bound to be problematic. class NotAType(object): pass assert type(NotAType) is type NaN does not have to be a float or a Decimal. Perhaps it should have its own class. Others have already pointed out this won't make any difference. Fundamentally, the problem is that some containers bypass equality tests for identity tests. There may be good reasons for that shortcut, but it leads to problems with *any* object that does not define equality to be reflexive, not just NANs. class Null: ... def __eq__(self, other): ... return False ... null = Null() null == null False [null] == [null] True Just because you can do that, doesn't mean you should. Equality should be reflexive, without that fundamental assumption many non-numeric algorithms fall apart. The default comparisons will then work as expected for collections. (No doubt, making NaN a new class will cause a whole new set of problems) As pointed out by Meyer: NaN == NaN is False is no more logical than NaN != NaN is False I don't agree with this argument. I think Meyer is completely mistaken there. The question of NAN equality is that of a vacuous truth, quite similar to the Present King of France: http://en.wikipedia.org/wiki/Present_King_of_France Meyer would have us accept that: The present King of France is a talking horse and The present King of France is not a talking horse are equally (pun not intended) valid. No, no they're not. I don't know much about who the King of France would be if France had a king, but I do know that he wouldn't be a talking horse. Once you accept that NANs aren't equal to anything else, it becomes a matter of *practicality beats purity* to accept that they can't be equal Not breaking a whole bunch of collections and algorithms has a certain practical appeal as well ;) to themselves either. A NAN doesn't represent a specific thing. It's a signal that your calculation has generated an indefinite, undefined, undetermined value. NANs aren't equal to anything. The fact that a NAN happens to have an existence as a bit-pattern at some location, or as a distinct object, is an implementation detail that is irrelevant. If you just happen by some fluke to compare a NAN to itself, that shouldn't change the result of the comparison: The present King of France is the current male sovereign who rules France is still false, even if you happen to write it like this: The present King of France is the present King of France The problem with this argument is the present King of France does not exist, whereas NaN (as a Python object) does exist. The present King of France argument only applies to non-existent things. Python objects do exist (as much as any computer language entity exists). So the expression The present King of France either raises an exception (non-existence) or evaluates to an object (existence). In this case the present King of France doesn't exist and should raise a FifthRepublicException :) inf / inf does not raise an exception, but evaluates to NaN, so NaN exists. For objects (that exist): (x is x) is True. The present President of France is the present President of France, regardless of who he or she may be. This might seem surprising to those who are used to reflexivity. Oh well. Just because reflexivity holds for actual things, doesn't mean it holds for, er, things that aren't things. NANs are things that aren't things. A NaN is thing that *is* a thing; it exists: object.__repr__(float('nan')) Of course if inf - inf, inf/inf raised exceptions, then NaN wouldn't exist (as a Python object) and the problem would just go away :) After all 0.0/0.0 already raises an exception, but the IEEE defines 0.0/0.0 as NaN. Although both NaN == NaN and NaN != NaN could arguably be a maybe
Re: [Python-Dev] Not-a-Number (was PyObject_RichCompareBool identity shortcut)
On 28/04/2011 15:58, Steven D'Aprano wrote: Fundamentally, the problem is that some containers bypass equality tests for identity tests. There may be good reasons for that shortcut, but it leads to problems with *any* object that does not define equality to be reflexive, not just NANs. I say you have that backwards. It is a legitimate shortcut, and any object that (perversely) doesn't define equality to be reflexive leads (unsurprisingly) to problems with it (and with *anything else* that - very reasonably - assumes that identity implies equality). Mark Shannon wrote: Although both NaN == NaN and NaN != NaN could arguably be a maybe value, the all important reflexivity (x == x is True) is effectively part of the language. All collections rely on it and Python wouldn't be much use without dicts, tuples and lists. Perhaps they shouldn't rely on it. Identity tests are an implementation detail. But in any case, reflexivity is *not* a guarantee of Python. With rich comparisons, you can define __eq__ to do anything you like. And you can write True = False (at least in older versions of Python you could). No language stops you from writing stupid programs. In fact I would propose that the language should DEFINE the meaning of == to be True if its operands are identical, and only if they are not would it use the comparison operators, thus enforcing reflexivity. (Nothing stops you from writing your own non-reflexive __eq__ and calling it explicitly, and I think it is right that you should have to work harder and be more explicit if you want that behaviour.) Please, please, can we have a bit of common sense and perspective here. No-one (not even a mathematician) except someone from Wonderland would seriously want an object not equal to itself. Regards Rob Cliffe ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Not-a-Number (was PyObject_RichCompareBool identity shortcut)
Mark Shannon wrote: Steven D'Aprano wrote: Mark Shannon wrote: Related to the discussion on Not a Number can I point out a few things that have not be explicitly addressed so far. The IEEE standard is about hardware and bit patterns, rather than types and values so may not be entirely appropriate for high-level language like Python. I would argue that the implementation of NANs is irrelevant. If NANs are useful in hardware floats -- and I think they are -- then they're just as equally useful as objects, or as strings in languages like REXX or Hypertalk where all data is stored as strings, or as quantum wave functions in some future quantum computer. So, Indeed, so its OK if type(NaN) != type(0.0) ? Sure. But that just adds complexity without actually resolving anything. Fundamentally, the problem is that some containers bypass equality tests for identity tests. There may be good reasons for that shortcut, but it leads to problems with *any* object that does not define equality to be reflexive, not just NANs. [...] Just because you can do that, doesn't mean you should. Equality should be reflexive, without that fundamental assumption many non-numeric algorithms fall apart. So what? If I have a need for non-reflexivity in my application, why should I care that some other algorithm, which I'm not using, will fail? Python supports non-reflexivity. If I take advantage of that feature, I can't guarantee that *other objects* will be smart enough to understand this. This is no different from any other property of my objects. The default comparisons will then work as expected for collections. (No doubt, making NaN a new class will cause a whole new set of problems) As pointed out by Meyer: NaN == NaN is False is no more logical than NaN != NaN is False I don't agree with this argument. I think Meyer is completely mistaken there. The question of NAN equality is that of a vacuous truth, quite similar to the Present King of France: http://en.wikipedia.org/wiki/Present_King_of_France [...] The problem with this argument is the present King of France does not exist, whereas NaN (as a Python object) does exist. NANs (as Python objects) exist in the same way as the present King of France exists as words. It's an implementation detail: we can't talk about the non-existent present King of France without using words, and we can't do calculations on non-existent/indeterminate values in Python without objects. Words can represent things that don't exist, and so can bit-patterns or objects or any other symbol. We must be careful to avoid mistaking the symbol (the NAN bit-pattern or object) for the thing (the result of whatever calculation generated that NAN). The idea of equality we care about is equality of what the symbol represents, not the symbol itself. The meaning of spam and eggs should not differ according to the typeface we write the words in. Likewise the number 42 should not differ according to how the int object is laid out, or whether the bit-pattern is little-endian or big-endian. What matters is the thing itself, 42, not the symbol: it will still be 42 even if we decided to write it in Roman numerals or base 13. Likewise, what matters is the non-thingness of NANs, not the fact that the symbol for them has an existence as an object or a bit-pattern. -- Steven ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Not-a-Number (was PyObject_RichCompareBool identity shortcut)
On 4/28/2011 4:40 AM, Mark Shannon wrote: NaN is *not* a number (the clue is in the name). The problem is that the committee itself did not believe or stay consistent with that. In the text of the draft, they apparently refer to Nan as an indefinite, unspecified *number*. Sort of like a random variable with a uniform pseudo* distribution over the reals (* 0 everywhere with integral 1). Or a quantum particle present but smeared out over all space. And that apparently is their rationale for Nan != NaN: an unspecified number will equal another unspecified number with probability 0. The rationale for bool(NaN)==True is that an unspecified *number* will be 0 with probability 0. If Nan truly indicated an *absence* (like 0 and '') then bool(NaN) should be False, I think the committee goofed -- badly. Statisticians used missing value indicators long before the committee existed. They has no problem thinking that the indicator, as an object, equaled itself. So one could write (and I often did through the 1980s) the equivalent of for i,x in enumerate(datavec): if x == XMIS: # singleton missing value indicator for BMDP datavec[i] = default (Statistics packages have no concept of identity different from equality.) If statisticians had made XMIS != XMIS, that obvious code would not have worked, as it will not today for Python. Instead, the special case circumlocution of if isXMIS(x): would have been required, adding one more unnecessary function to the list of builtins. NaN is, in its domain, the equivalent of None (== Not a Value), which also serves an an alternative to immediately raising an exception. But like XMIS, None==None. Also, bool(None) is corretly for something that indicates absence. Python treats it as if it were a number: As I said, so did the committee, and that was its mistake that we are more or less stuck with. NaN does not have to be a float or a Decimal. Perhaps it should have its own class. Like None As pointed out by Meyer: NaN == NaN is False is no more logical than NaN != NaN is False This is wrong if False/True are interpreted as probabilities 0 and 1. To summarise: NaN is required so that floating point operations on arrays and lists do not raise unwanted exceptions. Like None. NaN is Not a Number (therefore should be neither a float nor a Decimal). Making it a new class would solve some of the problems discussed, but would create new problems instead. Agreed, if we were starting fresh. Correct behaviour of collections is more important than IEEE conformance of NaN comparisons. Also agreed. -- Terry Jan Reedy ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Not-a-Number (was PyObject_RichCompareBool identity shortcut)
Terry Reedy wrote: I think the committee goofed -- badly. Statisticians used missing value indicators long before the committee existed. They has no problem thinking that the indicator, as an object, equaled itself. So one could write (and I often did through the 1980s) the equivalent of for i,x in enumerate(datavec): if x == XMIS: # singleton missing value indicator for BMDP datavec[i] = default But NANs aren't missing values (although some people use them as such, that can be considered abuse of the concept). R distinguishes NANs from missing values: they have a built-in value NaN, and a separate built-in value NA which is the canonical missing value. R also treats comparisons of both special values as a missing value: NA == NA [1] NA NaN == NaN [1] NA including reflexivity: x = NA x == x [1] NA which strikes me as the worst of both worlds, guaranteed to annoy those who want the IEEE behaviour where NANs compare unequal, those like Terry who expect missing values to compare equal to other missing values, and those who want reflexivity to be treated as an invariant no matter what. NaN is Not a Number (therefore should be neither a float nor a Decimal). Making it a new class would solve some of the problems discussed, but would create new problems instead. Agreed, if we were starting fresh. I don't see that making NANs a separate class would make any practical difference what-so-ever, but the point is moot since we're not starting fresh :) Correct behaviour of collections is more important than IEEE conformance of NaN comparisons. Also agreed. To be pedantic, the IEEE standard doesn't have anything to say about comparisons of lists of floats that might contain NANs. Given the current *documented* behaviour that list equality is based on object equality, the actual behaviour is surprising, but I don't think there is anything wrong with the idea of containers assuming that their elements are reflexive. -- Steven ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com