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