reSTify PEP 245 (#407)
This commit is contained in:
parent
916f0862cf
commit
58037ff300
698
pep-0245.txt
698
pep-0245.txt
|
@ -6,500 +6,522 @@ Author: Michel Pelletier <michel@users.sourceforge.net>
|
|||
Discussions-To: http://www.zope.org/Wikis/Interfaces
|
||||
Status: Rejected
|
||||
Type: Standards Track
|
||||
Content-Type: text/x-rst
|
||||
Created: 11-Jan-2001
|
||||
Python-Version: 2.2
|
||||
Post-History: 21-Mar-2001
|
||||
|
||||
|
||||
Rejection Notice
|
||||
================
|
||||
|
||||
I'm rejecting this PEP. It's been five years now. While at some
|
||||
point I expect that Python will have interfaces, it would be naive
|
||||
to expect it to resemble the syntax in this PEP. Also, PEP 246 is
|
||||
being rejected in favor of something completely different; interfaces
|
||||
won't play a role in adaptation or whatever will replace it. GvR.
|
||||
I'm rejecting this PEP. It's been five years now. While at some
|
||||
point I expect that Python will have interfaces, it would be naive
|
||||
to expect it to resemble the syntax in this PEP. Also, PEP 246 is
|
||||
being rejected in favor of something completely different; interfaces
|
||||
won't play a role in adaptation or whatever will replace it. GvR.
|
||||
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
This PEP describes a proposed syntax for creating interface
|
||||
objects in Python.
|
||||
This PEP describes a proposed syntax for creating interface
|
||||
objects in Python.
|
||||
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
In addition to thinking about adding a static type system to
|
||||
Python, the Types-SIG was also charged to devise an interface
|
||||
system for Python. In December of 1998, Jim Fulton released a
|
||||
prototype interfaces system based on discussions from the SIG.
|
||||
Many of the issues and background information on this discussion
|
||||
and prototype can be found in the SIG archives[1].
|
||||
In addition to thinking about adding a static type system to
|
||||
Python, the Types-SIG was also charged to devise an interface
|
||||
system for Python. In December of 1998, Jim Fulton released a
|
||||
prototype interfaces system based on discussions from the SIG.
|
||||
Many of the issues and background information on this discussion
|
||||
and prototype can be found in the SIG archives [1]_.
|
||||
|
||||
Around the end of 2000, Digital Creations began thinking about
|
||||
better component model designs for Zope[2]. Zope's future
|
||||
component model relies heavily on interface objects. This led to
|
||||
further development of Jim's "Scarecrow" interfaces prototype.
|
||||
Starting with version 2.3, Zope comes with an Interface package as
|
||||
standard software. Zope's Interface package is used as the
|
||||
reference implementation for this PEP.
|
||||
Around the end of 2000, Digital Creations began thinking about
|
||||
better component model designs for Zope [2]_. Zope's future
|
||||
component model relies heavily on interface objects. This led to
|
||||
further development of Jim's "Scarecrow" interfaces prototype.
|
||||
Starting with version 2.3, Zope comes with an Interface package as
|
||||
standard software. Zope's Interface package is used as the
|
||||
reference implementation for this PEP.
|
||||
|
||||
The syntax proposed by this PEP relies on syntax enhancements
|
||||
describe in PEP 232 [3] and describes an underlying framework
|
||||
which PEP 233 [4] could be based upon. There is some work being
|
||||
done with regard to interface objects and Proxy objects, so for
|
||||
those optional parts of this PEP you may want to see[5].
|
||||
The syntax proposed by this PEP relies on syntax enhancements
|
||||
describe in PEP 232 [3]_ and describes an underlying framework
|
||||
which PEP 233 [4]_ could be based upon. There is some work being
|
||||
done with regard to interface objects and Proxy objects, so for
|
||||
those optional parts of this PEP you may want to see [5]_.
|
||||
|
||||
|
||||
The Problem
|
||||
===========
|
||||
|
||||
Interfaces are important because they solve a number of problems
|
||||
that arise while developing software:
|
||||
Interfaces are important because they solve a number of problems
|
||||
that arise while developing software:
|
||||
|
||||
- There are many implied interfaces in Python, commonly referred
|
||||
to as "protocols". Currently determining those protocols is
|
||||
based on implementation introspection, but often that also
|
||||
fails. For example, defining __getitem__ implies both a
|
||||
sequence and a mapping (the former with sequential, integer
|
||||
keys). There is no way for the developer to be explicit about
|
||||
which protocols the object intends to implement.
|
||||
- There are many implied interfaces in Python, commonly referred
|
||||
to as "protocols". Currently determining those protocols is
|
||||
based on implementation introspection, but often that also
|
||||
fails. For example, defining ``__getitem__`` implies both a
|
||||
sequence and a mapping (the former with sequential, integer
|
||||
keys). There is no way for the developer to be explicit about
|
||||
which protocols the object intends to implement.
|
||||
|
||||
- Python is limited, from the developer's point of view, by the
|
||||
split between types and classes. When types are expected, the
|
||||
consumer uses code like 'type(foo) == type("")' to determine if
|
||||
'foo' is a string. When instances of classes are expected, the
|
||||
consumer uses 'isinstance(foo, MyString)' to determine if 'foo'
|
||||
is an instance of the 'MyString' class. There is no unified
|
||||
model for determining if an object can be used in a certain,
|
||||
valid way.
|
||||
- Python is limited, from the developer's point of view, by the
|
||||
split between types and classes. When types are expected, the
|
||||
consumer uses code like 'type(foo) == type("")' to determine if
|
||||
'foo' is a string. When instances of classes are expected, the
|
||||
consumer uses 'isinstance(foo, MyString)' to determine if 'foo'
|
||||
is an instance of the 'MyString' class. There is no unified
|
||||
model for determining if an object can be used in a certain,
|
||||
valid way.
|
||||
|
||||
- Python's dynamic typing is very flexible and powerful, but it
|
||||
does not have the advantage of static typed languages that
|
||||
provide type checking. Static typed languages provide you with
|
||||
much more type safety, but are often overly verbose because
|
||||
objects can only be generalized by common subclassing and used
|
||||
specifically with casting (for example, in Java).
|
||||
- Python's dynamic typing is very flexible and powerful, but it
|
||||
does not have the advantage of static typed languages that
|
||||
provide type checking. Static typed languages provide you with
|
||||
much more type safety, but are often overly verbose because
|
||||
objects can only be generalized by common subclassing and used
|
||||
specifically with casting (for example, in Java).
|
||||
|
||||
There are also a number of documentation problems that interfaces
|
||||
try to solve.
|
||||
There are also a number of documentation problems that interfaces
|
||||
try to solve.
|
||||
|
||||
- Developers waste a lot of time looking at the source code of
|
||||
your system to figure out how objects work.
|
||||
- Developers waste a lot of time looking at the source code of
|
||||
your system to figure out how objects work.
|
||||
|
||||
- Developers who are new to your system may misunderstand how your
|
||||
objects work, causing, and possibly propagating, usage errors.
|
||||
- Developers who are new to your system may misunderstand how your
|
||||
objects work, causing, and possibly propagating, usage errors.
|
||||
|
||||
- Because a lack of interfaces means usage is inferred from the
|
||||
source, developers may end up using methods and attributes that
|
||||
are meant for "internal use only".
|
||||
- Because a lack of interfaces means usage is inferred from the
|
||||
source, developers may end up using methods and attributes that
|
||||
are meant for "internal use only".
|
||||
|
||||
- Code inspection can be hard, and very discouraging to novice
|
||||
programmers trying to properly understand code written by gurus.
|
||||
- Code inspection can be hard, and very discouraging to novice
|
||||
programmers trying to properly understand code written by gurus.
|
||||
|
||||
- A lot of time is wasted when many people try very hard to
|
||||
understand obscurity (like undocumented software). Effort spend
|
||||
up front documenting interfaces will save much of this time in
|
||||
the end.
|
||||
- A lot of time is wasted when many people try very hard to
|
||||
understand obscurity (like undocumented software). Effort spend
|
||||
up front documenting interfaces will save much of this time in
|
||||
the end.
|
||||
|
||||
Interfaces try to solve these problems by providing a way for you
|
||||
to specify a contractual obligation for your object, documentation
|
||||
on how to use an object, and a built-in mechanism for discovering
|
||||
the contract and the documentation.
|
||||
Interfaces try to solve these problems by providing a way for you
|
||||
to specify a contractual obligation for your object, documentation
|
||||
on how to use an object, and a built-in mechanism for discovering
|
||||
the contract and the documentation.
|
||||
|
||||
Python has very useful introspection features. It is well known
|
||||
that this makes exploring concepts in the interactive interpreter
|
||||
easier, because Python gives you the ability to look at all kinds
|
||||
of information about the objects: the type, doc strings, instance
|
||||
dictionaries, base classes, unbound methods and more.
|
||||
Python has very useful introspection features. It is well known
|
||||
that this makes exploring concepts in the interactive interpreter
|
||||
easier, because Python gives you the ability to look at all kinds
|
||||
of information about the objects: the type, doc strings, instance
|
||||
dictionaries, base classes, unbound methods and more.
|
||||
|
||||
Many of these features are oriented toward introspecting, using
|
||||
and changing the implementation of software, and one of them ("doc
|
||||
strings") is oriented toward providing documentation. This
|
||||
proposal describes an extension to this natural introspection
|
||||
framework that describes an object's interface.
|
||||
Many of these features are oriented toward introspecting, using
|
||||
and changing the implementation of software, and one of them ("doc
|
||||
strings") is oriented toward providing documentation. This
|
||||
proposal describes an extension to this natural introspection
|
||||
framework that describes an object's interface.
|
||||
|
||||
|
||||
Overview of the Interface Syntax
|
||||
================================
|
||||
|
||||
For the most part, the syntax of interfaces is very much like the
|
||||
syntax of classes, but future needs, or needs brought up in
|
||||
discussion, may define new possibilities for interface syntax.
|
||||
For the most part, the syntax of interfaces is very much like the
|
||||
syntax of classes, but future needs, or needs brought up in
|
||||
discussion, may define new possibilities for interface syntax.
|
||||
|
||||
A formal BNF description of the syntax is givena later in the PEP,
|
||||
for the purposes of illustration, here is an example of two
|
||||
different interfaces created with the proposed syntax:
|
||||
A formal BNF description of the syntax is givena later in the PEP,
|
||||
for the purposes of illustration, here is an example of two
|
||||
different interfaces created with the proposed syntax::
|
||||
|
||||
interface CountFishInterface:
|
||||
"Fish counting interface"
|
||||
interface CountFishInterface:
|
||||
"Fish counting interface"
|
||||
|
||||
def oneFish():
|
||||
"Increments the fish count by one"
|
||||
def oneFish():
|
||||
"Increments the fish count by one"
|
||||
|
||||
def twoFish():
|
||||
"Increments the fish count by two"
|
||||
def twoFish():
|
||||
"Increments the fish count by two"
|
||||
|
||||
def getFishCount():
|
||||
"Returns the fish count"
|
||||
def getFishCount():
|
||||
"Returns the fish count"
|
||||
|
||||
interface ColorFishInterface:
|
||||
"Fish coloring interface"
|
||||
interface ColorFishInterface:
|
||||
"Fish coloring interface"
|
||||
|
||||
def redFish():
|
||||
"Sets the current fish color to red"
|
||||
def redFish():
|
||||
"Sets the current fish color to red"
|
||||
|
||||
def blueFish():
|
||||
"Sets the current fish color to blue"
|
||||
def blueFish():
|
||||
"Sets the current fish color to blue"
|
||||
|
||||
def getFishColor():
|
||||
"This returns the current fish color"
|
||||
def getFishColor():
|
||||
"This returns the current fish color"
|
||||
|
||||
This code, when evaluated, will create two interfaces called
|
||||
`CountFishInterface' and `ColorFishInterface'. These interfaces
|
||||
are defined by the `interface' statement.
|
||||
This code, when evaluated, will create two interfaces called
|
||||
``CountFishInterface`` and ``ColorFishInterface``. These interfaces
|
||||
are defined by the ``interface`` statement.
|
||||
|
||||
The prose documentation for the interfaces and their methods come
|
||||
from doc strings. The method signature information comes from the
|
||||
signatures of the `def' statements. Notice how there is no body
|
||||
for the def statements. The interface does not implement a
|
||||
service to anything; it merely describes one. Documentation
|
||||
strings on interfaces and interface methods are mandatory, a
|
||||
'pass' statement cannot be provided. The interface equivalent of
|
||||
a pass statement is an empty doc string.
|
||||
The prose documentation for the interfaces and their methods come
|
||||
from doc strings. The method signature information comes from the
|
||||
signatures of the ``def`` statements. Notice how there is no body
|
||||
for the def statements. The interface does not implement a
|
||||
service to anything; it merely describes one. Documentation
|
||||
strings on interfaces and interface methods are mandatory, a
|
||||
'pass' statement cannot be provided. The interface equivalent of
|
||||
a pass statement is an empty doc string.
|
||||
|
||||
You can also create interfaces that "extend" other interfaces.
|
||||
Here, you can see a new type of Interface that extends the
|
||||
CountFishInterface and ColorFishInterface:
|
||||
You can also create interfaces that "extend" other interfaces.
|
||||
Here, you can see a new type of Interface that extends the
|
||||
CountFishInterface and ColorFishInterface::
|
||||
|
||||
interface FishMarketInterface(CountFishInterface, ColorFishInterface):
|
||||
"This is the documentation for the FishMarketInterface"
|
||||
interface FishMarketInterface(CountFishInterface, ColorFishInterface):
|
||||
"This is the documentation for the FishMarketInterface"
|
||||
|
||||
def getFishMonger():
|
||||
"Returns the fish monger you can interact with"
|
||||
def getFishMonger():
|
||||
"Returns the fish monger you can interact with"
|
||||
|
||||
def hireNewFishMonger(name):
|
||||
"Hire a new fish monger"
|
||||
def hireNewFishMonger(name):
|
||||
"Hire a new fish monger"
|
||||
|
||||
def buySomeFish(quantity=1):
|
||||
"Buy some fish at the market"
|
||||
def buySomeFish(quantity=1):
|
||||
"Buy some fish at the market"
|
||||
|
||||
The FishMarketInteface extends upon the CountFishInterface and
|
||||
ColorfishInterface.
|
||||
The FishMarketInteface extends upon the CountFishInterface and
|
||||
ColorfishInterface.
|
||||
|
||||
|
||||
Interface Assertion
|
||||
===================
|
||||
|
||||
The next step is to put classes and interfaces together by
|
||||
creating a concrete Python class that asserts that it implements
|
||||
an interface. Here is an example FishMarket component that might
|
||||
do this:
|
||||
The next step is to put classes and interfaces together by
|
||||
creating a concrete Python class that asserts that it implements
|
||||
an interface. Here is an example FishMarket component that might
|
||||
do this::
|
||||
|
||||
class FishError(Error):
|
||||
pass
|
||||
class FishError(Error):
|
||||
pass
|
||||
|
||||
class FishMarket implements FishMarketInterface:
|
||||
number = 0
|
||||
color = None
|
||||
monger_name = 'Crusty Barnacles'
|
||||
class FishMarket implements FishMarketInterface:
|
||||
number = 0
|
||||
color = None
|
||||
monger_name = 'Crusty Barnacles'
|
||||
|
||||
def __init__(self, number, color):
|
||||
self.number = number
|
||||
self.color = color
|
||||
def __init__(self, number, color):
|
||||
self.number = number
|
||||
self.color = color
|
||||
|
||||
def oneFish(self):
|
||||
self.number += 1
|
||||
def oneFish(self):
|
||||
self.number += 1
|
||||
|
||||
def twoFish(self):
|
||||
self.number += 2
|
||||
def twoFish(self):
|
||||
self.number += 2
|
||||
|
||||
def redFish(self):
|
||||
self.color = 'red'
|
||||
def redFish(self):
|
||||
self.color = 'red'
|
||||
|
||||
def blueFish(self):
|
||||
self.color = 'blue'
|
||||
def blueFish(self):
|
||||
self.color = 'blue'
|
||||
|
||||
def getFishCount(self):
|
||||
return self.number
|
||||
def getFishCount(self):
|
||||
return self.number
|
||||
|
||||
def getFishColor(self):
|
||||
return self.color
|
||||
def getFishColor(self):
|
||||
return self.color
|
||||
|
||||
def getFishMonger(self):
|
||||
return self.monger_name
|
||||
def getFishMonger(self):
|
||||
return self.monger_name
|
||||
|
||||
def hireNewFishMonger(self, name):
|
||||
self.monger_name = name
|
||||
def hireNewFishMonger(self, name):
|
||||
self.monger_name = name
|
||||
|
||||
def buySomeFish(self, quantity=1):
|
||||
if quantity > self.count:
|
||||
raise FishError("There's not enough fish")
|
||||
self.count -= quantity
|
||||
return quantity
|
||||
def buySomeFish(self, quantity=1):
|
||||
if quantity > self.count:
|
||||
raise FishError("There's not enough fish")
|
||||
self.count -= quantity
|
||||
return quantity
|
||||
|
||||
This new class, FishMarket defines a concrete class which
|
||||
implements the FishMarketInterface. The object following the
|
||||
`implements' statement is called an "interface assertion". An
|
||||
interface assertion can be either an interface object, or tuple of
|
||||
interface assertions.
|
||||
This new class, FishMarket defines a concrete class which
|
||||
implements the FishMarketInterface. The object following the
|
||||
``implements`` statement is called an "interface assertion". An
|
||||
interface assertion can be either an interface object, or tuple of
|
||||
interface assertions.
|
||||
|
||||
The interface assertion provided in a `class' statement like this
|
||||
is stored in the class's `__implements__' class attribute. After
|
||||
interpreting the above example, you would have a class statement
|
||||
that can be examined like this with an 'implements' built-in
|
||||
function:
|
||||
The interface assertion provided in a ``class`` statement like this
|
||||
is stored in the class's ``__implements__`` class attribute. After
|
||||
interpreting the above example, you would have a class statement
|
||||
that can be examined like this with an 'implements' built-in
|
||||
function::
|
||||
|
||||
>>> FishMarket
|
||||
<class FishMarket at 8140f50>
|
||||
>>> FishMarket.__implements__
|
||||
(<Interface FishMarketInterface at 81006f0>,)
|
||||
>>> f = FishMarket(6, 'red')
|
||||
>>> implements(f, FishMarketInterface)
|
||||
1
|
||||
>>>
|
||||
>>> FishMarket
|
||||
<class FishMarket at 8140f50>
|
||||
>>> FishMarket.__implements__
|
||||
(<Interface FishMarketInterface at 81006f0>,)
|
||||
>>> f = FishMarket(6, 'red')
|
||||
>>> implements(f, FishMarketInterface)
|
||||
1
|
||||
>>>
|
||||
|
||||
A class can realize more than one interface. For example, say you
|
||||
had an interface called `ItemInterface' that described how an
|
||||
object worked as an item in a container object. If you wanted to
|
||||
assert that FishMarket instances realized the ItemInterface
|
||||
interface as well as the FishMarketInterface, you can provide an
|
||||
interface assertion that contained a tuple of interface objects to
|
||||
the FishMarket class:
|
||||
A class can realize more than one interface. For example, say you
|
||||
had an interface called ``ItemInterface`` that described how an
|
||||
object worked as an item in a container object. If you wanted to
|
||||
assert that FishMarket instances realized the ItemInterface
|
||||
interface as well as the FishMarketInterface, you can provide an
|
||||
interface assertion that contained a tuple of interface objects to
|
||||
the FishMarket class::
|
||||
|
||||
class FishMarket implements FishMarketInterface, ItemInterface:
|
||||
# ...
|
||||
class FishMarket implements FishMarketInterface, ItemInterface:
|
||||
# ...
|
||||
|
||||
Interface assertions can also be used if you want to assert that
|
||||
one class implements an interface, and all of the interfaces that
|
||||
another class implements:
|
||||
Interface assertions can also be used if you want to assert that
|
||||
one class implements an interface, and all of the interfaces that
|
||||
another class implements::
|
||||
|
||||
class MyFishMarket implements FishMarketInterface, ItemInterface:
|
||||
# ...
|
||||
class MyFishMarket implements FishMarketInterface, ItemInterface:
|
||||
# ...
|
||||
|
||||
class YourFishMarket implements FooInterface, MyFishMarket.__implements__:
|
||||
# ...
|
||||
class YourFishMarket implements FooInterface, MyFishMarket.__implements__:
|
||||
# ...
|
||||
|
||||
This new class YourFishMarket, asserts that it implements the
|
||||
FooInterface, as well as the interfaces implemented by the
|
||||
MyFishMarket class.
|
||||
This new class YourFishMarket, asserts that it implements the
|
||||
FooInterface, as well as the interfaces implemented by the
|
||||
MyFishMarket class.
|
||||
|
||||
It's worth going into a little bit more detail about interface
|
||||
assertions. An interface assertion is either an interface object,
|
||||
or a tuple of interface assertions. For example:
|
||||
It's worth going into a little bit more detail about interface
|
||||
assertions. An interface assertion is either an interface object,
|
||||
or a tuple of interface assertions. For example::
|
||||
|
||||
FooInterface
|
||||
FooInterface
|
||||
|
||||
FooInterface, (BarInteface, BobInterface)
|
||||
FooInterface, (BarInteface, BobInterface)
|
||||
|
||||
FooInterface, (BarInterface, (BobInterface, MyClass.__implements__))
|
||||
FooInterface, (BarInterface, (BobInterface, MyClass.__implements__))
|
||||
|
||||
Are all valid interface assertions. When two interfaces define
|
||||
the same attributes, the order in which information is preferred
|
||||
in the assertion is from top-to-bottom, left-to-right.
|
||||
Are all valid interface assertions. When two interfaces define
|
||||
the same attributes, the order in which information is preferred
|
||||
in the assertion is from top-to-bottom, left-to-right.
|
||||
|
||||
There are other interface proposals that, in the need for
|
||||
simplicity, have combined the notion of class and interface to
|
||||
provide simple interface enforcement. Interface objects have a
|
||||
`deferred' method that returns a deferred class that implements
|
||||
this behavior:
|
||||
There are other interface proposals that, in the need for
|
||||
simplicity, have combined the notion of class and interface to
|
||||
provide simple interface enforcement. Interface objects have a
|
||||
``deferred`` method that returns a deferred class that implements
|
||||
this behavior::
|
||||
|
||||
>>> FM = FishMarketInterface.deferred()
|
||||
>>> class MyFM(FM): pass
|
||||
>>> FM = FishMarketInterface.deferred()
|
||||
>>> class MyFM(FM): pass
|
||||
|
||||
>>> f = MyFM()
|
||||
>>> f.getFishMonger()
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
Interface.Exceptions.BrokenImplementation:
|
||||
An object has failed to implement interface FishMarketInterface
|
||||
>>> f = MyFM()
|
||||
>>> f.getFishMonger()
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
Interface.Exceptions.BrokenImplementation:
|
||||
An object has failed to implement interface FishMarketInterface
|
||||
|
||||
The getFishMonger attribute was not provided.
|
||||
>>>
|
||||
The getFishMonger attribute was not provided.
|
||||
>>>
|
||||
|
||||
This provides for a bit of passive interface enforcement by
|
||||
telling you what you forgot to do to implement that interface.
|
||||
This provides for a bit of passive interface enforcement by
|
||||
telling you what you forgot to do to implement that interface.
|
||||
|
||||
|
||||
Formal Interface Syntax
|
||||
=======================
|
||||
|
||||
Python syntax is defined in a modified BNF grammar notation
|
||||
described in the Python Reference Manual [8]. This section
|
||||
describes the proposed interface syntax using this grammar:
|
||||
Python syntax is defined in a modified BNF grammar notation
|
||||
described in the Python Reference Manual [8]_. This section
|
||||
describes the proposed interface syntax using this grammar::
|
||||
|
||||
interfacedef: "interface" interfacename [extends] ":" suite
|
||||
extends: "(" [expression_list] ")"
|
||||
interfacename: identifier
|
||||
interfacedef: "interface" interfacename [extends] ":" suite
|
||||
extends: "(" [expression_list] ")"
|
||||
interfacename: identifier
|
||||
|
||||
An interface definition is an executable statement. It first
|
||||
evaluates the extends list, if present. Each item in the extends
|
||||
list should evaluate to an interface object.
|
||||
An interface definition is an executable statement. It first
|
||||
evaluates the extends list, if present. Each item in the extends
|
||||
list should evaluate to an interface object.
|
||||
|
||||
The interface's suite is then executed in a new execution frame
|
||||
(see the Python Reference Manual, section 4.1), using a newly
|
||||
created local namespace and the original global namespace. When
|
||||
the interface's suite finishes execution, its execution frame is
|
||||
discarded but its local namespace is saved as interface elements.
|
||||
An interface object is then created using the extends list for the
|
||||
base interfaces and the saved interface elements. The interface
|
||||
name is bound to this interface object in the original local
|
||||
namespace.
|
||||
The interface's suite is then executed in a new execution frame
|
||||
(see the Python Reference Manual, section 4.1), using a newly
|
||||
created local namespace and the original global namespace. When
|
||||
the interface's suite finishes execution, its execution frame is
|
||||
discarded but its local namespace is saved as interface elements.
|
||||
An interface object is then created using the extends list for the
|
||||
base interfaces and the saved interface elements. The interface
|
||||
name is bound to this interface object in the original local
|
||||
namespace.
|
||||
|
||||
This PEP also proposes an extension to Python's 'class' statement:
|
||||
This PEP also proposes an extension to Python's 'class' statement::
|
||||
|
||||
classdef: "class" classname [inheritance] [implements] ":" suite
|
||||
implements: "implements" implist
|
||||
implist: expression-list
|
||||
classdef: "class" classname [inheritance] [implements] ":" suite
|
||||
implements: "implements" implist
|
||||
implist: expression-list
|
||||
|
||||
classname,
|
||||
inheritance,
|
||||
suite,
|
||||
expression-list: see the Python Reference Manual
|
||||
classname,
|
||||
inheritance,
|
||||
suite,
|
||||
expression-list: see the Python Reference Manual
|
||||
|
||||
Before a class' suite is executed, the 'inheritance' and
|
||||
'implements' statements are evaluated, if present. The
|
||||
'inheritance' behavior is unchanged as defined in Section 7.6 of
|
||||
the Language Reference.
|
||||
Before a class' suite is executed, the 'inheritance' and
|
||||
'implements' statements are evaluated, if present. The
|
||||
'inheritance' behavior is unchanged as defined in Section 7.6 of
|
||||
the Language Reference.
|
||||
|
||||
The 'implements', if present, is evaluated after inheritance.
|
||||
This must evaluate to an interface specification, which is either
|
||||
an interface, or a tuple of interface specifications. If a valid
|
||||
interface specification is present, the assertion is assigned to
|
||||
the class object's '__implements__' attribute, as a tuple.
|
||||
The 'implements', if present, is evaluated after inheritance.
|
||||
This must evaluate to an interface specification, which is either
|
||||
an interface, or a tuple of interface specifications. If a valid
|
||||
interface specification is present, the assertion is assigned to
|
||||
the class object's '__implements__' attribute, as a tuple.
|
||||
|
||||
This PEP does not propose any changes to the syntax of function
|
||||
definitions or assignments.
|
||||
This PEP does not propose any changes to the syntax of function
|
||||
definitions or assignments.
|
||||
|
||||
|
||||
Classes and Interfaces
|
||||
======================
|
||||
|
||||
The example interfaces above do not describe any kind of behavior
|
||||
for their methods, they just describe an interface that a typical
|
||||
FishMarket object would realize.
|
||||
The example interfaces above do not describe any kind of behavior
|
||||
for their methods, they just describe an interface that a typical
|
||||
FishMarket object would realize.
|
||||
|
||||
You may notice a similarity between interfaces extending from
|
||||
other interfaces and classes sub-classing from other classes.
|
||||
This is a similar concept. However it is important to note that
|
||||
interfaces extend interfaces and classes subclass classes. You
|
||||
cannot extend a class or subclass an interface. Classes and
|
||||
interfaces are separate.
|
||||
You may notice a similarity between interfaces extending from
|
||||
other interfaces and classes sub-classing from other classes.
|
||||
This is a similar concept. However it is important to note that
|
||||
interfaces extend interfaces and classes subclass classes. You
|
||||
cannot extend a class or subclass an interface. Classes and
|
||||
interfaces are separate.
|
||||
|
||||
The purpose of a class is to share the implementation of how an
|
||||
object works. The purpose of an interface is to document how to
|
||||
work with an object, not how the object is implemented. It is
|
||||
possible to have several different classes with very different
|
||||
implementations realize the same interface.
|
||||
The purpose of a class is to share the implementation of how an
|
||||
object works. The purpose of an interface is to document how to
|
||||
work with an object, not how the object is implemented. It is
|
||||
possible to have several different classes with very different
|
||||
implementations realize the same interface.
|
||||
|
||||
It's also possible to implement one interface with many classes
|
||||
that mix in pieces the functionality of the interface or,
|
||||
conversely, it's possible to have one class implement many
|
||||
interfaces. Because of this, interfaces and classes should not be
|
||||
confused or intermingled.
|
||||
It's also possible to implement one interface with many classes
|
||||
that mix in pieces the functionality of the interface or,
|
||||
conversely, it's possible to have one class implement many
|
||||
interfaces. Because of this, interfaces and classes should not be
|
||||
confused or intermingled.
|
||||
|
||||
|
||||
Interface-aware built-ins
|
||||
=========================
|
||||
|
||||
A useful extension to Python's list of built-in functions in the
|
||||
light of interface objects would be `implements()'. This builtin
|
||||
would expect two arguments, an object and an interface, and return
|
||||
a true value if the object implements the interface, false
|
||||
otherwise. For example:
|
||||
A useful extension to Python's list of built-in functions in the
|
||||
light of interface objects would be ``implements()``. This builtin
|
||||
would expect two arguments, an object and an interface, and return
|
||||
a true value if the object implements the interface, false
|
||||
otherwise. For example::
|
||||
|
||||
>>> interface FooInterface: pass
|
||||
>>> class Foo implements FooInterface: pass
|
||||
>>> f = Foo()
|
||||
>>> implements(f, FooInterface)
|
||||
1
|
||||
>>> interface FooInterface: pass
|
||||
>>> class Foo implements FooInterface: pass
|
||||
>>> f = Foo()
|
||||
>>> implements(f, FooInterface)
|
||||
1
|
||||
|
||||
Currently, this functionality exists in the reference
|
||||
implementation as functions in the `Interface' package, requiring
|
||||
an "import Interface" to use it. Its existence as a built-in
|
||||
would be purely for a convenience, and not necessary for using
|
||||
interfaces, and analogous to `isinstance()' for classes.
|
||||
Currently, this functionality exists in the reference
|
||||
implementation as functions in the ``Interface`` package, requiring
|
||||
an "import Interface" to use it. Its existence as a built-in
|
||||
would be purely for a convenience, and not necessary for using
|
||||
interfaces, and analogous to ``isinstance()`` for classes.
|
||||
|
||||
|
||||
Backward Compatibility
|
||||
======================
|
||||
|
||||
The proposed interface model does not introduce any backward
|
||||
compatibility issues in Python. The proposed syntax, however,
|
||||
does.
|
||||
The proposed interface model does not introduce any backward
|
||||
compatibility issues in Python. The proposed syntax, however,
|
||||
does.
|
||||
|
||||
Any existing code that uses `interface' as an identifier will
|
||||
break. There may be other kinds of backwards incompatibility that
|
||||
defining `interface' as a new keyword will introduce. This
|
||||
extension to Python's syntax does not change any existing syntax
|
||||
in any backward incompatible way.
|
||||
Any existing code that uses ``interface`` as an identifier will
|
||||
break. There may be other kinds of backwards incompatibility that
|
||||
defining ``interface`` as a new keyword will introduce. This
|
||||
extension to Python's syntax does not change any existing syntax
|
||||
in any backward incompatible way.
|
||||
|
||||
The new `from __future__' Python syntax[6], and the new warning
|
||||
framework [7] is ideal for resolving this backward
|
||||
incompatibility. To use interface syntax now, a developer could
|
||||
use the statement:
|
||||
The new ``from __future__`` Python syntax [6]_, and the new warning
|
||||
framework [7]_ is ideal for resolving this backward
|
||||
incompatibility. To use interface syntax now, a developer could
|
||||
use the statement::
|
||||
|
||||
from __future__ import interfaces
|
||||
from __future__ import interfaces
|
||||
|
||||
In addition, any code that uses the keyword `interface' as an
|
||||
identifier will be issued a warning from Python. After the
|
||||
appropriate period of time, the interface syntax would become
|
||||
standard, the above import statement would do nothing, and any
|
||||
identifiers named `interface' would raise an exception. This
|
||||
period of time is proposed to be 24 months.
|
||||
In addition, any code that uses the keyword ``interface`` as an
|
||||
identifier will be issued a warning from Python. After the
|
||||
appropriate period of time, the interface syntax would become
|
||||
standard, the above import statement would do nothing, and any
|
||||
identifiers named ``interface`` would raise an exception. This
|
||||
period of time is proposed to be 24 months.
|
||||
|
||||
|
||||
Summary of Proposed Changes to Python
|
||||
=====================================
|
||||
|
||||
Adding new `interface' keyword and extending class syntax with
|
||||
`implements'.
|
||||
Adding new ``interface`` keyword and extending class syntax with
|
||||
``implements``.
|
||||
|
||||
Extending class interface to include __implements__.
|
||||
Extending class interface to include ``__implements__``.
|
||||
|
||||
Add 'implements(obj, interface)' built-in.
|
||||
Add 'implements(obj, interface)' built-in.
|
||||
|
||||
|
||||
Risks
|
||||
=====
|
||||
|
||||
This PEP proposes adding one new keyword to the Python language,
|
||||
`interface'. This will break code.
|
||||
This PEP proposes adding one new keyword to the Python language,
|
||||
``interface``. This will break code.
|
||||
|
||||
|
||||
Open Issues
|
||||
===========
|
||||
|
||||
Goals
|
||||
Goals
|
||||
-----
|
||||
|
||||
Syntax
|
||||
Syntax
|
||||
------
|
||||
|
||||
Architecture
|
||||
Architecture
|
||||
------------
|
||||
|
||||
|
||||
Dissenting Opinion
|
||||
==================
|
||||
|
||||
This PEP has not yet been discussed on python-dev.
|
||||
This PEP has not yet been discussed on python-dev.
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
[1] https://mail.python.org/pipermail/types-sig/1998-December/date.html
|
||||
.. [1] https://mail.python.org/pipermail/types-sig/1998-December/date.html
|
||||
|
||||
[2] http://www.zope.org
|
||||
.. [2] http://www.zope.org
|
||||
|
||||
[3] PEP 232, Function Attributes, Warsaw
|
||||
http://www.python.org/dev/peps/pep-0232/
|
||||
.. [3] PEP 232, Function Attributes, Warsaw
|
||||
http://www.python.org/dev/peps/pep-0232/
|
||||
|
||||
[4] PEP 233, Python Online Help, Prescod
|
||||
http://www.python.org/dev/peps/pep-0233/
|
||||
.. [4] PEP 233, Python Online Help, Prescod
|
||||
http://www.python.org/dev/peps/pep-0233/
|
||||
|
||||
[5] http://www.lemburg.com/files/python/mxProxy.html
|
||||
.. [5] http://www.lemburg.com/files/python/mxProxy.html
|
||||
|
||||
[6] PEP 236, Back to the __future__, Peters
|
||||
http://www.python.org/dev/peps/pep-0236/
|
||||
.. [6] PEP 236, Back to the __future__, Peters
|
||||
http://www.python.org/dev/peps/pep-0236/
|
||||
|
||||
[7] PEP 230, Warning Framework, van Rossum
|
||||
http://www.python.org/dev/peps/pep-0236/
|
||||
.. [7] PEP 230, Warning Framework, van Rossum
|
||||
http://www.python.org/dev/peps/pep-0236/
|
||||
|
||||
.. [8] Python Reference Manual
|
||||
http://docs.python.org/reference/
|
||||
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
This document has been placed in the public domain.
|
||||
This document has been placed in the public domain.
|
||||
|
||||
|
||||
|
||||
Local Variables:
|
||||
mode: indented-text
|
||||
indent-tabs-mode: nil
|
||||
End:
|
||||
|
||||
..
|
||||
Local Variables:
|
||||
mode: indented-text
|
||||
indent-tabs-mode: nil
|
||||
End:
|
||||
|
|
Loading…
Reference in New Issue