Inheritance question

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Yannick Turgeon

    #1

    Inheritance question

    Hello,

    Say I have a base class called "A"

    class A:
    _value
    __init__(self, value):
    self._value = value

    and two derived classes "B1" and "B2":

    class B1(A):
    def doPrint(self):
    print "B1: " + str(self._value )

    class B2(A):
    def doPrint(self):
    print "B2: " + str(self._value )


    is there a way that I could change my class A to something like:

    class A:
    _value
    __init__(self, value):
    self._value = value
    if value > 10:
    set myself as an instance of B1 # How can I do that?
    else:
    set myself as an instance of B2

    in the real situation "value" is encoded and the way to know what kind of A
    it is, is more complex than just look at the value.

    Thanks for your help and time.

    Yannick


  • Peter Otten

    #2
    Re: Inheritance question

    Yannick Turgeon wrote:
    [color=blue]
    > is there a way that I could change my class A to something like:
    >
    > class A:
    > _value
    > __init__(self, value):
    > self._value = value
    > if value > 10:
    > set myself as an instance of B1 # How can I do that?
    > else:
    > set myself as an instance of B2
    >
    > in the real situation "value" is encoded and the way to know what kind of
    > A it is, is more complex than just look at the value.[/color]

    [Requires newstyle classes]
    [color=blue][color=green][color=darkred]
    >>> class A(object):[/color][/color][/color]
    .... def __new__(cls, value):
    .... if value > 10:
    .... return super(cls, A).__new__(B1, value)
    .... else:
    .... return super(cls, A).__new__(B2, value)
    .... def __init__(self, value):
    .... self._value = value
    ....[color=blue][color=green][color=darkred]
    >>> class B1(A):[/color][/color][/color]
    .... def doPrint(self):
    .... print "B1:", self._value
    ....[color=blue][color=green][color=darkred]
    >>> class B2(A):[/color][/color][/color]
    .... def doPrint(self):
    .... print "B2:", self._value
    ....[color=blue][color=green][color=darkred]
    >>> A(1).doPrint()[/color][/color][/color]
    B2: 1[color=blue][color=green][color=darkred]
    >>> A(100).doPrint( )[/color][/color][/color]
    B1: 100

    You can do it, but it's certainly bad design because A has to know all its
    subclasses. If you go with the above I recommend that you use some kind of
    registry instead of hardcoding the subclasses in A.__new__().

    Peter

    Comment

    • Alex Martelli

      #3
      Re: Inheritance question

      Yannick Turgeon <nobody@nowhere .com> wrote:
      [color=blue]
      > class A:
      > _value
      > __init__(self, value):
      > self._value = value
      > if value > 10:
      > set myself as an instance of B1 # How can I do that?[/color]

      self.__class__ = B1

      Whether you WANT to do that is quite another issue: you most likely
      don't, though you wrongly believe you do. Use a factory-function
      pattern if you want to generate different possible classes, don't use
      black magic such as changing an instance's class on the fly unless there
      are _really good_ reasons (an example of a really good reason, IMHO, is
      given by a recipe in the Cookbook that presents a bounded-ring-buffer
      class... its instances commute from NotFull to Full classes once and for
      all when they switch from non-full to full, NOT at instance generation
      time...).


      Alex

      Comment

      • Yannick Turgeon

        #4
        Re: Inheritance question

        Hello,

        Thanks to reply. My question has been answered but I'm now wondering if I do
        this the best way.

        In the real situation I'm implementing a protocol. "A" represent a command.
        Say "0144AYHR78 " (encoded data) means "Add client Joe" and "0589UAWERT "
        means "Ship 3 compressors to Joe". What I want to do is to create a "A"
        instance which find the command type and parameters and "mutate" itself to
        the good command. All command parameters ("Joe" for the first one and
        "3,compressor,J oe" for the secondeone) are kept in a sigle list.So B1 and B2
        would define the function "getClient( )" and B2 would define "getQty()" and
        "getProduct ()" and some other command-specific work.

        while True:
        encoded_data = readEncodedData ()
        command = A(encoded_data)
        type_ = command .getType() # Define in "A"
        if type_ == A.ADD:
        # Do what I have to do with a "Add" command using the "command"
        instance (B1)
        elif type_ == A.SHIP:
        # Do what I have to do with a "Ship" command using the "command"
        instance (B2)
        ...

        Any suggestion to do this in a better way

        Yannick

        [color=blue]
        > You can do it, but it's certainly bad design because A has to know all its
        > subclasses. If you go with the above I recommend that you use some kind of
        > registry instead of hardcoding the subclasses in A.__new__().
        >
        > Peter
        >[/color]


        Comment

        • Peter Otten

          #5
          Re: Inheritance question

          Yannick Turgeon wrote:
          [color=blue]
          > Hello,
          >
          > Thanks to reply. My question has been answered but I'm now wondering if I
          > do this the best way.
          >
          > In the real situation I'm implementing a protocol. "A" represent a
          > command. Say "0144AYHR78 " (encoded data) means "Add client Joe" and
          > "0589UAWERT " means "Ship 3 compressors to Joe". What I want to do is to
          > create a "A" instance which find the command type and parameters and
          > "mutate" itself to the good command. All command parameters ("Joe" for the
          > first one and "3,compressor,J oe" for the secondeone) are kept in a sigle
          > list.So B1 and B2 would define the function "getClient( )" and B2 would
          > define "getQty()" and "getProduct ()" and some other command-specific work.
          >
          > while True:
          > encoded_data = readEncodedData ()
          > command = A(encoded_data)
          > type_ = command .getType() # Define in "A"
          > if type_ == A.ADD:
          > # Do what I have to do with a "Add" command using the "command"
          > instance (B1)
          > elif type_ == A.SHIP:
          > # Do what I have to do with a "Ship" command using the "command"
          > instance (B2)
          > ...
          >
          > Any suggestion to do this in a better way[/color]

          Here's how I would do it based on the above:

          class Ship:
          def __init__(self, args):
          """ knows how to decode args """
          self.quantity = # your code
          self.item = # your code
          self.client = # your code
          def execute(self):
          """ do what is necessary for shipment """

          class Add:
          def __init__(self, args):
          """ knows how to decode args """
          self.client = # your code
          def execute(self):
          """ add a client """

          commands = {
          "0144": Add, # assuming the first 4 chars encode the command
          "0589": Ship,
          }

          def decode(data):
          """ separate the command and its arguments,
          hopefully possible without having to know
          individual commands
          """
          return data[:4], data[4:] # may actually be more complicated

          while True:
          type_, args = decode(readEnco dedData())
          cmd = commands[type_](args)
          cmd.execute()

          Ship and Add may or may not share a common base class depending on whether
          you can factor out common functionality - e. g. a mixin that knows how
          decode the client, but you do not need to artificially introduce a common
          base class as a factory for the actual instances. Just make sure that
          __init__() takes a single argument and an execute() method taking no
          arguments is available.
          The client code (the while loop) is independent of the actual command, so
          ideally you just have to create a new class for a new command and enter it
          into the commands dictionary.

          Peter

          Comment

          • Alex Martelli

            #6
            Re: Inheritance question

            Yannick Turgeon <nobody@nowhere .com> wrote:
            ...[color=blue]
            > Say "0144AYHR78 " (encoded data) means "Add client Joe" and "0589UAWERT "
            > means "Ship 3 compressors to Joe". What I want to do is to create a "A"
            > instance which find the command type and parameters and "mutate" itself to
            > the good command. All command parameters ("Joe" for the first one and[/color]
            ...[color=blue]
            > Any suggestion to do this in a better way[/color]

            Yeah -- Peter Otten explained in more detail, but summing up: what you
            need is a Factory Design Pattern -- a function that takes the encoded
            data, decodes it, instantiates the appropriate class (probably based on
            a dict to map code->class) with the appropriate parameters. No reason
            whatsoever to have an instance mutate its own class in this case.


            Alex

            Comment

            Working...