How to set object parameters nicely?

Bruno Desthuilliers bruno.42.desthuilliers at websiteburo.invalid
Thu Dec 3 11:22:20 EST 2009


allen.fowler a écrit :
(snip)
> In this case, and I am trying to create a number of ORM-like objects.
> (Though, there is no database involved.)
> 
> So, instances of these classes are acting as records that are shuttled
> around in the system, and the object's properties are acting as
> values.  The parameters are (mostly) orthogonal, but do need defaults,
> and some must be required.

You could specify the names, defaults and validations required at an 
upper level then automate the whole thing, ie (thinking out loud):


class Field(object):
     def __init__(self, name,required=False,
                  default=None,target=None,validate=None):
         self._name = name
         self._required = required
         self._default = default
         self._target = target or name
         self._validate = validate or lambda x: x

     def validate(self, value):
         """ _validate is supposed to raise a ValueError if not ok.
             it can also do any required conversion, formatting etc
         """
         return self._validate(value)

     def set(self, instance, **kw):
         value = kw.get(self._name, None)
         if value is None
             if self.required:
                 raise ValueError("argument %s is required" % self._name)
             else:
                 value = self._default
         value = self.validate(value)
         setattr(instance, self._target, value)


class Record(object):
    def __init__(self, **kw):
        if not hasattr(self, "_fields"):
            raise AttributeError("Record subclasses must define _fields")
        for field in self._fields:
            field.set(self, **kw)

class Foo(Record):
     _fields = (
         Field("bar", True, validate=lambda v : v > 1),
         Field("baaz", default=42)
         )



NB : totally untested code, so it will of course contains at least one 
major and obvious bug / typo / whatever !-)

You could go further using an even more declarative API based on a fancy 
custom metaclass and descriptors (for Fields) etc etc - and that even 
might be the RightThing(tm) to do if you have more than moderatly 
complex needs, but for simple cases the above should work fine without 
going over the top with black magic.

HTH



More information about the Python-list mailing list