Type casting a base class to a derived one?

Cliff Wells cliff at develix.com
Wed Jan 24 20:37:58 CET 2007

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 ):

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).

> I'm arguing against the idea that it makes sense, in Python, to
> upcast.

I think it's definitely a corner-case, but I'd be reluctant to claim it
would never be of use.

> I agree, but without a use case it's hard to understand the limits and
> needs of a requirement. So if you can't think of a need for a feature,
> it becomes difficult to understand how you might implement that
> feature.

Certainly.  Several years of using Python has never suggested a use to
me prior to this.


More information about the Python-list mailing list