[PEAK] 'Categories' in Python
Bob Ippolito
bob at redivi.com
Fri Dec 10 17:29:03 EST 2004
On Dec 10, 2004, at 4:30 PM, Andy Gross wrote:
> I was playing around with decorators and metaclasses last night, and I
> threw together a quick implementation of Objective-C style
> "Categories" for Python. In a nutshell, Categories are classes
> without data members, just methods.
> I have a bunch of application-specific classes that suffer from
> creeping Mixins - I have to implement some subject-oriented
> functionality to a bunch of related classes, so I originally used
> several Mixins to achieve this. The result just doesn't feel right,
> and the existence extra base classes gets in the way from time to
> time. Furthermore, if users need to change some relatively simple
> behavior, they have to dig into the code, find the Mixins, change
> them, and hope things don't break.
I think that categories come from Smalltalk originally..
> My little experiment last night uses a Category metaclass and
> decorators to formalize and simplify this kind of class extension. An
> overly simple example:
>
> class StringyThings(Category):
> def toLower(self):
> return self.string.lower()
>
> class StringyThing(B1, B2, ... BN):
> @categories(StringyThings)
> def __init__(self, string):
> self.string = string
>
> @category(StringyThings):
> def toUpper(self):
> return self.string.upper()
>
> By defining that toUpper function, any class belonging to
> StringyThings (and its subclasses) gains a toUpper method.
>
> For my application, I'm thinking of adding some kind of
> getCategoryForInterface(IFoo) to build dynamic event handler classes
> from user defined functions.
>
> I was hoping the wizards here could offer some comments or
> suggestions. You can see/download the code at:
>
> http://argv0.net/pycategories
Your implementation is backwards. Categories are added to existing
classes without their consent. Don't call what you're doing
categories.
Also, it's not really useful to distinguish between methods that a
class originally had, and the methods they acquired from a category.
This is an implementation of Category that works in Objective-C terms:
class MetaCategory(type):
def __new__(cls, name, bases, dct):
if '__category_of__' in dct:
return type.__new__(cls, name, bases, dct)
if not len(bases) == 1 and isinstance(bases[0], cls):
raise TypeError("Categories may only have a Category(...)
as their base")
cls = bases[0].__category_of__
for k,v in dct.iteritems():
if k == '__module__':
continue
setattr(cls, k, v)
return cls
def Category(cls):
return MetaCategory(
'Category(%s)' % (cls.__name__),
(object,),
{'__category_of__': cls}
)
class Foo(object):
pass
foo = Foo()
print "foo has a default repr: %r" % (foo,)
class Foo(Category(Foo)):
def __repr__(self):
return type(self).__name__ + '()'
print "now it has a nicer one: %r" % (foo,)
-bob
More information about the PEAK
mailing list