def add_field(self, attrname, fn, default=None):
        """Computes a new attribute for each object in table, or replaces an
           existing attribute in each record with a computed value
           @param attrname: attribute to compute for each object
           @type attrname: string
           @param fn: function used to compute new attribute value, based on 
           other values in the object, as in::
               
               lambda ob : ob.commission_pct/100.0 * ob.gross_sales
               
           @type fn: function(obj) returns value
           @param default: value to use if an exception is raised while trying
           to evaluate fn
           """
        # for rec in self:
        def _add_field_to_rec(rec_, fn_=fn, default_=default):
            try:
                val = fn_(rec_)
            except Exception:
                val = default_
            if isinstance(rec_, DataObject):
                rec_.__dict__[attrname] = val
            else:
                setattr(rec_, attrname, val)
        try:
            do_all(_add_field_to_rec(r) for r in self)
        except AttributeError:
            raise AttributeError("cannot add/modify attribute {!r} in table records".format(attrname))
        return self
Computes a new attribute for each object in table, or replaces an
           existing attribute in each record with a computed value
           @param attrname: attribute to compute for each object
           @type attrname: string
           @param fn: function used to compute new attribute value, based on 
           other values in the object, as in::
               
               lambda ob : ob.commission_pct/100.0 * ob.gross_sales
               
           @type fn: function(obj) returns value
           @param default: value to use if an exception is raised while trying
           to evaluate fn