Subject: Re: Zope avoiding nested DTMLs? From: Luciano Ramalho <luciano@hiper.com.br> Date: Tue, 20 Mar 2001 04:07:29 -0300

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

  1. < dtml-var expr="_['x']?">

but is not the same as

  1. < 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:

  1. < dtml-var expr="_['x']?">
  1. < 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

  1. < dtml-var expr="_.getitem('x')">
  2. < dtml-var expr="_.getitem(x)">

The result of (5) is the same as

  1. < 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 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 _.