Inheritance question

Y

Yannick Turgeon

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
 
P

Peter Otten

Yannick said:
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.

[Requires newstyle classes]
.... 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
........ def doPrint(self):
.... print "B1:", self._value
........ def doPrint(self):
.... print "B2:", self._value
....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
 
A

Alex Martelli

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

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
 
Y

Yannick Turgeon

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,Joe" 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
 
P

Peter Otten

Yannick said:
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,Joe" 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

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(readEncodedData())
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
 
A

Alex Martelli

Yannick Turgeon said:
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 ...
Any suggestion to do this in a better way

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
 
Y

Yannick Turgeon

Thanks Peter for you help and time. Everything is in this:
while True:
type_, args = decode(readEncodedData())
cmd = commands[type_](args)
cmd.execute()

I already changed the way I do this.

Yannick
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,206
Messages
2,571,069
Members
47,678
Latest member
Aniruddha Das

Latest Threads

Top