altendky
altendky

Reputation: 4354

How should I handle Python list properties with respect to getters/setters?

It is my understanding that one aspect of the Pythonic way is to use direct member variable access of classes until 'getters/setters' are needed. Code is available on Ideone

class Person():
    def __init__(self, name, age=None, friends=None):
        self.name = name
        self.age = age
        if friends is None:
            self.friends = []
        else:
            self.friends = friends

me = Person('Mr. Me')
you = Person('Ms. You')

me.age = 42
me.friends.append(you)

Because of the @property decorator approach this access to member variable age can be 'converted' to a 'getter/setter' interface in the future without rewriting the line that sets it to 42. But what about the last line where I add you to my friends list? Is it possible for the Person class to intercept the append() call and take other actions? Perhaps in the future I would decide to add the feature that you would get notified that they have been added to me's friends list.

Upvotes: 1

Views: 247

Answers (1)

altendky
altendky

Reputation: 4354

Of course, once I ask the question my brain turns on and comes up with a solution. Let me know if this is good or not. Instead of intercepting the .append() call in Person, create a class PersonFriendList(List) and override append() with the desired functionality. Then, instead of assigning [] to self.friends assign PersonFriendList(). The .friend value should probably also get decorated as a @property so that assignment can be intercepted by Person to avoid .friend being written to the wrong kind of list.

Code available on Ideone.

class Person():
    def __init__(self, name, age=None, friends=None):
        self.name = name
        self.age = age
        if friends is None:
            friends = []
        self.friends = PersonFriendList(friends)


class PersonFriendList(list):
    def __init__(self, *args):
        super(PersonFriendList, self).__init__(*args)
        self.DebugPrint('constructed with {}'.format(str(*args)))

    def DebugPrint(self, string):
        print('{}(): {}'.format(self.__class__.__name__, string))

    def append(self, *args):
        super(PersonFriendList, self).append(*args)
        self.DebugPrint('appending {}'.format(str(*args)))

me = Person('Mr. Me')
you = Person('Ms. You')

me.age = 42
me.friends.append(you)

Upvotes: 1

Related Questions