devin devin - 1 month ago 8
Python Question

Adding a descriptor to a Python subclass

I have a python class that inherits a priority queue and I also use a descriptor to add an attribute to the class, like this:

from Queue import PriorityQueue
class My_Class(PriorityQueue):
my_attr = NonNegativeInt(0)

def __init__(self):
PriorityQueue.__init__(self)


The descriptor is implemented like this:

class NonNegativeInt(object):
def __init__(self, default):
self.default = default
self.data = WeakKeyDictionary()

def __get__(self, instance, owner):
return self.data.get(instance, self.default)

def __set__(self, instance, value):

if type(value) is not int:
raise TypeError('Value must be an int')

if value < 0:
raise ValueError("Value must be above 0")

self.data[instance] = value


When I call
My_Class.my_attr = -1
I don't get any exception. However, if I change
My_Class
to this I get the exception fine:

class My_Class(object):
my_attr = NonNegativeInt(0)

def __init__(self):
pass


Interestingly, the first implementation of
My_Class
starts with the
my_attr
attribute, it just doesn't execute the
__set__
function in
NonNegativeInt
.

Why is it that changing the superclass changes how my descriptor works? Does it have to do with this line:
PriorityQueue.__init__(self)
? How can I give the subclass the behavior I want?

Answer

Descriptors only work on new-style classes (those that directly or indirectly inherit from object). There is some support for descriptor __get__ methods on old-style classes but this support is limited.

The PriorityQueue class you are using probably doesn't inherit from object. If this is the Queue.PriorityQueue class then that's certainly the case, the classes in that module are all old-style.

The fact that you call PriorityQueue.__init__ has nothing to do with this.