devin
devin

Reputation: 6527

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?

Upvotes: 1

Views: 409

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1122162

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.

Upvotes: 2

Related Questions