[Zope] avoiding nested DTMLs
Casey Duncan
cduncan@kaivo.com
Tue, 20 Mar 2001 08:27:26 -0700
Luciano Ramalho wrote:
>
> Timothy Wilson wrote:
> > Cool. That worked. I need to read up on that _[] stuff. Thanks.
>
> Knowing Python really helps in decrypting _['x'].
>
> First of all, _ is just a valid, albeit weird, variable name in Python.
> _ does not have any special powers in Python (as $_ has in Perl).
>
> The syntax y['x'] means: fetch item 'x' from dictionary y. y is not a
> real dictionary, but rather an object that behaves mostly like a
> dicionary. So _['x'] just means, fetch item 'x' from the namespace. In a
> dicionary, whatever goes inside the [] is called a "key". Now, what
> happens if I write y[x] and not y['x']? That is an indirection, is is
> discussed a few paragraphs below.
>
> Now, although _ would be just a regular variable name in Python, in DTML
> expressions it always refers to the namespace object which, like I said,
> is not really an object but just pretends to be one. The symbol for the
> namespace object could be 'namespace', 'super_dict', or '_ground'. But
> it was called '_'. Zopistas I've met pronounce _ as "under" or
> "namespace", depending on how formal they are.
>
> Like a dicionary, _ has a has_key method, which you call like this:
> "_.has_key('x')". Unlike a regular dictionary, it gives you access to
> dozens of Python functions such as int "_.int(x)", and whole modules
> such as string, DateTime and random: "_.random.randint(x,y)". On the
> other hand, _ does not have some usual dicionary methods, like keys() or
> items(), which are useful to retrieve the entire contents of a
> dictionary.
>
> WHAT _['x'] REALLY DOES
>
> The strangest thing about _ is that when you access something in it,
> like _['x'], it doesn't just fetch the x object for you. Whenever _
> retrives an object, it checks whether the object is callable (most
> things are callable objects in Zope). If the object is callable, _ calls
> or invokes it, which means the object is executed as code, and then what
> you get is not the object, but the result of executing it, whis is
> normally a string containing HTML. This is the same behaviour of the
> dtml-var "name" attribute. So:
>
> (1) <dtml-var name="x">
>
> gives the same result as
>
> (2) <dtml-var expr="_['x']">
>
> but is not the same as
>
> (3) <dtml-var expr="x">.
>
> For instance, if x is a DTML Method, (1) and (2) execute, or render it,
> replacing DTML tags within x by their results, and returning plain HTML.
> Then if you want to access some z attribute of x, you get the dreadful
> "String object has no attribute z", which tells you that x is no longer
> a rich object like a folder or a document, but is now a flat string
> containing the HTML resulting from rendering the x object.
>
> With syntax (3) you just fetch it, which depending on context would
> display the unrendered DTML code.
>
> If you need to indirectly fetch an object without executing it, you have
> to use another of _'s methods, getitem. The expression "_.getitem('x')"
> returns a reference to the object called x, without invoking it.
>
> INDIRECTION
>
> Notice difference between:
>
> (2) <dtml-var expr="_['x']">
>
> (4) <dtml-var expr="_[x]">
>
> These mean COMPLETELY DIFFERENT things. In (2) you want to get the
> object called 'x' from the namespace dictionary. The key you are using
> is the string 'x'.
>
> In (4), you are getting the object whose name is stored in variable x.
> The key, in this case, is whatever is referred by the variable x. If x
> refers to the string 'ni', then _[x] means _['ni'], that is, fetch the
> object called 'ni'.
>
> That is why _[x] is called an indirection: in our example you are not
> fetching 'ni' directly, but indirectly through the x variable. The next
> time _[x] is evaluated, x may refer to 'sikander', and then _[x] may
> yield a totally different result.
>
> The same rationale goes for
>
> (5) <dtml-var expr="_.getitem('x')">
>
> (6) <dtml-var expr="_.getitem(x)">
>
> The result of (5) is the same as
>
> (3) <dtml-var expr="x">
>
> so you would never use (5) in real code.
>
> But (6) is useful to fetch an object indirectly without executing it.
>
> AN INTERESTING EXPERIMENT
>
> Try this: within a folder, create two methods with ids 'method1' and
> 'method2'. Leave 'method2' with its default content, but replace the
> content of 'method1' with this, then View it.
>
> <dtml-var standard_html_header>
>
> <dtml-var name="method2">
> <hr>
> <dtml-var expr="method2">
> <hr>
> <dtml-var expr="_['method2']">
> <hr>
> <dtml-var expr="_.getitem('method2')">
>
> <dtml-var standard_html_footer>
>
> If my explanations were any good, you should understand what is going on
> now.
>
> The whole _ issue is why, whenever I teach Zope, I include at least one
> hour of "instrumental Python".
> And while playing with the Python interpreter, I always make the
> students create and do lots of operations with a dictionary called _.
>
> --
> Best regards,
>
> Luciano
>
You should put all of that into a howto! Very well said.
--
| Casey Duncan
| Kaivo, Inc.
| cduncan@kaivo.com
`------------------>