[Python-3000] PEP 3133: Introducing Roles (original) (raw)
Benji York benji at benjiyork.com
Thu May 17 15:15:28 CEST 2007
- Previous message: [Python-3000] PEP 3133: Introducing Roles
- Next message: [Python-3000] PEP 3133: Introducing Roles
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Guido van Rossum wrote:
On 5/16/07, Benji York <benji at benjiyork.com> wrote:
Guido van Rossum wrote:
On 5/14/07, Benji York <benji at benjiyork.com> wrote:
Collin Winter wrote:
PEP: 3133 Title: Introducing Roles Everything included here is included in zope.interface. See in-line comments below for the analogs. Could you look at PEP 3119 and do a similar analysis? Sure.
And here it is:
PEP: 3119 Title: Introducing Abstract Base Classes
I've placed my comments in-line and snipped chunks of the original PEP where it seemed appropriate.
Version: RevisionRevisionRevision Last-Modified: DateDateDate Author: Guido van Rossum <guido at python.org>, Talin <talin at acm.org> Status: Draft Type: Standards Track Content-Type: text/x-rst Created: 18-Apr-2007 Post-History: 26-Apr-2007, 11-May-2007
[snip]
Rationale
In the domain of object-oriented programming, the usage patterns for interacting with an object can be divided into two basic categories, which are 'invocation' and 'inspection'.
Invocation means interacting with an object by invoking its methods. Usually this is combined with polymorphism, so that invoking a given method may run different code depending on the type of an object.
Inspection means the ability for external code (outside of the object's methods) to examine the type or properties of that object, and make decisions on how to treat that object based on that information.
Both usage patterns serve the same general end, which is to be able to support the processing of diverse and potentially novel objects in a uniform way, but at the same time allowing processing decisions to be customized for each different type of object.
In classical OOP theory, invocation is the preferred usage pattern, and inspection is actively discouraged, being considered a relic of an earlier, procedural programming style. However, in practice this view is simply too dogmatic and inflexible, and leads to a kind of design rigidity that is very much at odds with the dynamic nature of a language like Python.
I disagree with the last sentance in the above paragraph. While zope.interface has been shown (in a seperate message) to perform the same tasks as the "rolls" PEP (3133) and below I show the similarities between this PEP (ABCs) and zope.interface, I want to point out that users of zope.interface don't actually use it in these ways.
So, what /do/ people use zope.interface for? There are two primary uses: making contracts explicit and adaptation. If more detail is desired about these uses; I'll be glad to share.
My main point is that the time machine worked; people have had the moral equivalent of ABCs and Roles for years and have decided against using them the way the PEPs envision. Of course if people still think ABCs are keen, then a stand-alone package can be created and we can see if there is uptake, if so; it can be added to the standard library later.
If I recall correctly, the original motivation for ABCs was that some times people want to "sniff" an object and see what it is, almost always to dispatch appropriately. That use case of "dispatch in the small", would seem to me to be much better addressed by generic functions. If those generic functions want something in addition to classes to dispatch on, then interfaces can be used too.
If GF aren't desirable for that use case, then basefile, basesequence, and basemapping can be added to Python and cover 90% of what people need. I think the Java Collections system has shown that it's not neccesary to provide all interfaces for all people. If you can only provide a subset of an interface, make unimplemented methods raise NotImplementedError.
[snip]
Overloading
isinstance()
andissubclass()
Perhaps the PEP should just be reduced to include only this section.
[snip]
The
abc
Module: an ABC Support Framework[snip] These methods are intended to be be called on classes whose metaclass is (derived from)
ABCMeta
; for example::from abc import ABCMeta
import zope.interface
class MyABC(metaclass=ABCMeta): pass
class MyInterface(zope.interface.Interface):
pass
MyABC.register(tuple)
zope.interface.classImplements(tuple, MyInterface)
assert issubclass(tuple, MyABC)
assert MyInterface.implementedBy(tuple)
assert isinstance((), MyABC)
assert MyInterface.providedBy(())
The last two asserts are equivalent to the following two::
assert MyABC.__subclasscheck__(tuple) assert MyABC.__instancecheck__(())
Of course, you can also directly subclass MyABC::
class MyClass(MyABC): pass
class MyClass:
zope.interface.implements(MyInterface)
assert issubclass(MyClass, MyABC)
assert MyInterface.implementedBy(MyClass)
assert isinstance(MyClass(), MyABC)
assert MyInterface.providedBy(MyClass())
Also, of course, a tuple is not a
MyClass
::assert not issubclass(tuple, MyClass) assert not isinstance((), MyClass)
You can register another class as a subclass of
MyClass
::MyClass.register(list)
There is an interface that MyClass implements that list implements as well.
class MyClassInterface(MyInterface):
pass
zope.interface.classImplements(list, MyClassInterface)
Sidebar: this highlights one of the reasons zope.interface users employ the naming convention of prefixing their interface names with "I", it helps keep interface names short while giving you an easy name for "interface that corresponds to things of class Foo", which would be IFoo.
assert issubclass(list, MyClass)
assert MyClassInterface.implementedBy(list)
assert issubclass(list, MyABC)
assert MyClassInterface.extends(MyInterface)
You can also register another ABC::
class AnotherClass(metaclass=ABCMeta): pass
class AnotherInterface(zope.interface.Interface):
pass
AnotherClass.register(basestring)
zope.interface.classImplements(basestring, AnotherInterface)
MyClass.register(AnotherClass)
I don't quite understand the intent of the above line. It appears to be extending the contract that AnotherClass embodies to promise to fulfill any contract that MyClass embodies. That seems to be an unusual thing to want to express. Although unusual, you could still do it using zope.interface. One way would be to add MyClassInterface to the bases of AnotherInterface.
OTOH, I might be confused by the colapsing of the class and interface hierarchies. Do the classes in the above line of code represent the implementation or specification?
[snip]
ABCs for Containers and Iterators
zope.interface defines similar interfaces. Surprisingly they aren't used all that often. They can be viewed at http://svn.zope.org/zope.interface/trunk/src/zope/interface/common/. The files mapping.py, sequence.py, and idatetime.py are the most interesting.
[snip rest]
I was just thinking of how to "sell" ABCs as an alternative to current happy users of zop.interfaces.
One of the things that makes zope.interface users happy is the separation of specification and implementation. The increasing separation of specification from implementation is what has driven Abstract Data Types in procedural languages, encapsulation in OOP, and now zope.interface. Mixing the two back together in ABCs doesn't seem attractive.
As for "selling" current users on an alternative, why bother? If people need interfaces, they know where to find them. I suspect I'm confused as to the intent of this discussion.
Benji York http://benjiyork.com
- Previous message: [Python-3000] PEP 3133: Introducing Roles
- Next message: [Python-3000] PEP 3133: Introducing Roles
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]