views:

286

answers:

3

To illustrate the question check the following code:

class MyDescriptor(object):
  def __get__(self, obj, type=None):
    print "get", self, obj, type
    return self._v
  def __set__(self, obj, value):
    self._v = value
    print "set", self, obj, value
    return None

class SomeClass1(object):
  m = MyDescriptor()

class SomeClass2(object):
  def __init__(self):
    self.m = MyDescriptor()

x1 = SomeClass1()
x2 = SomeClass2()

x1.m = 1000
# ->  set <__main__.MyDescriptor object at 0xb787c7ec> <__main__.SomeClass1 object at 0xb787cc8c> 10000
x2.m = 1000 # I guess that this overwrites the function. But why?
# ->
print x1.m
# -> get <__main__.MyDescriptor object at 0xb787c7ec> <__main__.SomeClass1 object at 0xb787cc8c> <class '__main__.SomeClass1'> 10000
print x2.m
# -> 10000
  1. Why doesn't x2.m = 1000 not call the __set__-function? It seems that this overwrites the function. But why?
  2. Where is _v in x1? It is not in x1._v
+3  A: 

To answer your second question, where is _v?

Your version of the descriptor keeps _v in the descriptor itself. Each instance of the descriptor (the class-level instance SomeClass1, and all of the object-level instances in objects of class SomeClass2 will have distinct values of _v.

Look at this version. This version updates the object associated with the descriptor. This means the object (SomeClass1 or x2) will contain the attribute _v.

class MyDescriptor(object):
  def __get__(self, obj, type=None):
    print "get", self, obj, type
    return obj._v
  def __set__(self, obj, value):
    obj._v = value
    print "set", self, obj, value
S.Lott
Thanks, that is a good idea to implement. One question to _v: I also couldn't access it via "MyDescriptor._v" - which is clear as it not a class attribute of MyDescriptor. But what is the explicit name of the instance? It should be accessible somehow, right?
Philipp der Rautenberg
You cannot access it, because it gets overwritten. In S.Lott case, you can access it via x._v
Sebastjan Trepča
ehh, sorry, x1._v
Sebastjan Trepča
Descriptor instances are HARD to access -- the point is that the containing class transparently calls their __set__ and __get__ functions for you. It never refers to the descriptor -- it calls the __set__ or __get__.
S.Lott
@Sebastjan Trepča: it's better to completely fix a comment by posting a new one and deleting the old comment. A sequence of comments is hard to read. But a new, complete comment is better.
S.Lott
+3  A: 

You should read this and this.

It overwrites the function because you didn't overload the __set__ and __get__ functions of SomeClass but of MyDescriptor class. Maybe you wanted for SomeClass to inherit MyDescriptor? SomeClass1 prints the "get" and "set" output because it's a static method AFAIK. For details read the upper links.

Sebastjan Trepča
A: 

I found _v of x1: It is in SomeClass1.__dict__['m']._v

For the version suggested by S.Lott within the other answer: _v is in x1._v

Philipp der Rautenberg