Type casting a base class to a derived one?

Chris Mellon arkanes at gmail.com
Wed Jan 24 14:55:20 EST 2007


On 1/24/07, Cliff Wells <cliff at develix.com> wrote:
> On Wed, 2007-01-24 at 12:57 -0600, Chris Mellon wrote:
>
> >
> > In Python, you can do this simply by re-assigning the __class__. I'm
> > not convinced that your type system makes sense, here though. Any
> > reasonable ORM should be able to persist and reload an object without
> > losing the type information. Perhaps it's just a blind spot in the way
> > I think about types. Assuming that the limitations of your ORM are
> > external and out of your control, I would still ensure that whatever
> > generic objects are being loaded from the ORM are converted into
> > "real" objects of the correct type as soon as possible. For example,
> > if you're persisting a file, you might just save the filename, and
> > your ORM might return a string of the filename. I would want to
> > convert that back into a file object ASAP, rather than writing all my
> > code to accept either a FLO or a string and converting then.
> >
> > If you know what to upcast something to, then you know what type it
> > is. If you know what type it is, then (in Python) you can simply
> > assume it is of that type.
>
> Probably being more specific would help in this case ;-)
>
> What I'm doing is implementing an object-publishing mechanism in my
> template engine (Breve).  The type decision isn't known until the moment
> of rendering (i.e. in the template itself).  Say for instance a set of
> records is pulled from the ORM (SQLAlchemy in this case) and that these
> records represent articles in a blog.  These records, until they hit the
> template, have no real representation in HTML.  The decision about how
> to present them is up to the template.  The dispatch mechanism I
> referred to earlier is a way that I allow users of the template system
> to register how a particular object should be rendered in HTML (a
> "flattener").  This allows commonly represented objects to be used
> without a lot of template clutter.
> However, if you consider the case of a blog, then if the template
> receives a list of articles, it would seem reasonable to present those
> articles in at least two ways: first as a table of contents in the page
> gutter, and then perhaps as two or three summaries in the main part of
> the page.  But this isn't known to the lower layers of the application,
> only to the template.  Therefore it would be nice if the template user
> could register two classes with the flattener, both representations of
> the original object but simply with a different type.
>
> I'll give a concrete example:
>
> class Person: # assume this is something from the ORM
>     name = "Kenny"
>
> class PersonRow ( Person ):
>     pass
>
> def flatten_person ( p ):
>     return "<span>omg, you've killed %p</span>" % p.name
>
> def flatten_personrow ( p ):
>     return "<tr><td>%s</td></tr>" % p.name
>
> register_flattener ( PersonRow, flatten_personrow )
> register_flattener ( Person, flatten_person )
>
>
> Now, assuming a list of Person records were passed in as 'persons', then
> in the template the template author could simply use:
>
> div [
>     # show the first person
>     persons [ 0 ],
>
>     # show a table of all persons
>     table [
>         [ PersonRow ( p ) for p in persons ]
>     ]
> ]
>
>
> > What you're describing is a disjoint between your actual type system
> > (that is, the one you have in code) and your theoretical type system
> > (the one that you model your code around). To me, this is a huge red
> > warning flag.
>
> What I'm describing is a disjoint between how I want my template engine
> to be used (I tend to build backwards, writing the desired template code
> and then the engine code to support that use) and what can be easily and
> efficiently achieved.  But yes, in a way you are correct since my
> theoretical type system is constrained by Python's type system (Breve
> templates are Python expressions).
>
> That being said, I'm certain I'll come up with a solution that doesn't
> bug me too much, it's just that the "obvious" solution doesn't exist
> (type casting).
>

When I look at this, I don't see type casting as the obvious solution
- PersonRow isn't a subclass of Person, it's a subclass of Row. The
way you actually write it (constructing a PersonRow with a person) is
exactly how I would actually implement it though, except I wouldn't
see it as a "typecast" any more than I see creating a file object from
a filename as a typecast. I see it as a construction. I might
implement PersonRow as:

class PersonRow(Row):
    def __init__(person):
        self.person = person #assumed to be a Person object
    def flatten(self):
        return "<tr><td>%s></tr></td>" % self.person.name


Of course, when types are just callables that return instances the
distinction between construction and typecasting becomes purely
semantic. So the real confusion here may simply be how one refers to
an operation, rather than the operation itself.



More information about the Python-list mailing list