downcasting problem

Discussion in 'Python' started by Nikola Skoric, Oct 25, 2010.

  1. Hi everybody,

    I need to downcast an object, and I've read repeatedly that if you
    need to downcast, you did something wrong in the design phase. So,
    instead of asking how do you downcast in python, let me explain my
    situation.

    I have a 2-pass parser. 1st pass ends up with a bunch of superclass
    object, and 2nd pass is supposed to downcast those to one of
    subclasses so I can work with them.

    Details:

    I have a file full of lines which I parse into Line objects. I also
    have two subclasses of Line, namely Individual and Family. Constructor
    of both subclasses needs all Line objects in the file to be
    constructed, so I cannot construct subclass objects in the first pass.

    The Python way of doing this (as I understand it) would be to wrap a
    subclass around Line and have the Line object as an attribute of a
    subclass. Now, this obviously breaks polymorphism and I now have to
    reimplement all of Line's classes in subclasses. Although
    reimplementation is simple (def method(self): return
    self.line.method()), that way of doing things is just not elegant.

    So, is there any more elegant solution to my problem?

    Thanks in advance.

    --
    "Now the storm has passed over me
    I'm left to drift on a dead calm sea
    And watch her forever through the cracks in the beams
    Nailed across the doorways of the bedrooms of my dreams"
     
    Nikola Skoric, Oct 25, 2010
    #1
    1. Advertising

  2. Nikola Skoric

    Tim Chase Guest

    While a dirty hack for which I'd tend to smack anybody who used
    it...you *can* assign to instance.__class__

    >>> class A:

    .... def __init__(self, name):
    .... self.name = name
    .... def __str__(self): return self.name
    ....
    >>> class B(A):

    .... def foo(self): print "I'm B: %r" % self.name
    ....
    >>> class C(A):

    .... def foo(self): print "I'm C: %r" % self.name
    ....
    >>> a = A("Alpha")
    >>> print a

    Alpha
    >>> a.__class__

    <class __main__.A at 0xb752d6bc>
    >>> a.__class__ = B
    >>> a.foo()

    I'm B: 'Alpha'
    >>> a.__class__ = C
    >>> a.foo()

    I'm C: 'Alpha'


    If it breaks you get to keep all the parts :)

    -tkc
     
    Tim Chase, Oct 25, 2010
    #2
    1. Advertising

  3. Dana Mon, 25 Oct 2010 09:38:42 -0500,
    Tim Chase <> kaze:
    > While a dirty hack for which I'd tend to smack anybody who used
    > it...you *can* assign to instance.__class__


    Wow! Python never stops to amaze me.

    > If it breaks you get to keep all the parts :)


    Yes, I can see great potential for shit hitting the fan here.

    Thanks for the tip!

    --
    "Now the storm has passed over me
    I'm left to drift on a dead calm sea
    And watch her forever through the cracks in the beams
    Nailed across the doorways of the bedrooms of my dreams"
     
    Nikola Skoric, Oct 25, 2010
    #3
  4. Nikola Skoric

    John Nagle Guest

    On 10/25/2010 7:38 AM, Tim Chase wrote:
    > While a dirty hack for which I'd tend to smack anybody who used it...you
    > *can* assign to instance.__class__


    That's an implementation detail of CPython. May not work in
    IronPython, Unladen Swallow, PyPy, or Shed Skin.

    (An implementation with a JIT has to trap stores into some
    internal variables and invalidate the generated code.
    This adds considerable complexity to the virtual machine.
    Java JVMs, for example, don't have to support that.)

    John Nagle
     
    John Nagle, Oct 25, 2010
    #4
  5. > Hi everybody,
    >
    > I need to downcast an object, and I've read repeatedly that if you
    > need to downcast, you did something wrong in the design phase. So,
    > instead of asking how do you downcast in python, let me explain my
    > situation.
    >
    > I have a 2-pass parser. 1st pass ends up with a bunch of superclass
    > object, and 2nd pass is supposed to downcast those to one of
    > subclasses so I can work with them.
    >
    > Details:
    >
    > I have a file full of lines which I parse into Line objects. I also
    > have two subclasses of Line, namely Individual and Family. Constructor
    > of both subclasses needs all Line objects in the file to be
    > constructed, so I cannot construct subclass objects in the first pass.
    >
    > The Python way of doing this (as I understand it) would be to wrap a
    > subclass around Line and have the Line object as an attribute of a
    > subclass. Now, this obviously breaks polymorphism and I now have to
    > reimplement all of Line's classes in subclasses. Although
    > reimplementation is simple (def method(self): return
    > self.line.method()), that way of doing things is just not elegant.


    > So, is there any more elegant solution to my problem?


    Why not have an abstract Line class with your Line methods, a SimpleLine (your
    current Line class, extends AbstractLine), and IndividualLine and FamilyLine
    (both extending AbstractLine)?

    Cheers,

    Emm
     
    Emmanuel Surleau, Oct 25, 2010
    #5
  6. Nikola Skoric <> writes:

    > Hi everybody,
    >
    > I need to downcast an object, and I've read repeatedly that if you
    > need to downcast, you did something wrong in the design phase. So,
    > instead of asking how do you downcast in python, let me explain my
    > situation.
    >
    > I have a 2-pass parser. 1st pass ends up with a bunch of superclass
    > object, and 2nd pass is supposed to downcast those to one of
    > subclasses so I can work with them.


    This is usually called a 'reducer' in parsing, and it's purpose is to
    rewrite the parsing result to something new.

    It's usually implemented using a visitor-pattern.

    In your case, it should be rather straightforward, by simply iterating
    over the objects and creating new, more specialized types depending on
    what you actually need.

    So you don't need to delegate anything.

    Diez
     
    Diez B. Roggisch, Oct 25, 2010
    #6
  7. Nikola Skoric

    Tim Chase Guest

    On 10/25/2010 12:56 PM, John Nagle wrote:
    > On 10/25/2010 7:38 AM, Tim Chase wrote:
    >> While a dirty hack for which I'd tend to smack anybody who used it...you
    >> *can* assign to instance.__class__

    >
    > That's an implementation detail of CPython. May not work in
    > IronPython, Unladen Swallow, PyPy, or Shed Skin.


    Curious by your claim, could you confirm this someplace in the
    docs? From my reading of [1]'s "If x is an instance of a
    new-style class, then type(x) is typically the same as
    x.__class__ (although this is not guaranteed - a new-style class
    instance is permitted to override the value returned for
    x.__class__)" is that this can be overridden (the definition of
    "overridden" however may mean different things to different
    people) and [2] refers to "__class__ assignment works only if
    both classes have the same __slots__" (that seems pretty clear
    that __class__ assignment is permissible)

    -tkc


    [1]
    http://docs.python.org/reference/datamodel.html#new-style-and-classic-classes

    [2]
    http://docs.python.org/reference/datamodel.html#__slots__
     
    Tim Chase, Oct 26, 2010
    #7
  8. John Nagle <> writes:

    > On 10/25/2010 7:38 AM, Tim Chase wrote:
    >> While a dirty hack for which I'd tend to smack anybody who used it...you
    >> *can* assign to instance.__class__

    >
    > That's an implementation detail of CPython. May not work in
    > IronPython, Unladen Swallow, PyPy, or Shed Skin.
    >
    > (An implementation with a JIT has to trap stores into some
    > internal variables and invalidate the generated code.
    > This adds considerable complexity to the virtual machine.
    > Java JVMs, for example, don't have to support that.)


    A Python implementation probably looks up attributes via type late at
    runtime anyway, so modifying __class__ boils down to changing a
    reference inside the (moral equivalent of the) PyObject structure.

    For example, assigning to __class__ appears to work just fine in Jython
    2.5.2:

    Jython 2.5.2rc2 (Release_2_5_2rc2:7167, Oct 24 2010, 22:48:30)
    [OpenJDK 64-Bit Server VM (Sun Microsystems Inc.)] on java1.6.0_18
    Type "help", "copyright", "credits" or "license" for more information.
    >>> class X(object):

    .... pass
    ....
    >>> class Y(X): pass

    ....
    >>> x = X()
    >>> x.__class__ = Y
    >>> x

    <__main__.Y object at 0x3>
     
    Hrvoje Niksic, Oct 26, 2010
    #8
  9. In message <ia42sr$e73$>, Nikola Skoric wrote:

    > I have a file full of lines which I parse into Line objects. I also
    > have two subclasses of Line, namely Individual and Family. Constructor
    > of both subclasses needs all Line objects in the file to be
    > constructed, so I cannot construct subclass objects in the first pass.


    Circularity of reference which does not fit into the object-oriented
    insistence on a hierarchy. So the only way around it is to introduce more
    layers of complications which get you further way from solving the original
    problem.

    Tell me again, what relevance OO has to the real world?
     
    Lawrence D'Oliveiro, Oct 30, 2010
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?Sm9l?=

    Upcasting/ Downcasting in VB.NET?

    =?Utf-8?B?Sm9l?=, Nov 14, 2005, in forum: ASP .Net
    Replies:
    3
    Views:
    4,869
    John Murray
    Nov 14, 2005
  2. Downcasting problem

    , Mar 17, 2006, in forum: Java
    Replies:
    4
    Views:
    10,914
    tom fredriksen
    Mar 17, 2006
  3. Stuart Golodetz
    Replies:
    6
    Views:
    467
    Chris \( Val \)
    Aug 30, 2003
  4. Michael
    Replies:
    2
    Views:
    467
    Michael
    Oct 16, 2004
  5. Random

    CType and downcasting classes

    Random, Dec 27, 2006, in forum: ASP .Net
    Replies:
    2
    Views:
    467
    Random
    Dec 28, 2006
Loading...

Share This Page