class "type" and metaclasses (was Re: Style for overwritten methods of abstract classes)

Stefan Schwarzer s.schwarzer at ndh.net
Sun Jan 6 18:05:20 EST 2002


Hello Alex

Alex Martelli wrote:
> > - (How) are the built-in function type and the class named "type" (that
> >   didn't exist prior to Python 2.2?) related?
> 
> Many entities that were built-in functions (acting as factories) up to 2.1
> have become types in 2.2.  type, int, str ...

I don't know if this question is related but it appeared to me some
weeks ago: I can define __int__ etc. in my classes to provide an
"opportunity" for int() to "convert" an instance of my class into an
int. I have not seen something like this for e. g. __list__, so I could
write something like

class ACollection:
    #...
    def __list__(self):
	'''Return a list object representing the contents of this object.'''
        # ...

obj = ACollection()
# do something with obj
L = list(obj)

Is it anyhow possible? Or, first, is it desirable and/or why was/is it
omitted from Python? (It's not that it hurts me, but to me it's an
asymmetry.)

> > No, I don't like B&D programming. If I would, I probably wouldn't use
> > Python but rather C++ or Java. ;-) My question aimed more at a simple
> > or elegant approach. (Please don't be upset if you consider your
> > suggestion simple and/or elegant. To be more specifically: the usage
> > of the so defined class may be simple but its implementation not so.
> > ;-) ).
> 
> I make no claims about the quality of the solution I proposed (actually
> hacked together somewhat fast) and wouldn't be surprised if it could be
> substantially improved.
> 
> The fundamental idea however does seem quite simple to me.  When a class
> statement executes, the metaclass is instantiated, so the metaclass's
> __init__ executes.  At that time, I want this metaclass-instance (this
> class) to become callable (with the normal semantics, that of producing
> class-instances) if and only if no abstract methods are left; otherwise,
> calling the class must raise an exception with a suitable error-message
> about what methods have not been overridden (have remained abstract).  All
> I do in that metaclass is try to enforce this idea, in order to parallel or
> mimic the "abstract classes" (non-instantiable classes) of certain other
> languages.
> 
> The whole setup seems reasonably elegant to me within the specified mindset
> of "must override" and "may override".  How else is a class going to be
> able to constrain its subclasses regarding what may or may not, must or
> must not, be overridden?  I think the mindset itself is at fault, and the
> normal Pythonic approach (let anybody override whatever, diagnose problems
> at runtime only if conflicts arise) far superior.  But the ability to
> constrain the 'may' and 'must' was the very essence of the thread, no?

Don't worry. :-) I did understand this from your previous posting.
I just could not figure out the details of the implementation. If I
hadn't understood your goals or your approach, I wouldn't have found
so much interest in it that I had asked those questions in response. :-)

> One case where I think a similar use of metaclasses might be _productive_
> is to emulate Haskell's typeclass construct.  In a Haskell typeclass,
> 'abstract' methods may be specified in apparently mutually-recursive terms,
> for example (in Python syntax):
> 
> class OneOrMany:
>     def doOne(self, one):
>         self.doMany([one])
>     def doMany(self, many):
>         for one in many:
>             self.doOne(one)
> 
> To implement a typeclass into an instantiable class, you have to override
> some subset of its methods so that all dependency cycles are broken.  Here,
> you might override either or both of doOne and doMany, otherwise the class
> would not be implementable.  Now THIS is what I consider elegant: it
> clearly specifies the intended semantic dependencies between the methods,
> and doesn't arbitrarily define one as more fundamental than others, when
> they're actually all on the same plane.  To translate this into a Python
> metaclass, you'd have to automatically or explicitly identify the
> dependencies (doOne->doMany, doMany->doOne), notice which dependencies are
> broken by subclassing (overriding some subsets of the methods), and check
> if the resulting dependency graph is acyclic -- otherwise, keep the class
> non-instantiable until by further subclassing the graph does become acyclic.

Yes, I think I understand. :-)

On the other hand, I don't know if I would really like it. C++ does so
many things automatically that it's not so easy to keep all these rules
in mind and consider them when it's necessary. I like the simplicity of
Python. :-)

Stefan



More information about the Python-list mailing list