A better way of making subsclassing of built-in types stick for attributes?

telesphore4 at gmail.com telesphore4 at gmail.com
Wed May 17 06:17:12 CEST 2006


Is there a better way to make the subclassing of built-in types stick?

The goal is to have the the fields of a class behave like strings with
extra methods attached. That is, I want the fact that the fields are
not strings to be invisible to the client programmers. But I always
want the extras to be there for the clients too.

What I'm doing is subclassing str. Of course, whenever you then set
mystr = 'a string' you loose the extra goodies that I have attached in
the subclass. So, to get around this I set up __get__ers and __set__ers
for the fields.

The question is there a more succinct way to have the extended string
behavior stick than using descriptors?

Just to make things concrete here's some abbreviated sample code:

class Person(Table.Table):
     def __init__(self, tcs, gender=None, first=None, last=None,
status=None):
        self.gender = gender
        self.first  = first
        self.last   = last
        self.status = status

# Using mix-ins to get the desired behavior
class Gender(Field.InitAlways, Field.SqlVarchar):
    table    = ('F', 'M')
    fillNext = -1
    @classmethod
    def fill(cls, rec):
        cls.fillNext += 1
        return cls.table[cls.fillNext % 2]

#classes First, Last, & Status are analogous but more complicated

# The descriptors are set up at the bottom of the module like so:
Person.first  = Field.Descriptor(First)
Person.gender = Field.Descriptor(Gender)
Person.status = Field.Descriptor(Status)

# Moving along to other stripped supporting code

class Descriptor(object):
    def __init__(self, cls, name=None):
        self.cls = cls
        if name == None:
            self.name  = cls.__name__.lower()
        else:
            self.name = name.lower()

    def __set__(self, inst, value):
        if inst.__dict__.has_key(self.name):
            inst.__dict__[self.name] = self.cls(inst, value, True)
        else:
            inst.__dict__[self.name] = self.cls(inst, value, False)

class InitAlways(str):
    def __new__(cls, rec, value, reset):
        if reset:
            return str.__new__(cls, value)
        if value == Empty:
            return str.__new__(cls, '')
        if value == Fill or value == None: #if value in (None, Fill,
''):
            return str.__new__(cls, cls.fill(rec) or '')
        return str.__new__(cls, value or '')




More information about the Python-list mailing list