diff options
Diffstat (limited to 'doc/core/howto/components.html')
-rw-r--r-- | doc/core/howto/components.html | 603 |
1 files changed, 603 insertions, 0 deletions
diff --git a/doc/core/howto/components.html b/doc/core/howto/components.html new file mode 100644 index 0000000..b52e9e7 --- /dev/null +++ b/doc/core/howto/components.html @@ -0,0 +1,603 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Components: Interfaces and Adapters</title> +<link href="stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Components: Interfaces and Adapters</h1> + <div class="toc"><ol><li><a href="#auto0">Interfaces and Components in Twisted code</a></li><ul><li><a href="#auto1">Components and Inheritance</a></li></ul></ol></div> + <div class="content"> +<span/> + +<p>Object oriented programming languages allow programmers to reuse portions of +existing code by creating new <q>classes</q> of objects which subclass another +class. When a class subclasses another, it is said to <em>inherit</em> all of its +behaviour. The subclass can then <q>override</q> and <q>extend</q> the behavior +provided to it by the superclass. Inheritance is very useful in many situations, +but because it is so convenient to use, often becomes abused in large software +systems, especially when multiple inheritance is involved. One solution is to +use <em>delegation</em> instead of <q>inheritance</q> where appropriate. +Delegation is simply the act of asking <em>another</em> object to perform a task +for an object. To support this design pattern, which is often referred to as +the <em>components</em> pattern because it involves many small interacting +components, <em>interfaces</em> and <em>adapters</em> were created by the Zope +3 team.</p> + +<p><q>Interfaces</q> are simply markers which objects can use to say <q>I +implement this interface</q>. Other objects may then make requests like +<q>Please give me an object which implements interface X for object type Y</q>. +Objects which implement an interface for another object type are called +<q>adapters</q>.</p> + +<p>The superclass-subclass relationship is said to be an <em>is-a</em> relationship. +When designing object hierarchies, object modellers use subclassing when they +can say that the subclass <em>is</em> the same class as the superclass. For +example:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +</p><span class="py-src-keyword">class</span> <span class="py-src-identifier">Shape</span>: + <span class="py-src-variable">sideLength</span> = <span class="py-src-number">0</span> + <span class="py-src-keyword">def</span> <span class="py-src-identifier">getSideLength</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">sideLength</span> + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">setSideLength</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">sideLength</span>): + <span class="py-src-variable">self</span>.<span class="py-src-variable">sideLength</span> = <span class="py-src-variable">sideLength</span> + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">area</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">raise</span> <span class="py-src-variable">NotImplementedError</span>, <span class="py-src-string">"Subclasses must implement area"</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">Triangle</span>(<span class="py-src-parameter">Shape</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">area</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">return</span> (<span class="py-src-variable">self</span>.<span class="py-src-variable">sideLength</span> * <span class="py-src-variable">self</span>.<span class="py-src-variable">sideLength</span>) / <span class="py-src-number">2</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">Square</span>(<span class="py-src-parameter">Shape</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">area</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">sideLength</span> * <span class="py-src-variable">self</span>.<span class="py-src-variable">sideLength</span> +</pre> + +<p>In the above example, a Triangle <em>is-a</em> Shape, so it subclasses Shape, +and a Square <em>is-a</em> Shape, so it also subclasses Shape.</p> + +<p>However, subclassing can get complicated, especially when Multiple +Inheritance enters the picture. Multiple Inheritance allows a class to inherit +from more than one base class. Software which relies heavily on inheritance +often ends up having both very wide and very deep inheritance trees, meaning +that one class inherits from many superclasses spread throughout the system. +Since subclassing with Multiple Inheritance means <em>implementation +inheritance</em>, locating a method's actual implementation and ensuring the +correct method is actually being invoked becomes a challenge. For example:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +</p><span class="py-src-keyword">class</span> <span class="py-src-identifier">Area</span>: + <span class="py-src-variable">sideLength</span> = <span class="py-src-number">0</span> + <span class="py-src-keyword">def</span> <span class="py-src-identifier">getSideLength</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">sideLength</span> + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">setSideLength</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">sideLength</span>): + <span class="py-src-variable">self</span>.<span class="py-src-variable">sideLength</span> = <span class="py-src-variable">sideLength</span> + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">area</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">raise</span> <span class="py-src-variable">NotImplementedError</span>, <span class="py-src-string">"Subclasses must implement area"</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">Color</span>: + <span class="py-src-variable">color</span> = <span class="py-src-variable">None</span> + <span class="py-src-keyword">def</span> <span class="py-src-identifier">setColor</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">color</span>): + <span class="py-src-variable">self</span>.<span class="py-src-variable">color</span> = <span class="py-src-variable">color</span> + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">getColor</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">color</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">Square</span>(<span class="py-src-parameter">Area</span>, <span class="py-src-parameter">Color</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">area</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">sideLength</span> * <span class="py-src-variable">self</span>.<span class="py-src-variable">sideLength</span> +</pre> + +<p>The reason programmers like using implementation inheritance is because it +makes code easier to read since the implementation details of Area are in a +separate place than the implementation details of Color. This is nice, because +conceivably an object could have a color but not an area, or an area but not a +color. The problem, though, is that Square is not really an Area or a Color, but +has an area and color. Thus, we should really be using another object oriented +technique called <em>composition</em>, which relies on delegation rather than +inheritance to break code into small reusable chunks. Let us continue with the +Multiple Inheritance example, though, because it is often used in practice.</p> + +<p>What if both the Color and the Area base class defined the same +method, perhaps <code>calculate</code>? Where would the implementation +come from? The implementation that is located +for <code>Square().calculate()</code> depends on the method resolution +order, or MRO, and can change when programmers change seemingly +unrelated things by refactoring classes in other parts of the system, +causing obscure bugs. Our first thought might be to change the +calculate method name to avoid name clashes, to +perhaps <code>calculateArea</code> and <code>calculateColor</code>. +While explicit, this change could potentially require a large number +of changes throughout a system, and is error-prone, especially when +attempting to integrate two systems which you didn't write.</p> + +<p>Let's imagine another example. We have an electric appliance, say a hair +dryer. The hair dryer is American voltage. We have two electric sockets, one of +them an American 120 Volt socket, and one of them a United Kingdom 240 Volt socket. If +we plug the hair dryer into the 240 Volt socket, it is going to expect 120 Volt +current and errors will result. Going back and changing the hair dryer to +support both <code>plug120Volt</code> and <code>plug240Volt</code> methods would +be tedious, and what if we decided we needed to plug the hair dryer into yet +another type of socket? For example:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +</p><span class="py-src-keyword">class</span> <span class="py-src-identifier">HairDryer</span>: + <span class="py-src-keyword">def</span> <span class="py-src-identifier">plug</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">socket</span>): + <span class="py-src-keyword">if</span> <span class="py-src-variable">socket</span>.<span class="py-src-variable">voltage</span>() == <span class="py-src-number">120</span>: + <span class="py-src-keyword">print</span> <span class="py-src-string">"I was plugged in properly and am operating."</span> + <span class="py-src-keyword">else</span>: + <span class="py-src-keyword">print</span> <span class="py-src-string">"I was plugged in improperly and "</span> + <span class="py-src-keyword">print</span> <span class="py-src-string">"now you have no hair dryer any more."</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">AmericanSocket</span>: + <span class="py-src-keyword">def</span> <span class="py-src-identifier">voltage</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">return</span> <span class="py-src-number">120</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">UKSocket</span>: + <span class="py-src-keyword">def</span> <span class="py-src-identifier">voltage</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">return</span> <span class="py-src-number">240</span> +</pre> + +<p>Given these classes, the following operations can be performed:</p> + +<pre class="python-interpreter" xml:space="preserve"> +>>> hd = HairDryer() +>>> am = AmericanSocket() +>>> hd.plug(am) +I was plugged in properly and am operating. +>>> uk = UKSocket() +>>> hd.plug(uk) +I was plugged in improperly and +now you have no hair dryer any more. +</pre> + +<p>We are going to attempt to solve this problem by writing an Adapter for +the <code>UKSocket</code> which converts the voltage for use with an American +hair dryer. An Adapter is a class which is constructed with one and only one +argument, the <q>adaptee</q> or <q>original</q> object. In this example, we +will show all code involved for clarity:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +</p><span class="py-src-keyword">class</span> <span class="py-src-identifier">AdaptToAmericanSocket</span>: + <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">original</span>): + <span class="py-src-variable">self</span>.<span class="py-src-variable">original</span> = <span class="py-src-variable">original</span> + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">voltage</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">original</span>.<span class="py-src-variable">voltage</span>() / <span class="py-src-number">2</span> +</pre> + +<p>Now, we can use it as so:</p> + +<pre class="python-interpreter" xml:space="preserve"> +>>> hd = HairDryer() +>>> uk = UKSocket() +>>> adapted = AdaptToAmericanSocket(uk) +>>> hd.plug(adapted) +I was plugged in properly and am operating. +</pre> + +<p>So, as you can see, an adapter can 'override' the original implementation. It +can also 'extend' the interface of the original object by providing methods the +original object did not have. Note that an Adapter must explicitly delegate any +method calls it does not wish to modify to the original, otherwise the Adapter +cannot be used in places where the original is expected. Usually this is not a +problem, as an Adapter is created to conform an object to a particular interface +and then discarded.</p> + +<h2>Interfaces and Components in Twisted code<a name="auto0"/></h2> + +<p>Adapters are a useful way of using multiple classes to factor code into +discrete chunks. However, they are not very interesting without some more +infrastructure. If each piece of code which wished to use an adapted object had +to explicitly construct the adapter itself, the coupling between components +would be too tight. We would like to achieve <q>loose coupling</q>, and this is +where <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.python.components.html" title="twisted.python.components">twisted.python.components</a></code> comes in.</p> + +<p>First, we need to discuss Interfaces in more detail. As we mentioned +earlier, an Interface is nothing more than a class which is used as a marker. +Interfaces should be subclasses of <code>zope.interface.Interface</code>, and +have a very odd look to python programmers not used to them:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +7 +</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Interface</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">IAmericanSocket</span>(<span class="py-src-parameter">Interface</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">voltage</span>(): + <span class="py-src-string">""" + Return the voltage produced by this socket object, as an integer. + """</span> +</pre> + +<p>Notice how it looks just like a regular class definition, other than +inheriting from <code>Interface</code>? However, the method definitions inside +the class block do not have any method body! Since Python does not have any +native language-level support for Interfaces like Java does, this is what +distinguishes an Interface definition from a Class.</p> + +<p>Now that we have a defined Interface, we can talk about objects using terms +like this: <q>The <code>AmericanSocket</code> class implements the <code>IAmericanSocket</code> interface</q> and <q>Please give me an object which +adapts <code>UKSocket</code> to the <code>IAmericanSocket</code> +interface</q>. We can make <em>declarations</em> about what interfaces a certain +class implements, and we can request adapters which implement a certain +interface for a specific class.</p> + +<p>Let's look at how we declare that a class implements an interface:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +7 +8 +</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">AmericanSocket</span>: + + <span class="py-src-variable">implements</span>(<span class="py-src-variable">IAmericanSocket</span>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">voltage</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">return</span> <span class="py-src-number">120</span> +</pre> + +<p>So, to declare that a class implements an interface, we simply +call <code>zope.interface.implements</code> at the class level.</p> + +<p>Now, let's say we want to rewrite +the <code>AdaptToAmericanSocket</code> class as a real adapter. In +this case we also specify it as +implementing <code>IAmericanSocket</code>:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">AdaptToAmericanSocket</span>: + + <span class="py-src-variable">implements</span>(<span class="py-src-variable">IAmericanSocket</span>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">original</span>): + <span class="py-src-string">""" + Pass the original UKSocket object as original + """</span> + <span class="py-src-variable">self</span>.<span class="py-src-variable">original</span> = <span class="py-src-variable">original</span> + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">voltage</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">original</span>.<span class="py-src-variable">voltage</span>() / <span class="py-src-number">2</span> +</pre> + +<p>Notice how we placed the implements declaration on this adapter class. So +far, we have not achieved anything by using components other than requiring us +to type more. In order for components to be useful, we must use the +<em>component registry</em>. Since <code>AdaptToAmericanSocket</code> +implements +<code>IAmericanSocket</code> and regulates the voltage of a +<code>UKSocket</code> object, we can register +<code>AdaptToAmericanSocket</code> as an <code>IAmericanSocket</code> adapter +for the <code>UKSocket</code> class. It is easier to see how this is +done in code than to describe it:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Interface</span>, <span class="py-src-variable">implements</span> +<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">components</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">IAmericanSocket</span>(<span class="py-src-parameter">Interface</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">voltage</span>(): + <span class="py-src-string">"""Return the voltage produced by this socket object, as an integer. + """</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">AmericanSocket</span>: + <span class="py-src-variable">implements</span>(<span class="py-src-variable">IAmericanSocket</span>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">voltage</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">return</span> <span class="py-src-number">120</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">UKSocket</span>: + <span class="py-src-keyword">def</span> <span class="py-src-identifier">voltage</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">return</span> <span class="py-src-number">240</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">AdaptToAmericanSocket</span>: + + <span class="py-src-variable">implements</span>(<span class="py-src-variable">IAmericanSocket</span>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">original</span>): + <span class="py-src-variable">self</span>.<span class="py-src-variable">original</span> = <span class="py-src-variable">original</span> + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">voltage</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">original</span>.<span class="py-src-variable">voltage</span>() / <span class="py-src-number">2</span> + +<span class="py-src-variable">components</span>.<span class="py-src-variable">registerAdapter</span>( + <span class="py-src-variable">AdaptToAmericanSocket</span>, + <span class="py-src-variable">UKSocket</span>, + <span class="py-src-variable">IAmericanSocket</span>) +</pre> + +<p>Now, if we run this script in the interactive interpreter, we can discover a +little more about how to use components. The first thing we can do is discover +whether an object implements an interface or not:</p> + +<pre class="python-interpreter" xml:space="preserve"> +>>> IAmericanSocket.implementedBy(AmericanSocket) +True +>>> IAmericanSocket.implementedBy(UKSocket) +False +>>> am = AmericanSocket() +>>> uk = UKSocket() +>>> IAmericanSocket.providedBy(am) +True +>>> IAmericanSocket.providedBy(uk) +False +</pre> + +<p>As you can see, the <code>AmericanSocket</code> instance claims to +implement <code>IAmericanSocket</code>, but the <code>UKSocket</code> +does not. If we wanted to use the <code>HairDryer</code> with the <code>AmericanSocket</code>, we could know that it would be safe to do so by +checking whether it implements <code>IAmericanSocket</code>. However, if we +decide we want to use <code>HairDryer</code> with a <code>UKSocket</code> +instance, we must <em>adapt</em> it to <code>IAmericanSocket</code> before +doing so. We use the interface object to do this:</p> + +<pre class="python-interpreter" xml:space="preserve"> +>>> IAmericanSocket(uk) +<__main__.AdaptToAmericanSocket instance at 0x1a5120> +</pre> + +<p>When calling an interface with an object as an argument, the interface +looks in the adapter registry for an adapter which implements the interface for +the given instance's class. If it finds one, it constructs an instance of the +Adapter class, passing the constructor the original instance, and returns it. +Now the <code>HairDryer</code> can safely be used with the adapted <code>UKSocket</code>. But what happens if we attempt to adapt an object +which already implements <code>IAmericanSocket</code>? We simply get back the +original instance:</p> + +<pre class="python-interpreter" xml:space="preserve"> +>>> IAmericanSocket(am) +<__main__.AmericanSocket instance at 0x36bff0> +</pre> + +<p>So, we could write a new <q>smart</q> <code>HairDryer</code> which +automatically looked up an adapter for the socket you tried to plug it into:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +</p><span class="py-src-keyword">class</span> <span class="py-src-identifier">HairDryer</span>: + <span class="py-src-keyword">def</span> <span class="py-src-identifier">plug</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">socket</span>): + <span class="py-src-variable">adapted</span> = <span class="py-src-variable">IAmericanSocket</span>(<span class="py-src-variable">socket</span>) + <span class="py-src-keyword">assert</span> <span class="py-src-variable">adapted</span>.<span class="py-src-variable">voltage</span>() == <span class="py-src-number">120</span>, <span class="py-src-string">"BOOM"</span> + <span class="py-src-keyword">print</span> <span class="py-src-string">"I was plugged in properly and am operating"</span> +</pre> + +<p>Now, if we create an instance of our new <q>smart</q> <code>HairDryer</code> +and attempt to plug it in to various sockets, the <code>HairDryer</code> will +adapt itself automatically depending on the type of socket it is plugged in +to:</p> + +<pre class="python-interpreter" xml:space="preserve"> +>>> am = AmericanSocket() +>>> uk = UKSocket() +>>> hd = HairDryer() +>>> hd.plug(am) +I was plugged in properly and am operating +>>> hd.plug(uk) +I was plugged in properly and am operating +</pre> + +<p>Voila; the magic of components.</p> + +<h3>Components and Inheritance<a name="auto1"/></h3> + +<p>If you inherit from a class which implements some interface, and your new +subclass declares that it implements another interface, the implements will be +inherited by default.</p> + +<p>For example, <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.Root.html" title="twisted.spread.pb.Root">pb.Root</a></code> is a class +which implements <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.IPBRoot.html" title="twisted.spread.pb.IPBRoot">IPBRoot</a></code>. This interface indicates that an +object has remotely-invokable methods and can be used as the initial object +served by a new Broker instance. It has an <code>implements</code> setting +like:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">Root</span>(<span class="py-src-parameter">Referenceable</span>): + <span class="py-src-variable">implements</span>(<span class="py-src-variable">IPBRoot</span>) +</pre> + +<p>Suppose you have your own class which implements your +<code>IMyInterface</code> interface:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +7 +</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>, <span class="py-src-variable">Interface</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">IMyInterface</span>(<span class="py-src-parameter">Interface</span>): + <span class="py-src-keyword">pass</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">MyThing</span>: + <span class="py-src-variable">implements</span>(<span class="py-src-variable">IMyInterface</span>) +</pre> + +<p>Now if you want to make this class inherit from <code>pb.Root</code>, +the interfaces code will automatically determine that it also implements +<code>IPBRoot</code>:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +7 +8 +</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span> +<span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>, <span class="py-src-variable">Interface</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">IMyInterface</span>(<span class="py-src-parameter">Interface</span>): + <span class="py-src-keyword">pass</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">MyThing</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Root</span>): + <span class="py-src-variable">implements</span>(<span class="py-src-variable">IMyInterface</span>) +</pre> + +<pre class="python-interpreter" xml:space="preserve"> +>>> from twisted.spread.flavors import IPBRoot +>>> IPBRoot.implementedBy(MyThing) +True +</pre> + +<p>If you want <code>MyThing</code> to inherit from <code>pb.Root</code> but <em>not</em> implement <code>IPBRoot</code> like <code>pb.Root</code> does, +use <code>implementOnly</code>:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +7 +8 +</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span> +<span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implementsOnly</span>, <span class="py-src-variable">Interface</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">IMyInterface</span>(<span class="py-src-parameter">Interface</span>): + <span class="py-src-keyword">pass</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">MyThing</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Root</span>): + <span class="py-src-variable">implementsOnly</span>(<span class="py-src-variable">IMyInterface</span>) +</pre> + +<pre class="python-interpreter" xml:space="preserve"> +>>> from twisted.spread.pb import IPBRoot +>>> IPBRoot.implementedBy(MyThing) +False +</pre> + +</div> + + <p><a href="index.html">Index</a></p> + <span class="version">Version: 12.1.0</span> + </body> +</html>
\ No newline at end of file |