On Thu, Jun 5, 2008 at 9:23 AM, Gonzalo Tornaria
<[EMAIL PROTECTED]> wrote:
>
>>  > Python classes can also take parameters.
>>
>>
>> I didn't know that.  I thought the only way to create a Python class
>>  is for the Python interpreter to execute Python code that looks like this:
>>
>>  class Foo(...):
>>      ...
>>
>>  That makes a new class called Foo.  How are you going to make, at
>>  runtime, new classes for each of Z/nZ say, for 1 <= n < 10^5, i.e.,
>>  something like this in Sage:
>>
>>   v = [Integers(n) for n in range(1,10^5)]
>>
>>  I do not think it is possible to concisely create a hundred thousand
>>  separate Python classes like that.
>
> FWIW, I think classes in python are "just" instances of class
> classobj. This latter class classobj (from new import classobj) is
> what implements the semantics of python's "new-style classes".
>
> Also classes can be constructed at runtime, as instances of class
> classobj. Moreover, one can also subclass "classobj" or "type" to
> produce metaclasses with different semantics (or whatever).
>
> Search for "python metaclass", e.g.
>
> http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html
>
> WRT your example:
>
> sage: def classinteger(m):
> ...     class A:
> ...       def __init__(self, n):
> ...         self.__n = n % m
> ...       def __repr__(self):
> ...         return  "%d mod %d" % (self.__n, m)
> ...     A.__name__ = "classintegers mod %d" % m
> ...     return A
> sage: classinteger(5)(3)
> 3 mod 5
> sage: time v = [classinteger(n) for n in range(1,10^5)]
> CPU time: 3.64 s,  Wall time: 4.14 s
> sage: time w = [Integers(n) for n in range(1,10^5)]
> CPU time: 15.75 s,  Wall time: 16.21 s
> sage: v[1256](34251235)
> 499 mod 1257
> sage: w[1256](34251235)
> 499
>
> Note that classinteger(n) is an instance of class 'classobj' in this
> simple example.
>
> sage: type(classinteger(n))
> <type 'classobj'>
> sage: classinteger(7)
> <class __main__.classintegers mod 7 at 0x3697770>
>
> But one could define a metaclass so this class works fine as a
> first-class object (e.g. it prints nicely, can define members acting
> on the class itself, etc):

Cool.  I stand corrected.  I'm glad this is fully supported in Python,
at least for new style classes.

OK, I have to come clean and admit that already actually knew all
about metaclasses, but considered using them this way so
unnatural and ugly that I would not recommend it.

> I was going to say that using classes built at runtime like this was
> fine but not a good option for performance reasons, but the example
> above shows the overhead of python class creation time is not so
> significant.

It is very impressive how fast Python classobj is,
but it is still an order of magnitude slower than object instantiation,
though your flawed benchmark incorrectly suggests the opposite.

Two points:

(1) It makes no sense to compare with Integers(n), which is
doing all kinds of other things (it could for all we know for now
be factoring n), etc.  You should compare with a minimal
class MyIntegers.   Creating Python class instances can be massively
optimized by doing the class creation in Cython, like we do in integer.pyx.

(2) It is important to consider the performance implications if the class you're
constructing has lots of methods.    I tried the above benchmark but
with 8 trivial methods added to the class, and it took 5 times as long
to run!  Of course, this could easily be mitigated with inheritance,
but is worth
pointing out.  Also, every single classobj takes *memory* for all methods
that are special for it. Again inheritance could  mitigate this problem.

Here's an example benchmark but using MyIntegers instead of Integer.
In it, creating a class takes four times as long as instantiating an instance:

{{{id=54|
def classinteger(m):
     class A:
       def __init__(self, n):
         self.__n = n % m
       def __repr__(self):
         return  "%d mod %d" % (self.__n, m)
     A.__name__ = "classintegers mod %d" % m
     return A
///
}}}

{{{id=57|
class MyIntegers:
    def __init__(self, m):
        self.__m = m
///
}}}

{{{id=55|
time v = [classinteger(n) for n in range(1,10^5)]
///

CPU time: 2.89 s,  Wall time: 2.98 s
}}}

{{{id=53|
time w = [MyIntegers(n) for n in range(1,10^5)]
///

CPU time: 0.63 s,  Wall time: 0.63 s
}}}

{{{id=52|
2.89 / 0.63
///

4.58730158730159
}}}

--~--~---------~--~----~------------~-------~--~----~
To post to this group, send email to sage-devel@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at http://groups.google.com/group/sage-devel
URLs: http://www.sagemath.org
-~----------~----~----~----~------~----~------~--~---

Reply via email to