creating many similar properties

Carl Banks pavlovevidence at gmail.com
Wed Oct 18 23:00:17 CEST 2006


Michele Simionato wrote:
> Carl Banks wrote:
> > Come on, I don't think anyone's under the impression we're being
> > indiscriminate here.
>
> Ok, but I don't  think that in the case at hand we should recommend a
> metaclass
> solution.

You sound as if you're avoiding metaclasses just for the sake of
avoiding them, which is just as bad as using them for the sake of using
them.

Here's how I see it: either it's ok to fiddle with the class dict, or
it isn't.  If it's ok, then a metaclass is the way to do it.  If it's
not ok to fiddle with the class dict, then he should be using
__setattr__, or creating properties longhand.  Messing with frames is
not the answer for production code.

...

Just for the hell of it, I decided to accept your challenge to run the
standard library with a different metaclass applied to all new-style
classes.  I ran the 2.4.3 regression test, replacing the builtin object
with a class that used the mod256metaclass I presented in this thread.
The results:

229 tests OK.
34 tests failed:
    test___all__ test_asynchat test_cgi test_cookielib test_copy
    test_copy_reg test_cpickle test_decimal test_descr test_descrtut
    test_email test_email_codecs test_httplib test_imaplib
    test_inspect test_logging test_mailbox test_mimetools
    test_mimetypes test_minidom test_pickle test_pyclbr
    test_robotparser test_sax test_sets test_socket test_socket_ssl
    test_sundry test_timeout test_urllib test_urllib2 test_urllib2net
    test_urllibnet test_xpickle

Not A-OK, but not exactly mass-pandemonium either.  There were plenty
of modules used the the new base object and worked fine.

There were only two causes for failure:
1. A class attempting to use __weakref__ slot.
2. There were also a few metaclass conflicts.

IMO, neither of these failure modes argues against using a metaclass to
preprocess the class dict.  The __weakref__ error is not applicable;
since it's an error to use it on any class with an instance dict.  (In
fact, the metaclass wasn't even causing the error: the same error would
have occurred if I had replaced builtin object with an empty subclass
of itself, without the metaclass.)

The metaclass conflict would only occur in the present case only if
someone wanted to subclass it AND specify a different metaclass.
Arguing that metaclasses should be avoided just to guard against this
rare possibility is defensive to the extreme.

I did not uncover any kinds of subtle, unexpected behavior that can
occur when metaclasses do weird things.  I know such things are
possible; how likely they are is another question.  The tests I ran
didn't uncover any.  So for now, the results of these tests don't seem
to support your point very well.

Carl


Appendix: Here's how I ran the test.  I inserted the following code at
the top of Lib/test/regrtest.py, and
ran make test.  I ran the tests on the Python 2.4.3 source tree, in
Linux.

=======================
import sys

class mod256metatype(type):
    def __new__(metatype,name,bases,clsdict):
        print >> sys.__stdout__, \
              "++++++++ Creating class %s of type mod256metatype" %
name
        def makeprop(sym):
            prop = '_%s'  % sym
            def _set(self,v):
                setattr(self,prop,v%256)
            def _get(self):
                return getattr(self,prop)
            return property(_get,_set)
        for sym in clsdict.get('__mod256__',()):
            clsdict[sym] = makeprop(sym)
        return super(metatype
        return type.__new__(metatype,name,bases,clsdict)

class _object:
    __metaclass__ = mod256metatype

import __builtin__
__builtin__.object = _object
=======================




More information about the Python-list mailing list