File: Acquisition.html

package info (click to toggle)
python-extclass 1.2-1
  • links: PTS
  • area: main
  • in suites: slink
  • size: 432 kB
  • ctags: 547
  • sloc: ansic: 4,549; python: 134; makefile: 46; sh: 18
file content (312 lines) | stat: -rw-r--r-- 10,954 bytes parent folder | download | duplicates (3)
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
<html><head><title>Acquisition</title>
	    </head><body>
	    <h1>Acquisition</h1>
<p>  <a href="COPYRIGHT.html">Copyright &copy; 1996-1998, Digital Creations</a>.</p>

<p>  Acquisition <a href="#1">[1]</a> is a mechanism that allows objects to obtain
  attributes from their environment.  It is similar to inheritence,
  except that, rather than traversing an inheritence hierarchy
  to obtain attributes, a containment hierarchy is traversed.</p>

<p>  The <a href="ExtensionClass.html">ExtensionClass</a>. release includes mix-in
  extension base classes that can be used to add acquisition as a
  feature to extension subclasses.  These mix-in classes use the
  context-wrapping feature of ExtensionClasses to implement
  acquisition. Consider the following example:</p>
<PRE>
    import ExtensionClass, Acquisition

    class C(ExtensionClass.Base):
      color='red'

    class A(Acquisition.Implicit):

      def report(self):
        print self.color

    a=A()
    c=C()
    c.a=A()

    c.a.report() # prints 'red'

    d=C()
    d.color='green'
    d.a=a

    d.a.report() # prints 'green'

    a.report() # raises an attribute error

</PRE>

<p>  The class <code>A</code> inherits acquisition behavior from
  <code>Acquisition.Implicit</code>.  The object, <code>a</code>, "has" the color of
  objects <code>c</code> and <code>d</code> when it is accessed through them, but it
  has no color by itself.  The object <code>a</code> obtains attributes
  from it's environment, where it's environment is defined by
  the access path used to reach <code>a</code>.</p>

<h2>Acquisition wrappers</h2>
<p>    When an object that supports acquisition is accessed through
    an extension class instance, a special object, called an
    acquisition wrapper, is returned.  In the example above, the
    expression <code>c.a</code> returns an acquisition wrapper that
    contains references to both <code>c</code> and <code>a</code>.  It is this wrapper
    that performs attribute lookup in <code>c</code> when an attribute
    cannot be found in <code>a</code>.</p>

<p>    Aquisition wrappers provide access to the wrapped objects
    through the attributes <code>aq_parent</code>, <code>aq_self</code>, <code>aq_base</code>.  
    In the example above, the expressions:</p>
<PRE>
       'c.a.aq_parent is c'

</PRE>

<p>    and:</p>
<PRE>
       'c.a.aq_self is a'

</PRE>

<p>    both evaluate to true, but the expression:</p>
<PRE>
       'c.a is a'

</PRE>

<p>    evaluates to false, because the expression <code>c.a</code> evaluates
    to an acquisition wrapper around <code>c</code> and <code>a</code>, not <code>a</code> itself.</p>

<p>    The attribute <code>aq_base</code> is similar to <code>aq_self</code>.  Wrappers may be
    nested and <code>aq_self</code> may be a wrapped object.  The <code>aq_base</code>
    attribute is the underlying object with all wrappers removed.</p>


<h2>Acquisition Control</h2>
<p>    Two styles of acquisition are supported in the current
    ExtensionClass release, implicit and explicit aquisition.</p>

<h3>Implicit acquisition</h3>
<p>      Implicit acquisition is so named because it searches for
      attributes from the environment automatically whenever an
      attribute cannot be obtained directly from an object or
      through inheritence.</p>

<p>      An attribute may be implicitly acquired if it's name does
      not begin with an underscore, <code>_</code>.</p>

<p>      To support implicit acquisition, an object should inherit
      from the mix-in class <code>Acquisition.Implicit</code>.</p>


<h3>Explicit Acquisition</h3>
<p>      When explicit acquisition is used, attributes are not
      automatically obtained from the environment.  Instead, the
      method <code>aq_aquire</code> must be used, as in:</p>
<PRE>
        print c.a.aq_acquire('color')

</PRE>

<p>      To support explicit acquisition, an object should inherit
      from the mix-in class <code>Acquisition.Explicit</code>.</p>


<h3>Controlled Acquisition</h3>
<p>      A class (or instance) can provide attribute by attribute control
      over acquisition.  This is done by:</p>

<ul><li><p>subclassing from <code>Acquisition.Explicit</code>, and</p>


<li><p>setting all attributes that should be acquired to the special
        value: <code>Acquisition.Acquired</code>.  Setting an attribute to this
        value also allows inherited attributes to be overridden with
        acquired ones.</p>
<p>        For example, in:</p>
<PRE>
          class C(Acquisition.Explicit):
             id=1
             secret=2
             color=Acquisition.Acquired
             __roles__=Acquisition.Acquired

</PRE>

<p>        The <em>only</em> attributes that are automatically acquired from
        containing objects are <code>color</code>, and <code>__roles__</code>.  Note also
        that the <code>__roles__</code> attribute is acquired even though it's
        name begins with an underscore.  In fact, the special
        <code>Acquisition.Acquired</code> value can be used in
        <code>Acquisition.Implicit</code> objects to implicitly acquire selected
        objects that smell like private objects.</p>


</ul>

<h3>Filtered Acquisition</h3>
<p>      The acquisition method, <code>aq_acquire</code>, accepts two optional
      arguments. The first of the additional arguments is a
      "filtering" function that is used when considering whether to
      acquire an object.  The second of the additional arguments is an
      object that is passed as extra data when calling the filtering
      function and which defaults to <code>None</code>.</p>

<p>      The filter function is called with five arguments:</p>

<ul><li><p>The object that the <code>aq_acquire</code> method was called on,</p>


<li><p>The object where an object was found,</p>


<li><p>The name of the object, as passed to <code>aq_acquire</code>,</p>


<li><p>The object found, and</p>


<li><p>The extra data passed to <code>aq_acquire</code>.</p>

</ul>
<p>      If the filter returns a true object that the object found is
      returned, otherwise, the acquisition search continues.</p>

<p>      For example, in:</p>
<PRE>
        from Acquisition import Explicit

        class HandyForTesting:
            def __init__(self, name): self.name=name
            def __str__(self):
                return &quot;%s(%s)&quot; % (self.name, self.__class__.__name__)
            __repr__=__str__

        class E(Explicit, HandyForTesting): pass

        class Nice(HandyForTesting):
            isNice=1
            def __str__(self):
                return HandyForTesting.__str__(self)+' and I am nice!'
            __repr__=__str__

        a=E('a')
        a.b=E('b')
        a.b.c=E('c')
        a.p=Nice('spam')
        a.b.p=E('p')

        def find_nice(self, ancestor, name, object, extra):
            return hasattr(object,'isNice') and object.isNice

        print a.b.c.aq_acquire('p', find_nice)

</PRE>

<p>      The filtered acquisition in the last line skips over the first
      attribute it finds with the name <code>p</code>, because the attribute
      doesn't satisfy the condition given in the filter. The output of
      the last line is:</p>
<PRE>
        spam(Nice) and I am nice!

</PRE>



<h2>Acquisition and methods</h2>
<p>    Python methods of objects that support acquisition can use
    acquired attributes as in the <code>report</code> method of the first example
    above.  When a Python method is called on an object that is
    wrapped by an acquisition wrapper, the wrapper is passed to the
    method as the first argument.  This rule also applies to
    user-defined method types and to C methods defined in pure mix-in
    classes.</p>

<p>    Unfortunately, C methods defined in extension base classes that
    define their own data structures, cannot use aquired attributes at
    this time.  This is because wrapper objects do not conform to the
    data structures expected by these methods.</p>


<h2>Acquiring Acquiring objects</h2>
<p>    Consider the following example:</p>
<PRE>
      from Acquisition import Implicit

      class C(Implicit):
          def __init__(self, name): self.name=name
          def __str__(self):
              return &quot;%s(%s)&quot; % (self.name, self.__class__.__name__)
          __repr__=__str__

      a=C(&quot;a&quot;)
      a.b=C(&quot;b&quot;)
      a.b.pref=&quot;spam&quot;
      a.b.c=C(&quot;c&quot;)
      a.b.c.color=&quot;red&quot;
      a.b.c.pref=&quot;eggs&quot;
      a.x=C(&quot;x&quot;)

      o=a.b.c.x

</PRE>

<p>    The expression <code>o.color</code> might be expected to return <code>"red"</code>. In
    earlier versions of ExtensionClass, however, this expression
    failed.  Acquired acquiring objects did not acquire from the
    environment they were accessed in, because objects were only
    wrapped when they were first found, and were not rewrapped as they
    were passed down the acquisition tree.</p>

<p>    In the current release of ExtensionClass, the expression "o.color"
    does indeed return <code>"red"</code>.</p>

<p>    When searching for an attribute in <code>o</code>, objects are searched in
    the order <code>x</code>, <code>a</code>, <code>b</code>, <code>c</code>. So, for example, the expression,
    <code>o.pref</code> returns <code>"spam"</code>, not <code>"eggs"</code>.  In earlier releases of
    ExtensionClass, the attempt to get the <code>pref</code> attribute from <code>o</code>
    would have failed.</p>

<p>    If desired, the current rules for looking up attributes in complex
    expressions can best be understood through repeated application of
    the <code>__of__</code> method:</p>

<dl><dt>    <code>a.x</code><dd><p><code>x.__of__(a)</code></p>


<dt>    <code>a.b</code><dd><p><code>b.__of__(a)</code></p>


<dt>    <code>a.b.x</code><dd><p><code>x.__of__(a).__of__(b.__of__(a))</code></p>


<dt>    <code>a.b.c</code><dd><p><code>c.__of__(b.__of__(a))</code></p>


<dt>    <code>a.b.c.x</code><dd><p><code>x.__of__(a).__of__(b.__of__(a)).__of__(c.__of__(b.__of__(a)))</code></p>

</dl>
<p>    and by keeping in mind that attribute lookup in a wrapper
    is done by trying to lookup the attribute in the wrapped object
    first and then in the parent object.  In the expressions above
    involving the <code>__of__</code> method, lookup proceeds from left to right.</p>

<p>    Note that heuristics are used to avoid most of the repeated
    lookups. For example, in the expression: <code>a.b.c.x.foo</code>, the object
    <code>a</code> is searched no more than once, even though it is wrapped three
    times.</p>


<p>  <a name="1">[1]</a> Gil, J., Lorenz, D., 
   <a href="http://www.bell-labs.com/people/cope/oopsla/Oopsla96TechnicalProgramAbstracts.html#GilLorenz">Environmental Acquisition--A New Inheritance-Like Abstraction Mechanism</a> 
   OOPSLA '96 Proceedings, ACM SIG-PLAN, October, 1996</p>

<p></p>



	    </body></html>