Welcome, guest | Sign In | My Account | Store | Cart

Permit anyone to add methods to a class in a library without having to change the name of the class by subclassing. This is like having a plugins directory. Also, given a normal function, treat it as a method of an arbitrary class (i.e. mimic a bound method).

Python, 47 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
"""This mixin supports autoloading of "friend" methods."""

__docformat__ = "restructuredtext"

from Curry import Curry


class HasFriends:

    """This mixin supports autoloading of "friend" methods.

    That means if you have a class like ``aquarium.widget.FormUtil``, and you
    try to call a function ``fooBar`` on that class, ``FormUtil`` (assuming it
    mixes in this class) will automatically import
    ``aquarium.widget.formutil.fooBar`` (notice that the ``FormUtil`` class is
    automatically associated with the ``formutil`` package) and return the
    ``fooBar`` function.  ``fooBar`` will behave as if it were actually a
    method inside ``FormUtil``.  ``fooBar`` should be implemented as a normal
    method that just happens to receive a ``FormUtil`` instance named ``self``
    as its first argument.

    """

    def __getattr__(self, attr):
        """Return the desired friend method.
        
        Note, these methods will be cached in ``self._friendCache``.

        """
        if not self.__dict__.has_key("_friendCache"):
            self._friendCache = {}
        cache = self._friendCache 
        if not cache.has_key(attr):
            pieces = self.__module__.split(".")
            pieces[-1] = pieces[-1].lower()
            pieces.append(attr)
            moduleName = ".".join(pieces)
            try:
                module = __import__(moduleName, {}, {}, [attr])
            except:
                raise (AttributeError, """\
%s instance has no attribute '%s', and HasFriends failed too""" % 
                       (self.__class__.__name__, attr))
            f = getattr(module, attr)
            curry = Curry(f, self)
            cache[attr] = curry
        return cache[attr]

Note that this comes from the Aquarium Web application framework, but any references to Aquarium can easily be removed.