2

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
Philipp der Rautenberg
  • 2,212
  • 3
  • 25
  • 39

3 Answers3

3

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
  • 384,516
  • 81
  • 508
  • 779
  • 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 Jan 09 '09 at 15:12
  • You cannot access it, because it gets overwritten. In S.Lott case, you can access it via x._v – Seb Jan 09 '09 at 15:26
  • 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 Jan 09 '09 at 15:28
  • @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 Jan 09 '09 at 15:29
3

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.

Esteban Küber
  • 36,388
  • 15
  • 79
  • 97
Seb
  • 17,141
  • 7
  • 38
  • 27
0

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
  • 2,212
  • 3
  • 25
  • 39