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

A collection groups a set of objects together and forwards attribute lookups to all elements of the collection that contain the desired attribute. It's not an error for an element of the collection to be missing an attribute. The list returned is just missing that value. The same holds true when forwarding __call__.

Python, 83 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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#!/usr/bin/env python

import UserList

class Collection(UserList.UserList):
    """Collections group objects together and forward attribute lookups.

    At least this is the Collection I remember from LYMB (an interpreted OO
    language developed by Bill Lorensen et al at GE CRD), which almost
    certainly got it from Smalltalk.
    """

    def get(self, attr):
        """return a list of attributes from ourselves.

        note that an object in the collection is not required to have 'attr',
        so the result may be shorter than the collection itself."""
        return Collection([getattr(x, attr) for x in self if hasattr(x, attr)])

    def call(self, attr, *args, **kwds):
        """return the result of calling 'attr' for each of our elements"""
        attrs = self.get(attr)
        return Collection([x(*args, **kwds)
                             for x in attrs
                               if callable(x)])

if __name__ == "__main__":
    import time

    class Food:
        def __init__(self):
            self.t = time.time()
            time.sleep(0.5)

    class Ham(Food):
        def say(self):
            print "I am Ham, and I don't want any arguments, thank you."
            return ()

        def speak_up(self, arg):
            print 'I am Ham, and my arguments are %s' % arg
            return arg

    class Eggs(Food):
        def speak_up(self, arg='bacon'):
            print 'I am Eggs, and my arguments are %s' % arg
            return arg

    class Spam(Food):
        def shout(self, arg1, arg2='sausage'):
            print 'I AM SPAM AND MY ARGUMENTS ARE %s AND %s' % (arg1, arg2)
            return (arg1, arg2)

    c = Collection()
    # kind of boring example...
    c.extend(range(3))
    print c.get("__hash__")
    print c.call("__hash__")
    print

    # slightly more interesting example...
    c = Collection([Ham(), Eggs(), Spam()])

    print "*** when was this food made? ***"
    times = c.get("t")
    print map(round, times, [2]*len(times))
    print

    print "*** what kind of food is it? ***"
    print c.get("__class__").get("__name__")
    print

    print "*** shouting ***"
    print c.call("shout", "nickel", "dime")
    print

    print "*** speaking up ***"
    print c.call("speak_up", "juice please")
    print

    print "*** saying ***"
    print c.call("say")
    print

When I worked at GE CRD, we used an internal language that was loosely based on Smalltalk. We used collections all the time. For some reason I haven't really needed them in Python. A thread on c.l.py prompted me to write this Collection class. The example is derived from that thread.