Hooks, aspect-oriented programming, and design by contract

montanaro at tttech.com montanaro at tttech.com
Wed Jan 23 09:08:37 EST 2002


    Alex> One simple (maybe even silly) example: I can write a metaclass
    Alex> that does substantially nothing different from builtin type (the
    Alex> normal metaclass of all except classic classes) EXCEPT emit a
    Alex> message upon each instantiation:

    Alex> import types

    Alex> class mymeta(type):
    Alex>     def __call__(self, *arg, **kw):
    Alex>         print "Creating instance of", self.__name__
    Alex>         return type.__call__(self, *arg, **kw)

    Alex> def makeaclassandafewinstances():
    Alex>     class justaclass:
    Alex>         def __del__(self): print "destroying an instance"
    Alex>     a = justaclass()
    Alex>     b = justaclass()

    Alex> __metaclass__ = type
    Alex> makeaclassandafewinstances()
    Alex> __metaclass__ = mymeta
    Alex> makeaclassandafewinstances()

Alex,

This confuses me a bit.  I assumed looking at your code that all that was
necessary was that there be an object with the name "__metaclass__" in-scope
at class definition time.  I was surprised that this slight modification of
your example doesn't work:

    import types

    class mymeta(type):
        def __call__(self, *arg, **kw):
            print "Creating instance of", self.__name__
            return type.__call__(self, *arg, **kw)

    def makeaclassandafewinstances(__metaclass__=type):
        print "using", __metaclass__
        class justaclass:
            def __del__(self): print "destroying an instance"
        a = justaclass()
        b = justaclass()

    makeaclassandafewinstances(type)
    makeaclassandafewinstances(mymeta)

Running it, I get

    using <type 'type'>
    destroying an instance
    destroying an instance
    using <class '__main__.mymeta'>
    destroying an instance
    destroying an instance

In PEP 253 Guido said:

  - a class statement can contain a __metaclass__ declaration,
    specifying the metaclass to be used to create the new class

Which lead me to this modification:

    def makeaclassandafewinstances(meta=type):
        print "using", meta
        class justaclass:
            __metaclass__ = meta
            def __del__(self): print "destroying an instance"
        a = justaclass()
        b = justaclass()

which does work.  This, however:

    def makeaclassandafewinstances(__metaclass__=type):
        print "using", __metaclass__
        class justaclass:
            __metaclass__ = __metaclass__
            def __del__(self): print "destroying an instance"
        a = justaclass()
        b = justaclass()

didn't, yielding a NameError for __metaclass__.

Can you explain why your version works (__metaclass__ as a global), while
the two versions with __metaclass__ as a local didn't and the version using
meta as a local did?

Thx,

-- 
Skip Montanaro (skip at pobox.com - http://www.mojam.com/)




More information about the Python-list mailing list