[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
`------------------>