<div dir="ltr"><div>"""<br>Just for Fun<br><br>A quick sketch of a Descriptor construct.<br><br>A descriptor is a type instance with a<br>__get __ and __set__ protocol, also __delete__,<br>and designed to satisfy a common need to manage <br>
setting and getting with mediating methods.<br><br><a href="http://docs.python.org/3.4/howto/descriptor.html">http://docs.python.org/3.4/howto/descriptor.html</a><br><br>(cc) Kirby Urner, MIT License<br>O'Reilly School of Technology<br>
<br>"""<br><br>class Guardian:<br>    """<br>    Takes a field name and a function for screening<br>    out banned values for said field name<br>    """<br><br>    def __init__(self, fn, banned):<br>
        self.field = fn<br>        self.banned = banned<br><br>    def __set__(self, obj, val):<br>        # print("Setting {} on {}".format(self.field, obj))<br>        if self.banned(val):<br>            raise AttributeError("Can't be {}".format(val))<br>
        obj.__dict__[self.field] = val<br><br>    def __get__(self, obj, objtype):<br>        objtype.ringding()  # calls class method<br>        return obj.__dict__[self.field]<br><br>class Guest:<br><br>    # data descriptors<br>
    age  = Guardian("age",  banned = lambda a: a in range(1,21)) # 21 or older<br>    fave_color = Guardian("fave_color", banned = lambda c: c in ["Orange", "Black"])<br><br>    def __init__(self, n, age=0, fc=None):<br>
        <a href="http://self.name">self.name</a> = n<br>        # data descriptors always override instance dictionaries.<br>        self.age = age <br>        self.fave_color = fc<br><br>    @classmethod<br>    def ringding(cls):  # called by __get__ in data descriptors<br>
        print("Ring Ding!")<br><br>    def __repr__(self):<br>        return "Guest of name {}".format(<a href="http://self.name">self.name</a>)<br><br><br><br>t1 = Guest('Helga', 40)<br>t2 = Guest('Vlad', 30)<br>
<br>print("Age of t2:", t2.age)<br><br>try:<br>    t1.age = 11  # comes up against banned()<br>except AttributeError:<br>    print("No can do:  11")<br><br>try:<br>    t1.fave_color = "Orange"  # ditto banned()<br>
except AttributeError:<br>    print("No can do:  Orange")<br><br>t1.age = 22<br>t1.fave_color = "Green"<br><br></div># attributes stick to their respective instances if legal<br><div>print(t1.age)<br>print(t1.fave_color)<br>
print(t2.age)<br></div></div>