[Python-3000] ABC's, Roles, etc (original) (raw)

Jeff Shell eucci.group at gmail.com
Tue May 8 23:52:48 CEST 2007


Hello. I just joined the list as the whole Abstract Base Class, Interfaces, and Roles/Traits system is of significant interest to me. I've tried to catch up on the discussion by reading through the archives, but I'm sure I missed a few posts and I apologize if I'm wasting time covering ground that's already been covered.

I have a lengthy post that dissects a major issue that I have with ABCs and the Interface definition that I saw in PEP 3124:: it all seems rigidly class and class-instance based. The cardinal sin I saw in the Interface definition in PEP 3124 (at least, at the time I last viewed it) was the inclusion of 'self' in a method spec.

It seems to me that Abstract Base Classes and even PEP 3124 are primarily focused on classes. But in Python, "everything is an object", but not everything is class-based.

Jim Fulton taught me a long time ago that there are numerous ways to fulfill a role, or provide an interface. 'self' is an internal detail of class-instance implementations. In my post, I show some (stupid) implementations of the 'IStack' interface seen in PEP 3124, only one of which is the traditional class - instance based style.

http://griddlenoise.blogspot.com/2007/05/abc-may-be-easy-as-123-but-it-cant-beat.html

The rest of this post focuses on what zope.interface already provides - a system for specifying behavior and declaring support at both the class and object level - and 'object' really means 'object', which includes modules. You're more than welcome to tune out now. My main focus is on determining what Abstract Base Classes and/or PEP 3124's Interfaces do better than zope.interface (if anyone else is familiar with that package). I've found great success using zope.interface to satisfy many of the requirements and issues that these systems may try to solve, and more. In fact, zope.interface is closer to Roles/Traits than anything else.

.....

I wanted to chime in here and say that zope.interface (from Zope 3, but available separately) is an existing implementation that comes quite close to what Collin Winter proposed. Even in some of its spellings.

http://cheeseshop.python.org/pypi/zope.interface/3.3.0.1

The main thing is that zope.interface focuses declaration on the object - NOT the class. You do not use self in interface specifications.

Terms I've grown fond of while using zope.interface are "specifies", "provides", and "implements".

An Interface specifies desired object behavior - basically it's the API::

class IAuthVerification(Interface):
    def verify(invoice_number, amount):
        """
        Returns an IAuthResult containing status information about
        success or failure.
        """

An object provides that behavior::

>>> IAuthVerification.providedBy(authorizer)
True
>>> result = authorizer.verify(invoice_number='KB125', amount=43.40)

Now, a class may implement that behavior, which is a way of saying that "instances of this class will provide the behavior":

class AuthNet(object):
    def verify(self, invoice_number, amount):
        """ ... (class - instance based implementation) """
classImplements(AuthNet, IAuthVerification)

>>> IAuthVerification.providedBy(AuthNet)
False
>>> AuthNet.verify(invoice_number='KB125', amount=43.40)
<UnboundMethod Exception>

Alternatively, class or static methods could be used:

class StaticAuthNet(object):
    @staticmethod
    def verify(invoice_number, amount):
        """ ... """
alsoProvides(StaticAuthNet, IAuthVerification)

>>> IAuthVerification.providedBy(StaticAuthNet)
True
>>> result = StaticAuthNet.verify(invoice_number='KB125', amount=43.40)

Or a module could even provide the interfaces. In the first example above (under 'an object provides that behavior'), do you know whether 'authorizer' is an instance, class, or module? Hell, maybe it's a function that has 'verify' added as an attribute. It doesn't matter - it fills the 'IAuthVerification' role.

In my blog post, I also show a dynamically constructed object providing an interface's specified behavior. An instance of an empty class is made, and then methods and other supporting attributes are attached to this specific instance only. Real world examples of this include Zope 2, where a folder may have "Python Scripts" or other callable members that, in effect, make for a totally custom object. It can also provide this same behavior (in fact, I was able to take advantage of this on some old old old Zope 2 projects that started in the web environment and transitioned to regular Python modules/classes).

In any case, there are numerous ways to fulfill a role. I think any system that was limited to classes and involved 'issubclass' and 'isinstance' trickery would be limiting or confusing if it started to be used to describe behaviors of modules, one-off objects, and so on.

-- Jeff Shell



More information about the Python-3000 mailing list