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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
<?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 xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.4: http://docutils.sourceforge.net/" />
<title>Proxy objects</title>
<link rel="stylesheet" href="html4css1.css" type="text/css" />
</head>
<body>
<div class="header">
<a class="reference" href="manager-objects.html">Prev</a> <a class="reference" href="processing-ref.html">Up</a> <a class="reference" href="pool-objects.html">Next</a>
<hr class="header"/>
</div>
<div class="document" id="proxy-objects">
<h1 class="title">Proxy objects</h1>
<p>A proxy is an object which <em>refers</em> to a shared object which lives
(presumably) in a different process. The shared object is said to be
the <em>referent</em> of the proxy. Multiple proxy objects may have the same
referent.</p>
<p>A proxy object has methods which invoke corresponding methods of its
referent (although not every method of the referent will
necessarily be available through the proxy). A proxy can usually be
used in most of the same ways that the its referent can:</p>
<pre class="literal-block">
>>> from processing import Manager
>>> manager = Manager()
>>> l = manager.list([i*i for i in range(10)])
>>> print l
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> print repr(l)
<Proxy[list] object at 0x00DFA230>
>>> l[4]
16
>>> l[2:5]
[4, 9, 16]
>>> l == [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
True
</pre>
<p>Notice that applying <tt class="docutils literal"><span class="pre">str()</span></tt> to a proxy will return the
representation of the referent, whereas applying <tt class="docutils literal"><span class="pre">repr()</span></tt> will
return the representation of the proxy.</p>
<p>An important feature of proxy objects is that they are picklable so
they can be passed between processes. Note, however, that if a proxy
is sent to the corresponding manager's process then unpickling it will
produce the referent itself. This means, for example, that one shared
object can contain a second:</p>
<pre class="literal-block">
>>> a = manager.list()
>>> b = manager.list()
>>> a.append(b) # referent of `a` now contains referent of `b`
>>> print a, b
[[]] []
>>> b.append('hello')
>>> print a, b
[['hello']] ['hello']
</pre>
<p>Some proxy methods return a proxy for an iterator. In particular list
and dictionary proxies are iterables so they can be used with the
<tt class="docutils literal"><span class="pre">for</span></tt> statement:</p>
<pre class="literal-block">
>>> a = manager.dict([(i*i, i) for i in range(10)])
>>> for key in a:
... print '<%r,%r>' % (key, a[key]),
...
<0,0> <1,1> <4,2> <81,9> <64,8> <9,3> <16,4> <49,7> <25,5> <36,6>
</pre>
<div class="note">
<p class="first admonition-title">Note</p>
<p>Although <tt class="docutils literal"><span class="pre">list</span></tt> and <tt class="docutils literal"><span class="pre">dict</span></tt> proxy objects are iterable, it will be
much more efficient to iterate over a <em>copy</em> of the referent, for
example</p>
<pre class="literal-block">
for item in some_list[:]:
...
</pre>
<p>and</p>
<pre class="last literal-block">
for key in some_dict.keys():
...
</pre>
</div>
<div class="section">
<h1><a id="methods-of-baseproxy" name="methods-of-baseproxy">Methods of <tt class="docutils literal"><span class="pre">BaseProxy</span></tt></a></h1>
<p>Proxy objects are instances of subclasses of <tt class="docutils literal"><span class="pre">BaseProxy</span></tt>. The only
semi-public methods of <tt class="docutils literal"><span class="pre">BaseProxy</span></tt> are the following:</p>
<blockquote>
<dl class="docutils">
<dt><tt class="docutils literal"><span class="pre">_callMethod(methodname,</span> <span class="pre">args=(),</span> <span class="pre">kwds={})</span></tt></dt>
<dd><p class="first">Call and return the result of a method of the proxy's referent.</p>
<p>If <tt class="docutils literal"><span class="pre">proxy</span></tt> is a proxy whose referent is <tt class="docutils literal"><span class="pre">obj</span></tt> then the
expression</p>
<blockquote>
<tt class="docutils literal"><span class="pre">proxy._callMethod(methodname,</span> <span class="pre">args,</span> <span class="pre">kwds)</span></tt></blockquote>
<p>will evaluate the expression</p>
<blockquote>
<tt class="docutils literal"><span class="pre">getattr(obj,</span> <span class="pre">methodname)(*args,</span> <span class="pre">**kwds)</span></tt> <span class="target" id="id1">(*)</span></blockquote>
<p>in the manager's process.</p>
<p>The returned value will be either a copy of the result of
<a class="reference" href="#id1">(*)</a> or if the result is an unpicklable iterator then a
proxy for the iterator.</p>
<p>If an exception is raised by <a class="reference" href="#id1">(*)</a> then then is re-raised by
<tt class="docutils literal"><span class="pre">_callMethod()</span></tt>. If some other exception is raised in the
manager's process then this is converted into a <tt class="docutils literal"><span class="pre">RemoteError</span></tt>
exception and is raised by <tt class="docutils literal"><span class="pre">_callMethod()</span></tt>.</p>
<p class="last">Note in particular that an exception will be raised if
<tt class="docutils literal"><span class="pre">methodname</span></tt> has not been <em>exposed</em> --- see the <tt class="docutils literal"><span class="pre">exposed</span></tt>
argument to <a class="reference" href="manager-objects.html#customized-managers">CreatorMethod</a>.</p>
</dd>
<dt><tt class="docutils literal"><span class="pre">_getValue()</span></tt></dt>
<dd><p class="first">Return a copy of the referent.</p>
<p class="last">If the referent is unpicklable then this will raise an exception.</p>
</dd>
<dt><tt class="docutils literal"><span class="pre">__repr__</span></tt></dt>
<dd>Return a representation of the proxy object.</dd>
<dt><tt class="docutils literal"><span class="pre">__str__</span></tt></dt>
<dd>Return the representation of the referent.</dd>
</dl>
</blockquote>
</div>
<div class="section">
<h1><a id="cleanup" name="cleanup">Cleanup</a></h1>
<p>A proxy object uses a weakref callback so that when it gets garbage
collected it deregisters itself from the manager which owns its
referent.</p>
<p>A shared object gets deleted from the manager process when there
are no longer any proxies referring to it.</p>
</div>
<div class="section">
<h1><a id="examples" name="examples">Examples</a></h1>
<p>An example of the usage of <tt class="docutils literal"><span class="pre">_callMethod()</span></tt>:</p>
<pre class="literal-block">
>>> l = manager.list(range(10))
>>> l._callMethod('__getslice__', (2, 7)) # equiv to `l[2:7]`
[2, 3, 4, 5, 6]
>>> l._callMethod('__iter__') # equiv to `iter(l)`
<Proxy[iter] object at 0x00DFAFF0>
>>> l._callMethod('__getitem__', (20,)) # equiv to `l[20]`
Traceback (most recent call last):
...
IndexError: list index out of range
</pre>
<p>As an example definition of a subclass of BaseProxy, the proxy type
used for iterators is the following:</p>
<pre class="literal-block">
class IteratorProxy(BaseProxy):
def __iter__(self):
return self
def next(self):
return self._callMethod('next')
</pre>
</div>
</div>
<div class="footer">
<hr class="footer" />
<a class="reference" href="manager-objects.html">Prev</a> <a class="reference" href="processing-ref.html">Up</a> <a class="reference" href="pool-objects.html">Next</a>
</div>
</body>
</html>
|