Background
I try to figure out Python descriptors by reading Lutz Learning Python in a section in which he says: "As properties, descriptors are designed to handle certain attributes ... Unlike properties, descriptors have their own state ..."
Throughout the chapter, he shows examples in which the managed attribute is actually hidden on the containing / wrapping object, as in:
def __set__(self, instance, value): instance._name = value.lower()
I understand these examples, and they seem to be common in write up on this topic. However, their superiority over properties is not obvious to me, and they do not seem to correspond to the internal state promised in the above quote.
At the end of the chapter, he shows an example that is closer to what I pictured after reading “to have my own state”, as in:
def __set__(self, instance, value): self.name = value.lower()
The example runs, but does not do what I expect from it. Since the example is a bit long, I put it on Pastebin and added the last line that shows unexpected behavior (Bob's name is now Sue). Here's a shorter snippet of the demo:
class Wrapper(object): class ExampleDescriptor(object): def __get__(self, instance, owner): print "get %s" % self.state return self.state def __set__(self, instance, value): print "set %s" % value self.state = value ex = ExampleDescriptor() w1 = Wrapper() w1.ex = 1 print w1.ex w2 = Wrapper() print w2.ex w2.ex = 2 print w1.ex print w1.ex is w2.ex
The output of which:
set 1 get 1 1 get 1 1 set 2 get 2 2 get 2 get 2 True
None of this execution comes as a surprise after carefully examining the code. The validation logic in the descriptor makes de facto singleton of this attribute in the wrapper class; however, it is difficult to imagine that this divided state is Lutz’s intention or intention in this widely related textbook .
Question
Is it possible to create a descriptor that has an internal state unique to the wrapper object without saving this state on instances of the wrapper object (as in the first fragment)? Is it possible to change the CardHolder class from a related example so that Bob doesn't end as Sue?