Hi!

For the record: If the metaclass M of a new class C is dynamically
created, for example from the metaclasses of the bases of C, then
pickling of C indeed works after registering copy_reg.pickle(M,
M.__reduce__).

Remark:

I found some comments stating that the current use of metaclasses in
Sage is not very scalable. I guess that shall be understood as "things
get messy if one puts a new metaclass on top of existing (and
different) metaclasses of the base classes".

It seems to me that the approach to dynamically create new metaclasses
from old would be better scalable.


Example:

I can easily put my FastHashMetaclass on top of the metaclass that
comes with UniqueRepresentation.
  sage: class Foo(UniqueRepresentation):
  ....:     __metaclass__ = FastHashMetaclass
  ....:     def __init__(self,R):
  ....:         self.R = R
  ....:     def __repr__(self):
  ....:         return "[%s]"%self.R
  ....:

It has a dynamic metaclass, obtained from FastHashMetaclass and
ClasscallMetaclass:
  sage: type(Foo)
  <class
'_home_king_SAGE_work_fast_hash_fast_hash_pyx_1.FastHashAndClasscallMetaclass'>

Pickling of the class works (which would, by the way, not work without
my metaclass. See below):
  sage: loads(dumps(Foo))
  <class '__main__.Foo'>

Object creation and object pickling works as well. Thanks to
inheritance from UniqueRepresentation, Foo instances are unique:
  sage: f = Foo(7)
  sage: f
  [7]
  sage: loads(dumps(f)) is f
  True

Now, we compare with a similar class that doesn't use
FastHashMetaclass:
  sage: class Bar(UniqueRepresentation):
  ....:     def __init__(self,R):
  ....:         self.R = R
  ....:     def __repr__(self):
  ....:         return "[%s]"%self.R
  ....:
  sage: b = Bar(8)
  # Pickling fails:
  sage: loads(dumps(b)) is b
  Traceback (most recent call last):
  ...
  PicklingError: Can't pickle <class '__main__.Bar'>: attribute lookup
__main__.Bar failed

And, as the name of the metaclass suggest: The hash is faster when one
uses it:
  sage: %timeit hash(f)
  625 loops, best of 3: 478 ns per loop
  sage: %timeit hash(b)
  625 loops, best of 3: 1.06 µs per loop

In some cases, the metaclass can be used to speed-up the hash *after*
object creation:
  sage: P.<x> = QQ[]
  sage: %timeit hash(P)
  625 loops, best of 3: 3.17 µs per loop
  sage: P.__class__ = FastHashMetaclass(P.__class__)
  sage: %timeit hash(P)
  625 loops, best of 3: 453 ns per loop
But in other cases, that won't work (for example, overriding the class
of x won't work).

To me, it seems like a potentially useful programming tool. I guess I
will soon open a ticket.

Best regards,
Simon

-- 
To post to this group, send an email to sage-devel@googlegroups.com
To unsubscribe from this group, send an email to 
sage-devel+unsubscr...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/sage-devel
URL: http://www.sagemath.org

Reply via email to