erikbstack
erikbstack

Reputation: 13254

How to handle innerclass attribute dependencies?

In case you want to change other variables in a class on change of an attribute you simply just write a property for it. That works fine, if you have a simple data type. But if your variable contains a complex type like a list (not so untypical), the content itself can be changed without calling the variable.setter again.

Are there any callbacks or events that can be used to track changes to a list attribute of a class? What else can be done to keep the code clean and not destroy the inner functionality of the class?

Example:

class Accumulator(object)
  def __init__(self,all_things):
     # :param all_things: a list of stuff of any kind
     self.__all_things = all_things
  @property
  def all_things(self):
     return self.__all_things
  @all_things.setter
  def all_things(self,input):
      self.__all_things = input

Thinking outside the box is probably the solution. The priority is not to keep the class structure alive, but to find a pattern that works and allows a clean API!

Upvotes: 1

Views: 83

Answers (2)

erikbstack
erikbstack

Reputation: 13254

To allow discussion and increase creativity I want to offer the following solution myself:

class Accumulator(object):

    def __init__(self,all_things):
       #:param all_things: a sequence or generator of stuff of any kind
       self.__all_things = tuple(all_things)

    @property
    def all_things(self):
        return self.__all_things

    @property
    def all_things(self, all_things):
        self.__all_things = tuple(all_things)

It's clean, it's read-only and nothing can go wrong or be misused. Now the same assumption applies as in the question's structure: You need to reset it, if you want to change it. But you don't have to tell the user, because it's his only chance. If the user still wonders why, he can read the hopefully verbose class docstring.

Upvotes: 1

Martijn Pieters
Martijn Pieters

Reputation: 1122152

You would have to use a custom subclass of list to detect changes:

class MyList(list):
    on_change_callback = None

    def _notify(self):
        if self.on_change_callback is not None:
            self.on_change_callback(self)

    def __setitem__(self, index, value):
        super(MyList, self).__setitem__(self, index, value)
        self._notify()

    # Etc, each mutating method needs to be overridden.

You'd need to override each mutating method, call the original method (through super()), then call self._notify(). For a list of methods, see the Emulating container types section.

Upvotes: 2

Related Questions