conditional __init__

Discussion in 'Python' started by King, Nov 2, 2009.

  1. King

    King Guest

    class A(object):
    def __init__(self):
    pass
    def printme(self):
    print "I am A"

    class B(object):
    def __init__(self):
    pass
    def printme(self):
    print "I am B"

    class K(A, B):
    def __init__(self, value=0):
    if value == 0:
    A.__init__(self)
    print "__init__ A"
    elif value == 1:
    B.__init__(self)
    print "__init__ B"
    self.printme()

    o = K(value=1)

    Output
    >>__init__ B
    >>I am A


    In above code "B" is correctly getting initialized as per condition.
    How ever method "printme" is printing "I am A".
    Instead it has to print "I am B" because "B" is the one that has been
    initialized. What's wrong here?

    Is there a better/another way to do conditional initialization as
    needed above?

    Cheers

    Prashant
    Python 2.6.2
    Win XP 32
    King, Nov 2, 2009
    #1
    1. Advertising

  2. King

    Chris Rebert Guest

    On Mon, Nov 2, 2009 at 12:40 PM, King <> wrote:
    > class A(object):
    >    def __init__(self):
    >        pass
    >    def printme(self):
    >        print "I am A"
    >
    > class B(object):
    >    def __init__(self):
    >        pass
    >    def printme(self):
    >        print "I am B"
    >
    > class K(A, B):
    >    def __init__(self, value=0):
    >        if value == 0:
    >            A.__init__(self)
    >            print "__init__ A"
    >        elif value == 1:
    >            B.__init__(self)
    >            print "__init__ B"
    >        self.printme()
    >
    > o = K(value=1)
    >
    > Output
    >>>__init__ B
    >>>I am A

    >
    > In above code "B" is correctly getting initialized as per condition.
    > How ever method "printme" is printing "I am A".
    > Instead it has to print "I am B" because "B" is the one that has been
    > initialized. What's wrong here?
    >
    > Is there a better/another way to do conditional initialization as
    > needed above?


    Which initializers are called *has no effect* on what order base
    classes are consulted in when looking up methods. To change the lookup
    order, you need to change the order of the base classes in the class
    statement.

    Your problem could be fixed by:

    1. Changing the code so the initializers do have an effect through
    what they initialize instance variables to;
    class A(object):
    def __init__(self):
    self.name = "A"
    def printme(self):
    print "I am", self.name

    class B(object):
    def __init__(self):
    self.name = "B"
    def printme(self):
    print "I am", self.name

    2. Use a factory function to return an instance of the proper class:

    class K1(A, B):
    pass

    class K2(B, A):
    pass

    def newK(value):
    if value == 0:
    return K1()
    elif value == 1:
    return K2()

    Cheers,
    Chris
    --
    http://blog.rebertia.com
    Chris Rebert, Nov 2, 2009
    #2
    1. Advertising

  3. King wrote:

    > class A(object):
    > def __init__(self):
    > pass
    > def printme(self):
    > print "I am A"
    >
    > class B(object):
    > def __init__(self):
    > pass
    > def printme(self):
    > print "I am B"
    >
    > class K(A, B):
    > def __init__(self, value=0):
    > if value == 0:
    > A.__init__(self)
    > print "__init__ A"
    > elif value == 1:
    > B.__init__(self)
    > print "__init__ B"
    > self.printme()
    >
    > o = K(value=1)
    >
    > Output
    >>>__init__ B
    >>>I am A

    >
    > In above code "B" is correctly getting initialized as per condition.
    > How ever method "printme" is printing "I am A".
    > Instead it has to print "I am B" because "B" is the one that has been
    > initialized. What's wrong here?


    It prints "I am A" because K inherits from A before B. Your
    __init__ methods don't do anything, so it doesn't matter which one you
    call. You seem to be thinking that running __init__ magically
    determines the class of the object, but it doesn't; it's just code that
    runs when the object is first created. When you do self.printme(), it
    decides to use A.printme because you did "class K(A, B)". If you do
    class K(B, A)" it will use B.printme.

    I imagine it's possible to do fiendish things and try to choose the
    superclass inheritance order at runtime, but you should be wary of this.
    In your example, why don't you just have K override printme and dispatch
    to A or B depending on "value"?

    --
    --OKB (not okblacke)
    Brendan Barnwell
    "Do not follow where the path may lead. Go, instead, where there is
    no path, and leave a trail."
    --author unknown
    OKB (not okblacke), Nov 2, 2009
    #3
  4. King

    Carl Banks Guest

    On Nov 2, 11:40 am, King <> wrote:
    > class A(object):
    >     def __init__(self):
    >         pass
    >     def printme(self):
    >         print "I am A"
    >
    > class B(object):
    >     def __init__(self):
    >         pass
    >     def printme(self):
    >         print "I am B"
    >
    > class K(A, B):
    >     def __init__(self, value=0):
    >         if value == 0:
    >             A.__init__(self)
    >             print "__init__ A"
    >         elif value == 1:
    >             B.__init__(self)
    >             print "__init__ B"
    >         self.printme()
    >
    > o = K(value=1)
    >
    > Output
    >
    > >>__init__ B
    > >>I am A

    >
    > In above code "B" is correctly getting initialized as per condition.
    > How ever method "printme" is printing "I am A".
    > Instead it has to print "I am B" because "B" is the one that has been
    > initialized. What's wrong here?


    What's wrong is that you have a fundamental misunderstanding of what's
    happening. You can't just shut off a subclass by refusing to
    initialize it--just doesn't work that way. All subclasses will
    continue to be active whether you call __init__ on them or not.
    Therefore when you call self.printme() it searches the base classes in
    order, and the first one it finds is A, so it always calls A's
    printme.

    It seems to me that you haven't learned enough about how inheritance
    works in Python to use multiple inheritance yet, so I would suggest
    just sticking to single inheritance for now, and study up.


    > Is there a better/another way to do conditional initialization as
    > needed above?


    The fact that you feel the need to do this suggests that you want a
    composition relationship, not an inheritance one. What you appear to
    be doing is defining a sort of "plugin", you have an object that can
    behave one way (A) or another (B), but which one isn't known till run
    time. In that case the A or B object should be made an attribute of
    the K object:

    class A(object):
    def printme(self):
    print "I am A"

    class B(object):
    def printme(self):
    print "I am B"

    class K(object):
    def __init__(self, value=0):
    if value == 0:
    self.plugin = A()
    print "__init__ A"
    elif value == 1:
    self.plugin = B()
    print "__init__ B"
    self.plugin.printme()


    Without seeing more of your code I strongly suspect that this change
    better reflects what you're trying to do.


    Carl Banks
    Carl Banks, Nov 2, 2009
    #4
    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. Alec S.
    Replies:
    10
    Views:
    10,147
    Alec S.
    Apr 16, 2005
  2. Alexander Eberts
    Replies:
    3
    Views:
    322
    Ulrich Petri
    Jul 15, 2003
  3. Steven Bethard
    Replies:
    2
    Views:
    456
    Steven Bethard
    Feb 16, 2005
  4. Kent Johnson
    Replies:
    7
    Views:
    914
    Jan Niklas Fingerle
    Feb 12, 2006
  5. Ramchandra Apte
    Replies:
    17
    Views:
    338
    Manuel Pégourié-Gonnard
    Sep 30, 2012
Loading...

Share This Page