2

I want to create a list of class instances that automatically updates itself following a particular condition on the instance attributes.

For example, I have a list of object of my custom class Person() and I want to be able to generate a list that always contains all the married persons, i.e. all persons having the attribute 'MAR_STATUS' equal to 'MARRIED'.

Is this possible at all in Python? I have used a C++ precompiler for microsimulations that had a very handy built-in called "actor_set" which did exactly this. But I have no idea of how it was implemented in C++.

Thank you.

Wilco
  • 429
  • 2
  • 5
  • 13

3 Answers3

4

List comprehension:

[person for person in people if person.MAR_STATUS == 'MARRIED']

If you need to assign it to a variable and you want that variable to automatically update on every access, you can put this same code in a lambda, a normal function, or, if your variable is a class member, in a property getter.

Silas Ray
  • 25,682
  • 5
  • 48
  • 63
2

It is poor form to have "action at a distance" / mutations / side-effects unless it is very carefully controlled.

That said, imperative language will let you do this, if you really want to, as follows. Here we use python's [property getters and setters]:

MARRIED_SET = set()
def updateMarriedSet(changedPerson):
    if hasattr(changedPerson,'married') and changedPerson.married==Person.MARRIED:
        MARRIED_SET.add(changedPerson)
    else:
        MARRIED_SET.discard(changedPerson)

class Person(object):
    ...

    @property
    def married(self):
        """The person is married"""
        return self._married

    @married.setter
    def married(self, newStatus):
        self._married = newStatus
        updateMarriedSet(self)

    @married.deleter
    def married(self):
        del self._married
        updateMarriedSet(self)

I can imagine this might, possibly, be useful to ensure accesses to getMarriedPeople() runs in O(1) time rather than amortized O(1) time.

ninjagecko
  • 88,546
  • 24
  • 137
  • 145
  • You could use a set to insert and remove people when married changes, instead of just marking them in the dictionary, and there you have the O(1) sequence of married people for the same effort. – Alejandro Piad May 22 '12 at 16:09
  • @AlejandroPiad: I am not sure what you are suggesting; it was already O(1). Unless you are referring to the fact that the OP wanted a list (rather than a set/dict; both of which are more reasonable than a list). Anyway I've modified it a little. – ninjagecko May 22 '12 at 16:18
  • What I was referring to is that although updating the dict is O(1) every time, the dict contains all persons, not just married. Iterating only over the married people, which is what I suppose he wants to do, requires iterating over all the people. Your new edit is exactly what I had in mind. Sorry if I didn't explain myself in the first comment. – Alejandro Piad May 23 '12 at 18:49
  • @AlejandroPiad: for the record, the version with the dictionary did not include all married people, only married people and divorcees. Point taken though, thanks. – ninjagecko May 23 '12 at 19:31
0

The simple way is to generate the list on the fly e.g., as shown in @sr2222's answer.

As an alternative you could call an arbitrary callback each time MAR_STATUS changes. Use __new__ if Person instances are immutable or make MAR_STATUS a property and call registered callbacks in the setter method (see notifications in traits library for a more complex implementation).

jfs
  • 399,953
  • 195
  • 994
  • 1,670