File: proxy-objects.txt

package info (click to toggle)
multiprocess 0.70.17-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 9,900 kB
  • sloc: python: 70,095; ansic: 7,509; makefile: 16
file content (160 lines) | stat: -rw-r--r-- 4,975 bytes parent folder | download | duplicates (38)
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