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 160
|
.. include:: header.txt
===============
Proxy objects
===============
A proxy is an object which *refers* to a shared object which lives
(presumably) in a different process. The shared object is said to be
the *referent* of the proxy. Multiple proxy objects may have the same
referent.
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::
>>> 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
Notice that applying `str()` to a proxy will return the
representation of the referent, whereas applying `repr()` will
return the representation of the proxy.
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::
>>> 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']
Some proxy methods return a proxy for an iterator. In particular list
and dictionary proxies are iterables so they can be used with the
`for` statement::
>>> 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>
.. note::
Although `list` and `dict` proxy objects are iterable, it will be
much more efficient to iterate over a *copy* of the referent, for
example ::
for item in some_list[:]:
...
and ::
for key in some_dict.keys():
...
Methods of `BaseProxy`
======================
Proxy objects are instances of subclasses of `BaseProxy`. The only
semi-public methods of `BaseProxy` are the following:
`_callMethod(methodname, args=(), kwds={})`
Call and return the result of a method of the proxy's referent.
If `proxy` is a proxy whose referent is `obj` then the
expression
`proxy._callMethod(methodname, args, kwds)`
will evaluate the expression
`getattr(obj, methodname)(*args, **kwds)` |spaces| _`(*)`
in the manager's process.
The returned value will be either a copy of the result of
`(*)`_ or if the result is an unpicklable iterator then a
proxy for the iterator.
If an exception is raised by `(*)`_ then then is re-raised by
`_callMethod()`. If some other exception is raised in the
manager's process then this is converted into a `RemoteError`
exception and is raised by `_callMethod()`.
Note in particular that an exception will be raised if
`methodname` has not been *exposed* --- see the `exposed`
argument to `CreatorMethod
<manager-objects.html#customized-managers>`_.
`_getValue()`
Return a copy of the referent.
If the referent is unpicklable then this will raise an exception.
`__repr__`
Return a representation of the proxy object.
`__str__`
Return the representation of the referent.
Cleanup
=======
A proxy object uses a weakref callback so that when it gets garbage
collected it deregisters itself from the manager which owns its
referent.
A shared object gets deleted from the manager process when there
are no longer any proxies referring to it.
Examples
========
An example of the usage of `_callMethod()`::
>>> 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
As an example definition of a subclass of BaseProxy, the proxy type
used for iterators is the following::
class IteratorProxy(BaseProxy):
def __iter__(self):
return self
def next(self):
return self._callMethod('next')
.. _Prev: manager-objects.html
.. _Up: processing-ref.html
.. _Next: pool-objects.html
|