"casting" Python objects

David Bolen db3l at fitlinxx.com
Wed May 22 23:52:57 EDT 2002


"djw" <dwelch91 at attbi.com> writes:

> Hmmmm... I don't think I understand when you say "variable 'msg' has no
> type"...

It's best to think of the labels by which you reference objects as
themselves having no inherent types - they are just bound to point to
an object.  Now the objects themselves are strongly typed.

This differs from other languages (say, for example, C) where
declaring a variable represents actual storage and that variable
itself has a type.

> Here is my simple analogous example:
> 
> class a:
>     def a(self):
>         print "a"
> 
> class b(a):
>     def b(self):
>         print "b"
> 
> >>>x=a()  # analogous to jabber.Message
> >>>x.b() # analogous to FooMsg
> Traceback (most recent call last):
>   File "<interactive input>", line 1, in ?
> AttributeError: a instance has no attribute 'b'
> 
> To me, this clearly shows that 'x' is of type 'a', not of type 'b'. I agree
> that I can then easily do this:

No - I would suggest that 'x' has no type in this.  Yes, the object to
which the name 'x' is currently bound (which is an instance of class
'a' that you created by your call to a()) does have a type - and
strongly so.  The error message you are getting is complaining that
the object returned by a() - e.g., the "a instance" - doesn't have the
'b' attribute.

But to say that this means 'x' has a type is, to my mind, misleading
at best.

> >>> x=b()
> >>> x.b()
> b
> 
> So, yes, x can dynamically change types to another type, but it can only be
> _one_type_at_a_time! Right???

There's no changing of types going on.  Here you just make the name
'x' reference or point to a different object.  The fact that the new
object has a different type than the previous object that x referenced
is true, but those are facts about the objects (which never change
types) and not the name by which you happen to refer to an object.

It may seem a nit, but it really gets to the root of how objects work
in Python and name bindings, and name spaces and so on, and thinking
about it as if the labels you are using have types associated with
them can make things more confusing down the road.

> In my original post, the Queue was put() with types of jabber.Message. When
> you get() them from the Queue, they come off as type jabber.Message. In
> order to call a FooMsg method on a message, their type must somehow be
> changed to type FooMsg (or something like that).

But that doesn't make much sense.  Whatever object you put() into the
queue is a particular object type, and that is regardless of what name
you may use to reference the object.  That object type is unchanged
when you retrieve them from the queue and can not be changed, again
regardless of what sort of name you may use when retrieving the
object.

If the object you put/get from the queue is a jabber.Message, it's
non-sensical to talk about treating it like FooMsg (unless FooMsg is a
parent class of jabber.Message) since by definition that's not the
type of object it is.

> So, to continue my above example:
> 
> >>> import Queue
> >>> q = Queue:Queue()
> >>> x=a()
> >>> q.put(x)
> >>> y=q.get()
> >>> y.b()
> Traceback (most recent call last):
>   File "<interactive input>", line 1, in ?
> AttributeError: a instance has no attribute 'b'
> 
> Fails because 'y' is of type 'a' not of type 'b'

No it fails because the 'a instance' object (which was put into the
queue and then retrieved) doesn't have a method 'b'.  Neither the
labels 'x' nor 'y' really come into it as far as what it wrong
underneath the covers.


But I think that's moot for your underlying question.  You seem to
want to take an object of class A (jabber.Message) and call a method
that belongs to a subclass of A (FooMsg) even though all you have is
an instance of the parent class A.  But by definition, while a
subclass has access to the methods of its parent classes, a parent
class object knows nothing about possible subclass methods - they
don't and can't even exist in an object of the parent class.  Basic
inheritance.

If you knew that the instance data was compatible between the two
object types you could do some meta-class hacking (e.g., assigning to
__class__) to try to get Python to call a different set of class
methods for the object instance, but I really don't think that's
appropriate for something like this.

The right approach is to create the appropriate subclass of
jabber.Message before putting it into the queue.  Your retrieval code
won't have to worry which subclass it is, since they'll all have the
Handler function and will be dispatched appropriately.  So from the
info in your original post, it sounds like your connection object is
the one that should be determining what sort of object instance to
create (e.g., FooMsg) and creating an instance of that to post to the
queue rather than jabber.Message.

--
-- David
-- 
/-----------------------------------------------------------------------\
 \               David Bolen            \   E-mail: db3l at fitlinxx.com  /
  |             FitLinxx, Inc.            \  Phone: (203) 708-5192    |
 /  860 Canal Street, Stamford, CT  06902   \  Fax: (203) 316-5150     \
\-----------------------------------------------------------------------/



More information about the Python-list mailing list