Creating new instances of subclasses.

Terry Reedy tjreedy at udel.edu
Wed Jan 7 19:11:09 CET 2009


J. Cliff Dyer wrote:
> I want to be able to create an object of a certain subclass, depending
> on the argument given to the class constructor.
> 
> I have three fields, and one might need to be a StringField, one an
> IntegerField, and the last a ListField.  But I'd like my class to
> delegate to the proper subclass automatically, so I can just do:
> 
>>>> f1 = Field('abc')
>>>> f2 = Field('123')
>>>> f3 = Field('D,E,F')
>>>> f1.data
> 'abc'
>>>> f2.data
> 123
>>>> f3.data
> ['D','E','F']
>>>> type(f1)
> <class '__main__.StringField'>
>>>> type(f2)
> <class '__main__.StringField'>
>>>> type(f3)
> <class '__main__.ListField'>
> 
> I've come up with a solution, but I suspect there's something cleaner

Make your master class _Field and make Field a factory function that 
returns the proper subclass instance.  The body of Field could be the 
body of __new__ below.  Then dump the __new__ methods.

tjr


  I
> can do with the inheritance structure of __new__.  I don't like
> explicitly leapfrogging over Field.__new__ to object.__new__.
> 
> My attempt is below:
> 
> def is_list(arg):
>     if ',' in arg:  return True
>     else:  return False
> 
> def is_integer(arg):
>     try:  int(arg)
>     except ValueError:  return False
>     else:  return True
> 
> class Field(object):
>     def __new__(cls, a):
>         if is_list(a):
>             return ListField(a)
>         elif is_integer(a):
>             return IntegerField(a)
>         else:
>             return StringField(a)
>     
>     def __init__(self, input):
>         super(Field, self).__init__(input)
>         self.data = input
> 
> class IntegerField(Field):
>     def __new__(cls, a):
>         return object.__new__(cls, a)
>     def __init__(self, s):
>         super(IntegerField, self).__init__(s)
>         self.s = int(self.s)
>     
> class ListField(Field):
>     def __new__(cls, a):
>         return object.__new__(cls, a)
>     def __init__(self, s):
>         super(ListField, self).__init__(s)
>         self.s = s.split(',')
> 
> class StringField(Field):
>     def __new__(cls, a):
>         return object.__new__(cls, a)
> 
> Is there a cleaner way to do this?  The main problem is that
> Field.__new__ gets in the way of properly constructing the subclasses
> once I've used it to select the proper subclass in the first place.
> 
> Cheers,
> Cliff
> 




More information about the Python-list mailing list