PEP 31XX: A Type Hierarchy for Numbers (and other algebraic entities)

Here's a draft of the numbers ABCs PEP. The most up to date version will live in the darcs repository at http://jeffrey.yasskin.info/darcs/PEPs/pep-3141.txt (unless the number changes) for now. Naming a PEP about numbers 3.141 seems cute, but of course, I don't get to pick the number. :) This is my first PEP, so apologies for any obvious mistakes.
I'd particularly like the numpy people's input on whether I've gotten floating-point support right.
Thanks, Jeffrey Yasskin
------------------------------- PEP: 3141 Title: A Type Hierarchy for Numbers (and other algebraic entities) Version: $Revision: 54928 $ Last-Modified: $Date: 2007-04-23 16:37:29 -0700 (Mon, 23 Apr 2007) $ Author: Jeffrey Yasskin jyasskin@gmail.com Status: Draft Type: Standards Track Content-Type: text/x-rst Created: 23-Apr-2007 Post-History: Not yet posted
Abstract ========
This proposal defines a hierarchy of Abstract Base Classes (ABCs) [#pep3119] to represent numbers and other algebraic entities similar to numbers. It proposes:
* A hierarchy of algebraic concepts, including monoids, groups, rings, and fields with successively more operators and constraints on their operators. This will be added as a new library module named "algebra".
* A hierarchy of specifically numeric types, which can be converted to and from the native Python types. This will be added as a new library module named "numbers".
Rationale =========
Functions that take numbers as arguments should be able to determine the properties of those numbers, and if and when overloading based on types is added to the language, should be overloadable based on the types of the arguments. This PEP defines some abstract base classes that are useful in numerical calculations. A function can check that variable is an instance of one of these classes and then rely on the properties specified for them. Of course, the language cannot check these properties, so where I say something is "guaranteed", I really just mean that it's one of those properties a user should be able to rely on.
This PEP tries to find a balance between providing fine-grained distinctions and specifying types that few people will ever use.
Specification =============
Although this PEP uses terminology from PEP3119, the hierarchy is meaningful for any systematic method of defining sets of classes. **Todo:** link to the Interfaces PEP when it's ready. I'm also using the extra notation from [#pep3107] (annotations) to specify some types.
Object oriented systems have a general problem in constraining functions that take two arguments. To take addition as an example, ``int(3) + int(4)`` is defined, and ``vector(1,2,3) + vector(3,4,5)`` is defined, but ``int(3) + vector(3,4,5)`` doesn't make much sense. So ``a + b`` is not guaranteed to be defined for any two instances of ``AdditiveGroup``, but it is guaranteed to be defined when ``type(a) == type(b)``. On the other hand, ``+`` does make sense for any sorts of numbers, so the ``Complex`` ABC refines the properties for plus so that ``a + b`` is defined whenever ``isinstance(a,Complex) and isinstance(b,Complex)``, even if ``type(a) != type(b)``.
Monoids (http://en.wikipedia.org/wiki/Monoid) consist of a set with an associative operation, and an identity element under that operation. **Open issue**: Is a @classmethod the best way to define constants that depend only on the type?::
class MonoidUnderPlus(Abstract): """+ is associative but not necessarily commutative and has an identity given by plus_identity().
Subclasses follow the laws:
a + (b + c) === (a + b) + c a.plus_identity() + a === a === a + a.plus_identity()
Sequences are monoids under plus (in Python) but are not AdditiveGroups. """ @abstractmethod def __add__(self, other): raise NotImplementedError
@classmethod @abstractmethod def plus_identity(cls): raise NotImplementedError
I skip ordinary non-commutative groups here because I don't have any common examples of groups that use ``+`` as their operator but aren't commutative. If we find some, the class can be added later.::
class AdditiveGroup(MonoidUnderPlus): """Defines a commutative group whose operator is +, and whose inverses are produced by -x. See http://en.wikipedia.org/wiki/Abelian_group.
Where a, b, and c are instances of the same subclass of AdditiveGroup, the operations should follow these laws, where 'zero' is a.__class__.zero().
a + b === b + a (a + b) + c === a + (b + c) zero + a === a a + (-a) === zero a - b === a + -b
Some abstract subclasses, such as Complex, may extend the definition of + to heterogenous subclasses, but AdditiveGroup only guarantees it's defined on arguments of exactly the same types.
Vectors are AdditiveGroups but are not Rings. """ @abstractmethod def __add__(self, other): """Associative commutative operation, whose inverse is negation.""" raise NotImplementedError
**Open issue:** Do we want to give people a choice of which of the following to define, or should we pick one arbitrarily?::
def __neg__(self): """Must define this or __sub__().""" return self.zero() - self
def __sub__(self, other): """Must define this or __neg__().""" return self + -other
@classmethod @abstractmethod def zero(cls): """A better name for +'s identity as we move into more mathematical domains.""" raise NotImplementedError
@classmethod def plus_identity(cls): return cls.zero()
Including Semiring (http://en.wikipedia.org/wiki/Semiring) would help a little with defining a type for the natural numbers. That can be split out once someone needs it (see ``IntegralDomain`` for how).::
class Ring(AdditiveGroup): """A mathematical ring over the operations + and *. See http://en.wikipedia.org/wiki/Ring_%28mathematics%29.
In addition to the requirements of the AdditiveGroup superclass, a Ring has an associative but not necessarily commutative multiplication operation with identity (one) that distributes over addition. A Ring can be constructed from any integer 'i' by adding 'one' to itself 'i' times. When R is a subclass of Ring, the additive identity is R(0), and the multiplicative identity is R(1).
Matrices are Rings but not Commutative Rings or Division Rings. The quaternions are a Division Ring but not a Field. The integers are a Commutative Ring but not a Field. """ @abstractmethod def __init__(self, i:int): """An instance of a Ring may be constructed from an integer.
This may be a lossy conversion, as in the case of the integers modulo N.""" pass
@abstractmethod def __mul__(self, other): """Satisfies: a * (b * c) === (a * b) * c one * a === a a * one === a a * (b + c) === a * b + a * c
where one == a.__class__(1) """ raise NotImplementedError
@classmethod def zero(cls): return cls(0)
@classmethod def one(cls): return cls(1)
I'm skipping both CommutativeRing and DivisionRing here.
class Field(Ring): """The class Field adds to Ring the requirement that * be a commutative group operation except that zero does not have an inverse. See http://en.wikipedia.org/wiki/Field_%28mathematics%29.
Practically, that means we can define division on a Field. The additional laws are:
a * b === b * a a / a === a.__class_(1) # when a != a.__class__(0)
Division lets us construct a Field from any Python float, although the conversion is likely to be lossy. Some Fields include the real numbers, rationals, and integers mod a prime. Python's ``float`` resembles a Field closely. """ def __init__(self, f:float): """A Field should be constructible from any rational number, which includes Python floats.""" pass
@abstractmethod def __div__(self, divisor): raise NotImplementedError
Division is somewhat complicated in Python. You have both __floordiv__ and __div__, and ints produce floats when they're divided. For the purposes of this hierarchy, ``__floordiv__(a, b)`` is defined by ``floor(__div__(a, b))``, and, since int is not a subclass of Field, it's allowed to do whatever it wants with __div__.
There are four more reasonable classes that I'm skipping here in the interest of keeping the initial library simple. They are:
``Algebraic`` Rational powers of its elements are defined (and maybe a few other operations) (http://en.wikipedia.org/wiki/Algebraic_number). Complex numbers are the most well-known algebraic set. Real numbers are _not_ algebraic, but Python does define these operations on floats, which makes defining this class somewhat difficult.
``Trancendental`` The elementary functions (http://en.wikipedia.org/wiki/Elementary_function) are defined. These are basically arbitrary powers, trig functions, and logs, the contents of ``cmath``.
The following two classes can be reasonably combined with ``Integral`` for now. ``IntegralDomain`` Defines __divmod__. (http://darcs.haskell.org/numericprelude/docs/html/Algebra-IntegralDomain.htm...)
``PrincipalIdealDomain`` Defines gcd and lcm. (http://darcs.haskell.org/numericprelude/docs/html/Algebra-PrincipalIdealDoma...)
If someone needs to split them later, they can use code like:: import numbers class IntegralDomain(Ring): ... numbers.Integral.__bases__ = (IntegralDomain,) + numbers.Integral.__bases__
Finally, we get to numbers. This is where we switch from the "algebra" module to the "numbers" module.::
class Complex(Ring, Hashable): """The ``Complex`` ABC indicates that the value lies somewhere on the complex plane, not that it in fact has a complex component: ``int`` is a subclass of ``Complex``. Because these actually represent complex numbers, they can be converted to the ``complex`` type.
``Complex`` finally gets around to requiring its subtypes to be immutable so they can be hashed in a standard way.
``Complex`` also requires its operations to accept heterogenous arguments. Subclasses should override the operators to be more accurate when they can, but should fall back on the default definitions to handle arguments of different (Complex) types.
**Open issue:** __abs__ doesn't fit here because it doesn't exist for the Gaussian integers (http://en.wikipedia.org/wiki/Gaussian_integer). In fact, it only exists for algebraic complex numbers and real numbers. We could define it in both places, or leave it out of the ``Complex`` classes entirely and let it be a custom extention of the ``complex`` type.
The Gaussian integers are ``Complex`` but not a ``Field``. """ @abstractmethod def __complex__(self): """Any Complex can be converted to a native complex object.""" raise NotImplementedError
def __hash__(self): return hash(complex(self))
@abstractmethod def real(self) => Real: raise NotImplementedError
@abstractmethod def imag(self) => Real: raise NotImplementedError
@abstractmethod def __add__(self, other): """The other Ring operations should be implemented similarly.""" if isinstance(other, Complex): return complex(self) + complex(other) else: return NotImplemented
``FractionalComplex(Complex, Field)`` might fit here, except that it wouldn't give us any new operations.
class Real(Complex, TotallyOrdered): """Numbers along the real line. Some subclasses of this class may contain NaNs that are not ordered with the rest of the instances of that type. Oh well. **Open issue:** what problems will that cause? Is it worth it in order to get a straightforward type hierarchy? """ @abstractmethod def __float__(self): raise NotImplementedError def __complex__(self): return complex(float(self)) def real(self) => self.__class__: return self def imag(self) => self.__class__: return self.__class__(0) def __abs__(self) => self.__class__: if self < 0: return -self else: return self
class FractionalReal(Real, Field): """Rationals and floats. This class provides concrete definitions of the other four methods from properfraction and allows you to convert fractional reals to integers in a disciplined way. """ @abstractmethod def properfraction(self) => (int, self.__class__): """Returns a pair (n,f) such that self == n+f, and: * n is an integral number with the same sign as self; and * f is a fraction with the same type and sign as self, and with absolute value less than 1. """ raise NotImplementedError def floor(self) => int: n, r = self.properfraction() if r < 0 then n - 1 else n def ceiling(self) => int: ... def __trunc__(self) => int: ... def round(self) => int: ...
**Open issue:** What's the best name for this class? RealIntegral? Integer?::
class Integral(Real): """Integers!""" @abstractmethod def __int__(self): raise NotImplementedError def __float__(self): return float(int(self))
@abstractmethod def __or__(self, other): raise NotImplementedError @abstractmethod def __xor__(self, other): raise NotImplementedError @abstractmethod def __and__(self, other): raise NotImplementedError @abstractmethod def __lshift__(self, other): raise NotImplementedError @abstractmethod def __rshift__(self, other): raise NotImplementedError @abstractmethod def __invert__(self): raise NotImplementedError
Floating point values may not exactly obey several of the properties you would expect from their superclasses. For example, it is possible for ``(large_val + -large_val) + 3 == 3``, but ``large_val + (-large_val + 3) == 0``. On the values most functions deal with this isn't a problem, but it is something to be aware of. Types like this inherit from ``FloatingReal`` so that functions that care can know to use a numerically stable algorithm on them. **Open issue:** Is this the proper way to handle floating types?::
class FloatingReal: """A "floating" number is one that is represented as ``mantissa * radix**exponent`` where mantissa, radix, and exponent are all integers. Subclasses of FloatingReal don't follow all the rules you'd expect numbers to follow. If you really care about the answer, you have to use numerically stable algorithms, whatever those are.
**Open issue:** What other operations would be useful here?
These include floats and Decimals. """ @classmethod @abstractmethod def radix(cls) => int: raise NotImplementedError
@classmethod @abstractmethod def digits(cls) => int: """The number of significant digits of base cls.radix().""" raise NotImplementedError
@classmethod @abstractmethod def exponentRange(cls) => (int, int): """A pair of the (lowest,highest) values possible in the exponent.""" raise NotImplementedError
@abstractmethod def decode(self) => (int, int): """Returns a pair (mantissa, exponent) such that mantissa*self.radix()**exponent == self.""" raise NotImplementedError
Inspiration =========== http://hackage.haskell.org/trac/haskell-prime/wiki/StandardClasses http://repetae.net/john/recent/out/classalias.html
References ==========
.. [#pep3119] Introducing Abstract Base Classes (http://www.python.org/dev/peps/pep-3119/)
.. [#pep3107] Function Annotations (http://www.python.org/dev/peps/pep-3107/)
.. [3] Possible Python 3K Class Tree?, wiki page created by Bill Janssen (http://wiki.python.org/moin/AbstractBaseClasses)
.. [#numericprelude] NumericPrelude: An experimental alternative hierarchy of numeric type classes (http://darcs.haskell.org/numericprelude/docs/html/index.html)
Acknowledgements ----------------
Thanks to Neil Norwitz for helping me through the PEP process.
The Haskell Numeric Prelude [#numericprelude] nicely condensed a lot of experience with the Haskell numeric hierarchy into a form that was relatively easily adaptable to Python.
Copyright =========
This document has been placed in the public domain.
.. Local Variables: mode: indented-text indent-tabs-mode: nil sentence-end-double-space: t fill-column: 70 coding: utf-8 End:

"Jeffrey Yasskin" jyasskin@gmail.com wrote:
Here's a draft of the numbers ABCs PEP. The most up to date version will live in the darcs repository at http://jeffrey.yasskin.info/darcs/PEPs/pep-3141.txt (unless the number changes) for now. Naming a PEP about numbers 3.141 seems cute, but of course, I don't get to pick the number. :) This is my first PEP, so apologies for any obvious mistakes.
I'd particularly like the numpy people's input on whether I've gotten floating-point support right.
Thanks, Jeffrey Yasskin
PEP: 3141 Title: A Type Hierarchy for Numbers (and other algebraic entities) Version: $Revision: 54928 $ Last-Modified: $Date: 2007-04-23 16:37:29 -0700 (Mon, 23 Apr 2007) $ Author: Jeffrey Yasskin jyasskin@gmail.com Status: Draft Type: Standards Track Content-Type: text/x-rst Created: 23-Apr-2007 Post-History: Not yet posted
Abstract
This proposal defines a hierarchy of Abstract Base Classes (ABCs) [#pep3119] to represent numbers and other algebraic entities similar to numbers. It proposes:
[snip]
Are the base number operations in Python all that difficult to understand? Do we really need to add mathematical formalism into Python's type system before people understand the meaning of X * Y? Because all I really see this doing is confusing the hell out of people who aren't mathematicians; I'm a theoretical computer scientist and I had to try to think for a moment to verify that all of those were really necessary to separate the cases.
I really do understand wanting to be able to ask "is operation X supported for values Y and Z", but is this really necessary for numbers?
- Josiah

[bcc'ing numpy-discussion. Comments should probably try to stay on the python-3000 list.]
On 4/25/07, Josiah Carlson jcarlson@uci.edu wrote:
Are the base number operations in Python all that difficult to understand? Do we really need to add mathematical formalism into Python's type system before people understand the meaning of X * Y? Because all I really see this doing is confusing the hell out of people who aren't mathematicians; I'm a theoretical computer scientist and I had to try to think for a moment to verify that all of those were really necessary to separate the cases.
I really do understand wanting to be able to ask "is operation X supported for values Y and Z", but is this really necessary for numbers?
If you don't want to use the full power of the system, nothing forces you to. If someone doesn't know what a Ring or a complex number is, they can just check for Real and rely on the same operations, at the small cost of overconstraining their inputs. One reason I'm suggesting splitting the classes into the "algebra" and "numbers" modules is so that people who don't know or care about the algebra can rely on just "numbers" and still get nearly all of the benefits.
However, I think it's important to provide a framework for people who want to do more powerful things. If you write a function that can take an arbitrary ring, it should Just Work on a python int, or any other Complex subclass, without you having to check for a lot of operations separately. The Haskell98 numerical hierarchy actually does start at Num, ignoring the algebraic structures underneath, and it draws a lot of criticism for it.
That does mean that the names and documentation in the numbers module need to be as clear as we can make them for non-mathematical audiences. I'm certainly open to suggestions on that front.

[bcc'ing numpy-discussion. Comments should probably try to stay on the python-3000 list.]
On 4/25/07, Josiah Carlson jcarlson@uci.edu wrote:
Are the base number operations in Python all that difficult to understand? Do we really need to add mathematical formalism into Python's type system before people understand the meaning of X * Y? Because all I really see this doing is confusing the hell out of people who aren't mathematicians; I'm a theoretical computer scientist and I had to try to think for a moment to verify that all of those were really necessary to separate the cases.
I really do understand wanting to be able to ask "is operation X supported for values Y and Z", but is this really necessary for numbers?
If you don't want to use the full power of the system, nothing forces you to. If someone doesn't know what a Ring or a complex number is, they can just check for Real and rely on the same operations, at the small cost of overconstraining their inputs. One reason I'm suggesting splitting the classes into the "algebra" and "numbers" modules is so that people who don't know or care about the algebra can rely on just "numbers" and still get nearly all of the benefits.
However, I think it's important to provide a framework for people who want to do more powerful things. If you write a function that can take an arbitrary ring, it should Just Work on a python int, or any other Complex subclass, without you having to check for a lot of operations separately. The Haskell98 numerical hierarchy actually does start at Num, ignoring the algebraic structures underneath, and it draws a lot of criticism for it.
That does mean that the names and documentation in the numbers module need to be as clear as we can make them for non-mathematical audiences. I'm certainly open to suggestions on that front.

Are the base number operations in Python all that difficult to understand?
Well, they're a little tricky.
But the basic problem with "number" support, in almost every programming language, is that they are too low-level an abstraction. A number in a program is never *just* an integer or a float. It's always an integer or float (or complex, OK) deployed in support of a very specific purpose. It's a loop index, or a weight in kilos, or the number of calendar entries for a particular day. It often has units, and a fixed range of values or fixed set of values, neither of which are taken into account in most programming languages.
Strings really suffer from the same lack of focus. A string is never just a string. It's a book title, or a filename, or a person's surname, or an email address. It's usually got a particular human language (or computer OS) associated with it. Each of these usages has particular limitations and patterns which limit both its range of values, and the operations which can be successfully applied to it.
Bill

On Thu, 26 Apr 2007 10:11:27 PDT, Bill Janssen janssen@parc.com wrote:
Are the base number operations in Python all that difficult to understand?
Well, they're a little tricky.
But the basic problem with "number" support, in almost every programming language, is that they are too low-level an abstraction. A number in a program is never *just* an integer or a float. It's always an integer or float (or complex, OK) deployed in support of a very specific purpose. It's a loop index, or a weight in kilos, or the number of calendar entries for a particular day. It often has units, and a fixed range of values or fixed set of values, neither of which are taken into account in most programming languages.
Strings really suffer from the same lack of focus. A string is never just a string. It's a book title, or a filename, or a person's surname, or an email address. It's usually got a particular human language (or computer OS) associated with it. Each of these usages has particular limitations and patterns which limit both its range of values, and the operations which can be successfully applied to it.
I definitely agree with this, and resolving it would probably address a large class of mistakes made when doing any programming involving numbers and strings (anyone done much of that lately? :).
Does the introduction of a lot of base classes for `int' and `float' do anything to address this, though? What you really want is a bunch of new subclasses of them, the opposite.
Jean-Paul

The following things mean absolutely nothing to me:
- Monoid - MonoidUnderPlus - Group - Ring - Semiring - Field
So, most of the terminology in the PEP.
I can see use-cases for this level of formalism, but I'm a strong -1 on making any part of the stdlib effectively off-limits for people without advanced math degrees. Why can't this be shipped as a third-party module?
Collin Winter

On 4/25/07, Collin Winter collinw@gmail.com wrote:
The following things mean absolutely nothing to me:
- Monoid
- MonoidUnderPlus
- Group
- Ring
- Semiring
- Field
So, most of the terminology in the PEP.
I can see use-cases for this level of formalism, but I'm a strong -1 on making any part of the stdlib effectively off-limits for people without advanced math degrees. Why can't this be shipped as a third-party module?
As a math major I have no excuse, but I have to confess I'm also really rusty on these things. (Nothing a quick look at wikipedia can't refresh though.)
Jeffrey, is there any way you can drop the top of the tree and going straight from Number to Complex -> Real -> Rational -> Integer? These are the things that everyone with high school math will know.

On 4/25/07, Guido van Rossum guido@python.org wrote:
Jeffrey, is there any way you can drop the top of the tree and going straight from Number to Complex -> Real -> Rational -> Integer? These are the things that everyone with high school math will know.
I think yes, if you can confirm that the import numbers class Ring(AdditiveGroup): ... numbers.Complex.__bases__ = (Ring,) + numbers.Complex.__bases__ hack I mention under IntegralDomain will make isinstance(int, Ring) return True.
Do you want "Number" to be equivalent to Ring+Hashable (or a Haskell-like Ring+Hashable+__abs__+__str__)? I don't think a "Number" class is strictly necessary since people can check for Complex or Real directly, and one of those two is probably what they'll expect after knowing that something's a number.
Also, I don't see much point in putting Rational between Real and Integer. The current hierarchy is Real (int, float, Decimal, rational) :> Integer (int) and Real :> FractionalReal (float, Decimal, rational), but Integer and FractionalReal are just siblings.
I'm wondering how many people are writing new numeric types who don't know the abstract algebra. I think we should be able to insulate people who are just using the types from the complexities underneath, and the people writing new types will benefit. Or will seeing "Ring" in a list of superclasses be enough to confuse people?

On 4/25/07, Jeffrey Yasskin jyasskin@gmail.com wrote:
On 4/25/07, Guido van Rossum guido@python.org wrote:
Jeffrey, is there any way you can drop the top of the tree and going straight from Number to Complex -> Real -> Rational -> Integer? These are the things that everyone with high school math will know.
I think yes, if you can confirm that the import numbers class Ring(AdditiveGroup): ... numbers.Complex.__bases__ = (Ring,) + numbers.Complex.__bases__ hack I mention under IntegralDomain will make isinstance(int, Ring) return True.
Hm... That would require built-in types to be mutable (by mere mortals) which would kill the idea of multiple interpreters. AFAIK the only user of multiple interpreters is mod_python, which is a pretty popular Apache module... (Google claims 1.8M hits, vs. 5.66M for mod_perl, the market leader.)
I guess the alternative would be to keep the mathematical ones in but make it so that mere mortals (among which I count myself :) never need to know about them. Sort of like metaclasses, for most people.
But this still presents a bit of a problem. If we insist that built-in types are immutable, whenever a mathematician needs a new kind of algebraic category (you mention a few in the PEP), they have no way to declare that int or float are members of that category. They could write things like
class MyFloat(float, DivisionRing): pass
but this would be fairly painful. I would like to let users modify the built-ins, but such changes ought to be isolated from other interpreters running in the same address space. I don't want to be the one to tell the mod_python community they won't be able to upgrade to 3.0...
Do you want "Number" to be equivalent to Ring+Hashable (or a Haskell-like Ring+Hashable+__abs__+__str__)? I don't think a "Number" class is strictly necessary since people can check for Complex or Real directly, and one of those two is probably what they'll expect after knowing that something's a number.
Fair enough, you could start with Complex.
Also, I don't see much point in putting Rational between Real and Integer. The current hierarchy is Real (int, float, Decimal, rational) :> Integer (int) and Real :> FractionalReal (float, Decimal, rational), but Integer and FractionalReal are just siblings.
Why? Why not have a properfraction() on Integer that always returns 0 for the fraction? The current math.modf() works just fine on ints (returning a tuple of floats).
And why distinguish between Real and FractionalReal? What's the use case for reals that don't know how to compute their fractional part?
I'm wondering how many people are writing new numeric types who don't know the abstract algebra.
It's easy to know the algebra without recalling the terminologies. Lots of programmers (myself included!) are largely self-taught.
I think we should be able to insulate people who are just using the types from the complexities underneath, and the people writing new types will benefit. Or will seeing "Ring" in a list of superclasses be enough to confuse people?
Shouldn't only mathematicians be tempted to write classes deriving from Ring? Everyone else is likely to subclass one of the more familiar types, from Complex onwards.
PS. I've checked your PEP in, as PEP3141. We might as well keep a fairly complete record in svn, even if we decide to cut out the algebraic foundational classes.

On Apr 26, 6:58 am, "Guido van Rossum" g...@python.org wrote:
I would like to let users modify the built-ins, but such changes ought to be isolated from other interpreters running in the same address space. I don't want to be the one to tell the mod_python community they won't be able to upgrade to 3.0...
As someone from the mod_python community, the discussion has been noted though. :-)
FWIW, in mod_wsgi, an alternate way of hosting Python in conjunction with Apache which is being developed and already available for early experimentation, it will also be optionally possible to isolate applications into separate processes potentially being run as different users. This will still though all be configured through and managed by Apache with it being pretty transparent to an application and a user as to whether a specific application is running in the Apache child process or the distinct daemon process spawned by Apache. Since the use of a separate daemon process will probably end up being the preferred mode of operation, especially for commercial web hosting, loosing the ability to also run parallel applications in distinct interpreters within the same process would only be a minor loss. Using multiple sub interpreters already causes lots of headaches with the simple GIL state API, inability to have different versions of extension modules loaded etc, so much so that separate processes may have to be the norm.
Graham

Jeffrey, is there any way you can drop the top of the tree and going straight from Number to Complex -> Real -> Rational -> Integer? These are the things that everyone with high school math will know.
I think knowledge of the concepts of group, ring, and field is supposed to be standard knowledge for any high-school senior -- isn't this what the "new math" was all about?. But they're pretty fundamental to computer science; anyone trying to do serious work in the field (that is, anyone with a reason to read the PEP) should have a nodding acquaintance with them.
Bill

Guido van Rossum wrote:
Jeffrey, is there any way you can drop the top of the tree and going straight from Number to Complex -> Real -> Rational -> Integer? These are the things that everyone with high school math will know.
Having taught mathematics at a community college for a little while (hell, having taught mathematics at a few Universities - I won't name names), I would suggest that this is not a valid premise. I was going to qualify that by adding that hopefully it is a valid premise for would-be mathematics-package-using programmers, but I recall a fellow student in an Intro to C class I was once in (not teaching, however) who, even though the class was not supposed to be an Intro to Programming course (this was back in the day when those were still taught in Pascal and those taking the C class were supposed to have had successfully completed the Pascal course first), had to be handheld not simply through the implementation of algorithms in C, but in the very development of algorithms from a problem statement. Even without having to resort to such an extreme anecdote, I can envision situations where knowledgeable, skilled, experienced, but "deficient"-in-math programmers are called upon (implicitly or explicitly) by management to use numpy/scipy.
All this said, I'm certainly of the opinion that we can't "dumb down" numpy *too* much (after all, by some definition, it is an "advanced" mathematics package, at least IMO), and to my mind the sequence above, i.e., X->C->R->Q->Z, is a more than reasonable "line in the sand".
DG

On 4/25/07, Jeffrey Yasskin jyasskin@gmail.com wrote:
class MonoidUnderPlus(Abstract):
Is this useful? Just because two things are both Monoid instances doesn't mean I can add them -- they have to be part of the same Monoid. By the time you do
assert isinstance(a, MonoidUnderPlus) assert isinstance(b, MonoidUnderPlus) assert isinstance(a, b.__class__) or isinstance(b, a.__class__)
I'm not sure how much you've really saved.
**Open issue:** Do we want to give people a choice of which of the following to define, or should we pick one arbitrarily?::
def __neg__(self): """Must define this or __sub__().""" return self.zero() - self
def __sub__(self, other): """Must define this or __neg__().""" return self + -other
Probably better to pick one; then it is clear that they have to override something, and there won't be as many accidental infinite loops. If they really want to define the other, they can just do
def __neg__(self): super(_this_class__, self).__neg__()
The decorator doesn't know it isn't a real override.
-jJ
participants (9)
-
Bill Janssen
-
Collin Winter
-
David Goldsmith
-
Graham Dumpleton
-
Guido van Rossum
-
Jean-Paul Calderone
-
Jeffrey Yasskin
-
Jim Jewett
-
Josiah Carlson