Movatterモバイル変換


[0]ホーム

URL:


Following system colour schemeSelected dark colour schemeSelected light colour scheme

Python Enhancement Proposals

PEP 245 – Python Interface Syntax

PEP 245 – Python Interface Syntax

Author:
Michel Pelletier <michel at users.sourceforge.net>
Status:
Rejected
Type:
Standards Track
Created:
11-Jan-2001
Python-Version:
2.2
Post-History:
21-Mar-2001

Table of Contents

Note

The no-longer-available Zope interfaces wiki page(https://www.zope.org/Wikis/Interfaces) originally linked here,containing links to further resources for this PEP,can befound on the Wayback Machine archive.Also, the Interface-Dev Zope mailing list on which this PEP was discussedwas shut down, butits archives remain available.

Rejection Notice

I’m rejecting this PEP. It’s been five years now. While at somepoint I expect that Python will have interfaces, it would be naiveto expect it to resemble the syntax in this PEP. Also,PEP 246 isbeing rejected in favor of something completely different; interfaceswon’t play a role in adaptation or whatever will replace it. GvR.

Introduction

This PEP describes a proposed syntax for creating interfaceobjects in Python.

Overview

In addition to thinking about adding a static type system toPython, the Types-SIG was also charged to devise an interfacesystem for Python. In December of 1998, Jim Fulton released aprototype interfaces system based on discussions from the SIG.Many of the issues and background information on this discussionand prototype can be found in the SIG archives[1].

Around the end of 2000, Digital Creations began thinking aboutbetter component model designs for Zope[2]. Zope’s futurecomponent model relies heavily on interface objects. This led tofurther development of Jim’s “Scarecrow” interfaces prototype.Starting with version 2.3, Zope comes with an Interface package asstandard software. Zope’s Interface package is used as thereference implementation for this PEP.

The syntax proposed by this PEP relies on syntax enhancementsdescribe inPEP 232 and describes an underlying frameworkwhichPEP 233 could be based upon. There is some work beingdone with regard to interface objects and Proxy objects, so forthose optional parts of this PEP you may want to see[3].

The Problem

Interfaces are important because they solve a number of problemsthat arise while developing software:

  • There are many implied interfaces in Python, commonly referredto as “protocols”. Currently determining those protocols isbased on implementation introspection, but often that alsofails. For example, defining__getitem__ implies both asequence and a mapping (the former with sequential, integerkeys). There is no way for the developer to be explicit aboutwhich protocols the object intends to implement.
  • Python is limited, from the developer’s point of view, by thesplit between types and classes. When types are expected, theconsumer uses code like ‘type(foo) == type(“”)’ to determine if‘foo’ is a string. When instances of classes are expected, theconsumer uses ‘isinstance(foo, MyString)’ to determine if ‘foo’is an instance of the ‘MyString’ class. There is no unifiedmodel for determining if an object can be used in a certain,valid way.
  • Python’s dynamic typing is very flexible and powerful, but itdoes not have the advantage of static typed languages thatprovide type checking. Static typed languages provide you withmuch more type safety, but are often overly verbose becauseobjects can only be generalized by common subclassing and usedspecifically with casting (for example, in Java).

There are also a number of documentation problems that interfacestry to solve.

  • Developers waste a lot of time looking at the source code ofyour system to figure out how objects work.
  • Developers who are new to your system may misunderstand how yourobjects work, causing, and possibly propagating, usage errors.
  • Because a lack of interfaces means usage is inferred from thesource, developers may end up using methods and attributes thatare meant for “internal use only”.
  • Code inspection can be hard, and very discouraging to noviceprogrammers trying to properly understand code written by gurus.
  • A lot of time is wasted when many people try very hard tounderstand obscurity (like undocumented software). Effort spendup front documenting interfaces will save much of this time inthe end.

Interfaces try to solve these problems by providing a way for youto specify a contractual obligation for your object, documentationon how to use an object, and a built-in mechanism for discoveringthe contract and the documentation.

Python has very useful introspection features. It is well knownthat this makes exploring concepts in the interactive interpretereasier, because Python gives you the ability to look at all kindsof information about the objects: the type, doc strings, instancedictionaries, base classes, unbound methods and more.

Many of these features are oriented toward introspecting, usingand changing the implementation of software, and one of them (“docstrings”) is oriented toward providing documentation. Thisproposal describes an extension to this natural introspectionframework that describes an object’s interface.

Overview of the Interface Syntax

For the most part, the syntax of interfaces is very much like thesyntax of classes, but future needs, or needs brought up indiscussion, 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 twodifferent interfaces created with the proposed syntax:

interfaceCountFishInterface:"Fish counting interface"defoneFish():"Increments the fish count by one"deftwoFish():"Increments the fish count by two"defgetFishCount():"Returns the fish count"interfaceColorFishInterface:"Fish coloring interface"defredFish():"Sets the current fish color to red"defblueFish():"Sets the current fish color to blue"defgetFishColor():"This returns the current fish color"

This code, when evaluated, will create two interfaces calledCountFishInterface andColorFishInterface. These interfacesare defined by theinterface statement.

The prose documentation for the interfaces and their methods comefrom doc strings. The method signature information comes from thesignatures of thedef statements. Notice how there is no bodyfor the def statements. The interface does not implement aservice to anything; it merely describes one. Documentationstrings on interfaces and interface methods are mandatory, a‘pass’ statement cannot be provided. The interface equivalent ofa 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 theCountFishInterface and ColorFishInterface:

interfaceFishMarketInterface(CountFishInterface,ColorFishInterface):"This is the documentation for the FishMarketInterface"defgetFishMonger():"Returns the fish monger you can interact with"defhireNewFishMonger(name):"Hire a new fish monger"defbuySomeFish(quantity=1):"Buy some fish at the market"

The FishMarketInterface extends upon the CountFishInterface andColorfishInterface.

Interface Assertion

The next step is to put classes and interfaces together bycreating a concrete Python class that asserts that it implementsan interface. Here is an example FishMarket component that mightdo this:

classFishError(Error):passclassFishMarketimplementsFishMarketInterface:number=0color=Nonemonger_name='Crusty Barnacles'def__init__(self,number,color):self.number=numberself.color=colordefoneFish(self):self.number+=1deftwoFish(self):self.number+=2defredFish(self):self.color='red'defblueFish(self):self.color='blue'defgetFishCount(self):returnself.numberdefgetFishColor(self):returnself.colordefgetFishMonger(self):returnself.monger_namedefhireNewFishMonger(self,name):self.monger_name=namedefbuySomeFish(self,quantity=1):ifquantity>self.count:raiseFishError("There's not enough fish")self.count-=quantityreturnquantity

This new class, FishMarket defines a concrete class whichimplements the FishMarketInterface. The object following theimplements statement is called an “interface assertion”. Aninterface assertion can be either an interface object, or tuple ofinterface assertions.

The interface assertion provided in aclass statement like thisis stored in the class’s__implements__ class attribute. Afterinterpreting the above example, you would have a class statementthat can be examined like this with an ‘implements’ built-infunction:

>>>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 youhad an interface calledItemInterface that described how anobject worked as an item in a container object. If you wanted toassert that FishMarket instances realized the ItemInterfaceinterface as well as the FishMarketInterface, you can provide aninterface assertion that contained a tuple of interface objects tothe FishMarket class:

classFishMarketimplementsFishMarketInterface,ItemInterface:# ...

Interface assertions can also be used if you want to assert thatone class implements an interface, and all of the interfaces thatanother class implements:

classMyFishMarketimplementsFishMarketInterface,ItemInterface:# ...classYourFishMarketimplementsFooInterface,MyFishMarket.__implements__:# ...

This new class YourFishMarket, asserts that it implements theFooInterface, as well as the interfaces implemented by theMyFishMarket class.

It’s worth going into a little bit more detail about interfaceassertions. An interface assertion is either an interface object,or a tuple of interface assertions. For example:

FooInterfaceFooInterface,(BarInterface,BobInterface)FooInterface,(BarInterface,(BobInterface,MyClass.__implements__))

Are all valid interface assertions. When two interfaces definethe same attributes, the order in which information is preferredin the assertion is from top-to-bottom, left-to-right.

There are other interface proposals that, in the need forsimplicity, have combined the notion of class and interface toprovide simple interface enforcement. Interface objects have adeferred method that returns a deferred class that implementsthis behavior:

>>>FM=FishMarketInterface.deferred()>>>classMyFM(FM):pass>>>f=MyFM()>>>f.getFishMonger()Traceback (innermost last):  File"<stdin>", line1, in?Interface.Exceptions.BrokenImplementation:An object has failed to implement interface FishMarketInterface        The getFishMonger attribute was not provided.>>>

This provides for a bit of passive interface enforcement bytelling you what you forgot to do to implement that interface.

Formal Interface Syntax

Python syntax is defined in a modified BNF grammar notationdescribed in the Python Reference Manual[4]. This sectiondescribes the proposed interface syntax using this grammar:

interfacedef:"interface"interfacename[extends]":"suiteextends:"("[expression_list]")"interfacename:identifier

An interface definition is an executable statement. It firstevaluates the extends list, if present. Each item in the extendslist 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 newlycreated local namespace and the original global namespace. Whenthe interface’s suite finishes execution, its execution frame isdiscarded but its local namespace is saved as interface elements.An interface object is then created using the extends list for thebase interfaces and the saved interface elements. The interfacename is bound to this interface object in the original localnamespace.

This PEP also proposes an extension to Python’s ‘class’ statement:

classdef:"class"classname[inheritance][implements]":"suiteimplements:"implements"implistimplist:expression-listclassname,inheritance,suite,expression-list:seethePythonReferenceManual

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 ofthe Language Reference.

The ‘implements’, if present, is evaluated after inheritance.This must evaluate to an interface specification, which is eitheran interface, or a tuple of interface specifications. If a validinterface specification is present, the assertion is assigned tothe class object’s ‘__implements__’ attribute, as a tuple.

This PEP does not propose any changes to the syntax of functiondefinitions or assignments.

Classes and Interfaces

The example interfaces above do not describe any kind of behaviorfor their methods, they just describe an interface that a typicalFishMarket object would realize.

You may notice a similarity between interfaces extending fromother interfaces and classes sub-classing from other classes.This is a similar concept. However it is important to note thatinterfaces extend interfaces and classes subclass classes. Youcannot extend a class or subclass an interface. Classes andinterfaces are separate.

The purpose of a class is to share the implementation of how anobject works. The purpose of an interface is to document how towork with an object, not how the object is implemented. It ispossible to have several different classes with very differentimplementations realize the same interface.

It’s also possible to implement one interface with many classesthat mix in pieces the functionality of the interface or,conversely, it’s possible to have one class implement manyinterfaces. Because of this, interfaces and classes should not beconfused or intermingled.

Interface-aware built-ins

A useful extension to Python’s list of built-in functions in thelight of interface objects would beimplements(). This builtinwould expect two arguments, an object and an interface, and returna true value if the object implements the interface, falseotherwise. For example:

>>>interfaceFooInterface:pass>>>classFooimplementsFooInterface:pass>>>f=Foo()>>>implements(f,FooInterface)1

Currently, this functionality exists in the referenceimplementation as functions in theInterface package, requiringan “import Interface” to use it. Its existence as a built-inwould be purely for a convenience, and not necessary for usinginterfaces, and analogous toisinstance() for classes.

Backward Compatibility

The proposed interface model does not introduce any backwardcompatibility issues in Python. The proposed syntax, however,does.

Any existing code that usesinterface as an identifier willbreak. There may be other kinds of backwards incompatibility thatdefininginterface as a new keyword will introduce. Thisextension to Python’s syntax does not change any existing syntaxin any backward incompatible way.

The newfrom__future__ Python syntax (PEP 236), and the new warningframework (PEP 230) is ideal for resolving this backwardincompatibility. To use interface syntax now, a developer coulduse the statement:

from__future__importinterfaces

In addition, any code that uses the keywordinterface as anidentifier will be issued a warning from Python. After theappropriate period of time, the interface syntax would becomestandard, the above import statement would do nothing, and anyidentifiers namedinterface would raise an exception. Thisperiod of time is proposed to be 24 months.

Summary of Proposed Changes to Python

Adding newinterface keyword and extending class syntax withimplements.

Extending class interface to include__implements__.

Add ‘implements(obj, interface)’ built-in.

Risks

This PEP proposes adding one new keyword to the Python language,interface. This will break code.

Open Issues

Goals

Syntax

Architecture

Dissenting Opinion

This PEP has not yet been discussed on python-dev.

References

[1]
https://mail.python.org/pipermail/types-sig/1998-December/date.html
[2]
http://www.zope.org
[3]
http://www.lemburg.com/files/python/mxProxy.html
[4]
Python Reference Manualhttp://docs.python.org/reference/

Copyright

This document has been placed in the public domain.


Source:https://github.com/python/peps/blob/main/peps/pep-0245.rst

Last modified:2025-02-01 08:59:27 GMT


[8]ページ先頭

©2009-2026 Movatter.jp