Skip to content

Delegate methods and properties to child objects in a terse, explicit style

License

Notifications You must be signed in to change notification settings

bgschiller/superdelegate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

superdelegate

Delegate methods and properties to child objects in a terse, explicit style

Installation

$ pip install superdelegate

Consider the motivating example of a sorted list. In order to encapsulate the list and prevent clients from breaking the sorted order, we want to only allow certain methods through to the underlying list:

import bisect

class SortedList:
    def __init__(self, *args, **kwargs):
        self._lst = list(*args, **kwargs)

    def insert(self, elem):
        bisect.insort(self._lst, elem)

    def __contains__(self, elem):
        ix = bisect.bisect(self._lst, elem)
        return ix != len(self._lst) and self._lst[ix] == elem

    def __getitem__(self, key):
        return self._lst.__getitem__(key)

    def __reversed__(self):
        return self._lst.__reversed__()

    def __len__(self):
        return self._lst.__len__()

    def __iter__(self):
        return self._lst.__iter__()

Much of that code is pretty repetitive. Can we do better? Yes! with superdelegate!

import bisect
from superdelegate import SuperDelegate, delegate_to

class SortedList(SuperDelegate):
    def __init__(self, *args, **kwargs):
        self._lst = list(*args, **kwargs)

    def insert(self, elem):
        bisect.insort(self._lst, elem)

    def __contains__(self, elem):
        ix = bisect.bisect(self._lst, elem)
        return ix != len(self._lst) and self._lst[ix] == elem

    __getitem__ = __reversed__ = __len__ = __iter__ = delegate_to('_lst')

FAQs

Does it work for properties? It does work for properties!

class OnlyGrowsOlder:
    def __init__(self):
        self._age

    @property
    def age(self):
        return self._age
    @age.setter
    def age(self, new_age):
        if new_age > self._age:
            self._age = new_age
        else:
            raise ValueError('Time is like a boy band. It only flows in one direction')

class OlderWrapper(SuperDelegate):
    def __init__(self):
        self._ager

    age = delegate_to('_ager')

Can you have multiple delgatees? You can!

    class SandwichMaker:
        def choose_cheese(self):
            return 'swiss'
    class NavyEngineer:
        def lift_periscope(self):
            return 'done'
    class SubmarineTechnician(SuperDelegate):
        def __init__(self):
            self.sm = SandwichMaker()
            self.ne = NavyEngineer()

        choose_cheese = delegate_to('sm')
        lift_periscope = delegate_to('ne')

Inspiration

This library was inspired by Ruby ActiveSupport's Module#delegate extension.

About

Delegate methods and properties to child objects in a terse, explicit style

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages