Ian Bicking: the old part of his blog


Ian, you are right on target with your observations.

First, interfaces were chosen instead of strings (for example, implementing __getattr__ on Context) because they are namespaced.

Second, ISession(ctx) should absolutely be used instead of ctx.locate(ISession), and I plan on implementing that soon in my copious spare time.

Finally, context objects in nevow are chained in order to keep track of state across asynchronous callbacks. context.remember remembers an object for an interface at that particular context, and context.locate (or eventually IFoo(ctx)) searches through this parent chain if that particular interface isn't immediately available. This allows me to do things like:

- reuse context objects across multiple page renders (in the case where a template is precompiled and certain things happen once but other things happen every page render)

- implement locate() in different ways in different places; the normal Context objects used to represent a DOM node implement locate as described above, but other IContext implementors implement it by directly returning some object or by being a factory for interface implementors

- implement very explicit acquisition, should anyone choose to use it. Before writing Woven and Nevow I wrote a few very large applications in Zope and was struck by the power and simplicity of in-a inheritance, but burned a few times by it's implicitness. Thus, I wanted to build in a way to pass information from parent to children pages into nevow. The context chain is used to accomplish this.

Also, twisted.python.context is relevant to this discussion. It is used to implicitly pass state during the execution of a function, and it uses some form of thread identity checking to provide a unique context to each thread. (Read the implementation, it is short.) It is used like this:

from twisted.python import context

context.call({'any keys': 'any values'}, someFunction, someArgument, someKeyword='argument')

Then later, during the execution of someFunction or any function called by someFunction:

from twisted.python import context

context.get('any keys')

Thanks for the interesting blog posts as always!

Comment on Dealing with Context
by Donovan Preston