<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>