Version 4 (modified by 13 years ago) ( diff ) | ,
---|
Global State
This page serves as a collecting point for facts and consideration of global state in Django.
What is "global state"
This generally refers to variables in memory that are available to any code running within a given context
this is a manifestation of scoping
A global variable is one that is local in one context, and global for all contained contexts.
Generally globals are added during import time, and are defined as module level variables
so if we have a module foo, that assigns at the module level to a variable named x like:
x = 5
then foo.x is globally shared across any code that imports foo within that running process
There are several contexts in which a variable can be defined. This variable becomes available to this context and any containing context, but not in any parent contexts.
machine > process > thread > greenlet
Why remove global state:
First we could ask why is it there in the first place?
Global state allows coordination between many different areas of a framework without having to explicitly pass that information around.
There are several reasons to remove the use of global state in Django, and these can be grouped into areas that improve isolation, create a better runtime experience, and add more flexibility in the use of the framework.
Isolation:
- Multiple Django projects on single server (multitenancy)
- Make unit testing easier as configuration is self contained - easier to isolate tests, integration test vs unit test
Better runtime experience:
- Being more explicit about where global state is used, and when it is created, it provides a good place for a process initialization hook
- By having less configuration stored globally, it allows for more dynamic reconfiguration of framework behavior at runtime (including per-request changes), fewer required server restarts
More Flexible:
- More structured organization of non-global configuration would set the stage to allow more granular configuration on a per INSTALLED_APP basis.
- Make it easier to use Django components as just another python library, including outside the direct context of a web application
"Explicit is better than implicit." --zen of Python
if some function depends on a variable being "magically" defined, without it being clear where the variable was set - that code is less clear
Immutable is less evil than mutable - it can alleviate erratic and surprising behavior, but doesn't improve the situation with regards to isolation.
An well articulated litany of some of the issues related to global state in Django was put forth by Simon Willison. Specifically the idea of having a dynamic runtime configuration.(good comments too about chaining callables)
What areas of Django suffer from problems with global state
note each of these areas can be flushed out with specific subissues, solutions, and notes.
template system
https://code.djangoproject.com/ticket/17093
settings
signals
WSGI handler
urlconf/urlreverse
db
cache system
https://code.djangoproject.com/ticket/16006
translations
https://code.djangoproject.com/ticket/14894
management commands
testing
https://code.djangoproject.com/ticket/11593
What are some possible approaches to handling reasonable amounts of global state:
Flask (uses werkzeug) keeps a stack of threadlocal objects.
Pyramid contains a single list of "application registries" in a global_registry - this is the single bit of global state. A registry is bound with other configuration information into a Configurator object.
https://github.com/Pylons/pyramid/blob/master/pyramid/config/__init__.py
http://docs.pylonsproject.org/projects/pyramid/dev/api/registry.html
A common issue solved with a bit of global, sort out location in the filesystem:
The Pyramid configurator object accepts a 'package' argument which should be the python path location of a package - otherwise the current package/module, so the python file that defines the Configurator object becomes a positional anchor in the filesystem.
Flask does something very similar, using name to locate your Flask application.
People routinely do this using file in Django settings.py
Some related discussions:
A good discussion on what role the framework should play in owning the request and response: http://lucumr.pocoo.org/2009/8/5/pro-cons-about-werkzeug-webob-and-django/
an explanation of how process global data effects code running in mod_wsgi: http://code.google.com/p/modwsgi/wiki/ProcessesAndThreading#Sharing_Of_Global_Data
Armin why I can't stand thread.local (and others) July 10, 2006 main issues are that is magic and hard to understand why some globals should be mutable, and others not cached as pocoo version is 404 http://meineartikel.labs.nzz.ch/user/pneff/set/python/id/1Wg
http://justindriscoll.us/2008/02/objects-with-shared-state-in-python.html a way of using a class level attribute reflected into all instances
odds and ends, tangents
http://www.python.org/dev/peps/pep-3104/
Dynamic Scoping in python http://www.voidspace.org.uk/python/articles/code_blocks.shtml
http://stackoverflow.com/questions/1920053/what-is-so-bad-with-threadlocals
http://stackoverflow.com/questions/3227180/why-is-using-thread-locals-in-django-bad