Now we are finally ready to implement the content components of the package. This is the heart of this chapter. But how do we know which methods and properties we have to implement? There is a neat tool called pyskel.py in ZOPE3/utiltities that generates a skeleton. Go to ZOPE3/src and type:

现在,我们终于准备好要实现这个软件包的内容组件了。这是本章节的核心部分。但是我们如何知道我们应当诠释哪些方法和属性呢? 在ZOPE3/utilites中有一个名为pyskel.py的好工具,它能够生成一个框架。进入ZOPE3/src,然后键入:

1 python2.3 ../utilities/pyskel.py \ 2 book.messageboard.interfaces.IMessageBoard

The expected result is shown below. The tool inspects the given interface and creates the skeleton of an implementing class. It also recurses into all base interfaces to get their methods. Here the generated code:

预计的输出结果显示如下。该工具检查给定的接口并创建该接口的实现类的框架。它还会递归进入所有基础接口,并获取他们的方法。以下是生成的代码:

  • 1 from zope.interface import implements 2 from book.messageboard.interfaces import IMessageBoard 3

    4 class MessageBoard: 5 doc = IMessageBoard.doc 6 7 implements(IMessageBoard) 8 9

10 def setitem(self, name, object): 11 "See book.messageboard.interfaces.IMessageBoard" 12 13 # See book.messageboard.interfaces.IMessageBoard 14 description = None 15 16 def getitem(self, key): 17 "See zope.interface.common.mapping.IItemMapping" 18 19 def get(self, key, default=None): 20 "See zope.interface.common.mapping.IReadMapping" 21 22 def contains(self, key): 23 "See zope.interface.common.mapping.IReadMapping" 24 25 def getitem(self, key): 26 "See zope.interface.common.mapping.IItemMapping" 27 28 def keys(self): 29 "See zope.interface.common.mapping.IEnumerableMapping" 30 31 def iter(self): 32 "See zope.interface.common.mapping.IEnumerableMapping" 33 34 def values(self): 35 "See zope.interface.common.mapping.IEnumerableMapping" 36 37 def items(self): 38 "See zope.interface.common.mapping.IEnumerableMapping" 39 40 def len(self): 41 "See zope.interface.common.mapping.IEnumerableMapping" 42 43 def get(self, key, default=None): 44 "See zope.interface.common.mapping.IReadMapping" 45 46 def contains(self, key): 47 "See zope.interface.common.mapping.IReadMapping" 48 49 def getitem(self, key): 50 "See zope.interface.common.mapping.IItemMapping" 51 52 def setitem(self, name, object): 53 "See zope.app.container.interfaces.IWriteContainer" 54 55 def delitem(self, name): 56 "See zope.app.container.interfaces.IWriteContainer"

This result is good but some parts are unnecessary; we will for example simply inherit the BTreeContainer base component, so that we do not have to implement the methods from the IReadMapping, IEnumerableMapping, IReadMapping, IItemMapping and IWriteContainer interfaces.

该结果已经非常好了,不过还需要另外一些部分;例如我们需要简单的基础BTreeContainer基础组件,这样我们就不需要来自IReadMapping、IEnumberableMapping、IReadMapping、IItemMapping和 IWriteContainer接口中的方法。

Open a new file called messageboard.py for editing. The implementation of the message board including doc tests looks like this:

打开一个名为messageboard.py的新文件进行编辑。包含文档测试件的message board的实现如下所示:

  • 1 from zope.interface import implements 2 from zope.app.container.btree import BTreeContainer 3 4 from book.messageboard.interfaces import IMessageBoard 5

    6 class MessageBoard(BTreeContainer): 7 """A very simple implementation of a message board using B-Tree Containers 8 9 Make sure that the MessageBoard implements the IMessageBoard

10 interface: 11 12 >>> from zope.interface.verify import verifyClass 13 >>> verifyClass(IMessageBoard, MessageBoard) 14 True 15 16 Here is an example of changing the description of the board: 17 18 >>> board = MessageBoard() 19 >>> board.description 20 u 21 >>> board.description = u'Message Board Description' 22 >>> board.description 23 u'Message Board Description' 24 """ 25 implements(IMessageBoard) 26 27 # See book.messageboard.interfaces.IMessageBoard 28 description = u

  • Line 1: The implements() method is used to declare that a class implements one or more interfaces. See “An Introduction to Interfaces” for more details.
  • 第一行:implements()方式用来申明某个类实现了一个或多个接口。详见“接口介绍”。
  • Line 2: Everything that has to do with containers is located in zope. app.container. BTreeContainers are a very efficient implementation of the IContainer interface and are commonly used as base classes for other containerish objects, such as the message board.
  • 第二行:与容器相关的所有东西都在zope.app.container中,BTreeContainers是IContainer接口的一个非常高效的实现,通常被用作其他容器对象的基类,例如message board的基类。
  • Line 7-24: The class docstring’s purpose is to document the class. To follow Python documentation standards, all docstrings should be using the re-structured text format. And doc tests are considered documentation, so it should be written in a narrative style.
  • 第7-24行:该类的docstring的目的是对该类编著文档。按照Python文档的标准,所有的docstrings应当使用re-structured text 格式。文档测试是一种文档,因此应当按照某种叙述性的风格进行编写。

· On line 12-14 we verify that the MessageBoard component really implements IMessageBoard. The verifyClass function actually checks the object for the existence of the specified attributes and methods.

· 第12-14行,我们验证该MessageBoard组件确实实现的是IMessageBoard. 这个验证函数会对该对象存在的指定属性和方法进行实际的检查。

Lines 18 through 23 just give a demonstration about the default description value and how it can be set. The test seems trivial, but at some point you might change the implementation of the description attribute to using properties and the test should still pass.

  • 第18-23行只是给出关于缺省描述值以及如何进行设置的演示。这个测试看起来微不足道,但是有时你可能需要使用属性来修改这个描述属性的诠释,而这个测试应当仍然能够通过。
  • Line 25: Here we tell the class that it implements IMessage. This function call might seem like magic, since one might wonder how the function knows as to which class to assign the interface. For the ones interested, it uses sys.getframe().
  • 第25行:在此,我们告诉该类它实现的是IMessage。该函数调用看起来有点神秘,因为可能有人会困惑这个函数是如何知道哪个类要指派给这个接口。告诉有兴趣的读者,它使用的是sys.getframe()。
  • Line 27-28: Make the description a simple attribute.

Note: Python is very unique in this way. In almost any other object-oriented language (for example Java) one would have written an accessor ( getDescription()) and a mutator ( setDescription(desc)) method. However, Python’s attribute and property support makes this unnecessary, which in turn makes the code cleaner.

  • 第27 -28行:将描述作为一个简单的属性。注意:Python在这种方式下非常独特。在几乎所有的面向对象语言(例如Java)中,有人可能已经编写了一个 accessor(getDescription())和一个mutator(setDescription(desc))方法。但是,Python的属 性和特征能够使得这是不必要的,这样就使得代码更加简介。

The next task is to write the Message object, which is pretty much the same code. Therefore we will not list it here and refer you to the code at http://svn.zope.org/book/trunk/messageboard/step01/message.py. The only difference is that in this case the Message component must implement IMessage, IMessageContained, and IMessageContainer.