How can we write a class factory that dynamically redefines the __init__ function etc.
Gabriel Genellina
gagsl-py2 at yahoo.com.ar
Tue May 6 01:14:48 EDT 2008
En Mon, 05 May 2008 20:34:32 -0300, John Schroeder <jschroed at gmail.com>
escribió:
> Basically I have some classes like this:
>
>
> ###############################################################################
> # 0x01: ModeCommand
> ###############################################################################
> class ModeCommand:
> """This is the Mode Command Packet class."""
> def __init__(self, mode, command, id=0x01):
> """The unspecial init function."""
> self.mode = mode
> self.command = command
> self.id = id
>
> def RawData(self):
> return [self.id, self.mode, self.command]
>
> def __getitem__(self, index):
> """[] operator (read): indexes from the byte data."""
> return self.RawData()[index]
>
> def __str__(self):
> """Print a nice thing."""
> string = "Mode = %d\n" % self.mode + \
> "Command = %d\n" % self.command + \
> "ID = %d\n\n" % self.id
> return string
>
> ###############################################################################
> # 0x02: CallRequest
> ###############################################################################
> class CallRequest:
> """This is the Call Request Packet class. (Look familiar?)"""
> def __init__(self, service_number, id=0x02):
> """The unspecial init function."""
> self.service_number = service_number
> self.id = id
>
> def RawData(self):
> return [self.id, self.service_number]
>
> def __getitem__(self, index):
> """[] operator (read): indexes from the byte data."""
> return self.RawData()[index]
>
> def __str__(self):
> """Print a nice thing."""
> string = "Service Number = %d\n" % self.service_number + \
> "ID = %d\n\n" % self.id
> return string
>
>
> ###############################################################################
> # Test Code
> ###############################################################################
> x = ModeCommand(mode=1, command=0)
> print x[:]
> print x
> y = CallRequest(service_number=2001)
> print y[:]
> print y
>
>
> Which is ok but I had to do this over 100 times. It is difficult to
> maintain and no one else can understand what the heck I did here. So I
> was
> trying to look a metaclasses to do something fancy like this:
You don't need a metaclass, nor a class factory. You only need a base
class.
__getitem__ is the same on both classes, and presumably on all: move it to
the base class.
And the only difference between both versions of __init__, RawData and
__str__ is the name and order of the attributes: let's make them a
parameter, a class attribute. The default id attribute may be a class
attribute too.
So in principle, if you have the right base class, the subclasses could be
defined as simply as:
class ModeCommand(Base):
"""This is the Mode Command Packet class."""
parameters = "mode command id".split()
id = 0x01
class CallRequest(Base):
"""This is the Call Request Packet class. (Look familiar?)"""
parameters = "service_number id".split()
id = 0x02
and that's all. Now we have to write the Base class:
class Base(object):
parameters = None # redefined in all subclasses
id = None
def __init__(self, **kw):
assert self.parameters is not None # must be redefined
for name in kw:
if name in self.parameters:
setattr(self, name, kw[name])
else:
raise NameError, "unknown parameter: %s" % name
assert self.id is not None # must be redefined
def RawData(self):
return [getattr(self, name) for name in self.parameters]
def __getitem__(self, index):
return self.RawData()[index]
def __str__(self):
return '\n'.join(
["%s = %r" % (name, getattr(self, name))
for name in self.parameters])
py> x = ModeCommand(mode=1, command=0)
py> print x[:]
[1, 0, 1]
py> print x
mode = 1
command = 0
id = 1
py> y = CallRequest(service_number=2001, id=13)
py> print y[:]
[2001, 13]
py> print y
service_number = 2001
id = 13
(the convention is to use lowercase names for attributes: rawdata instead
of RawData)
--
Gabriel Genellina
More information about the Python-list
mailing list