Tail recursion in Python

There’s an interesting post on tail recursion in Python from Chris Penner (actually an old post, but I’ve only just seen it).

Chris comes up with a way of allowing functions in Python to be tail-recursive, that is to be able to call themselves without exhausting the limited stack space in Python.

In other languages tail-recursion is used as a substitute for iteration, in order to express iterative algorithms without having to have mutable local state. That’s not really a good idea in Python. But there may be a role for tail recursion in expressing fundamentally recursive algorithms which would otherwise get limited by lack of stack space.

Why do Django views need an as_view() method?

One thing I’ve sometimes wondered about when using Django: Why do view objects need to be constructed in a special way?

For those of you who haven’t used Django, a typical URL mapping scheme looks like this:

urlpatterns = [
    url(r'^login/

This maps URLs to view classes in a fairly obvious way. A view object is just an instance that handles an HTTP request and returns an appropriate response (actually combining both Model and View, for those of you used to thinking in a more orthodox MVC structure).

The LoginView.as_view() call is actually calling a static method on the LoginView class, which constructs and returns an instance of LoginView. This is basically the Factory Method pattern.

But why can’t this just be:

url(r'^login/

This isn’t just a cosmetic detail either. Sometimes you want to pass arguments in to customise the view instance, and if you want to do this you have to pass keyword arguments to as_view(). These aren’t actually passed as arguments to __init__() either; keyword arguments to as_view() can only assign to attribues already declared on the class.

So if we want to customise our LoginView, we have to do something like:

class LoginView(View):
    require_staff = False
 
    # ...
 
# later...
 
urlpatterns = [
    url(r'^login/

First, let’s look at what Django is actually doing, then ask why. Here’s the as_view() method in the base class (minus a little bit of parameter checking code):

def as_view(cls, **initkwargs):
    """
    Main entry point for a request-response process.
    """
    for key in initkwargs:
        # ... some checking on args
 
    def view(request, *args, **kwargs):
        self = cls(**initkwargs)
        if hasattr(self, 'get') and not hasattr(self, 'head'):
            self.head = self.get
        self.request = request
        self.args = args
        self.kwargs = kwargs
        return self.dispatch(request, *args, **kwargs)
    view.view_class = cls
    view.view_initkwargs = initkwargs
 
    # take name and docstring from class
    update_wrapper(view, cls, updated=())
 
    # and possible attributes set by decorators
    # like csrf_exempt from dispatch
    update_wrapper(view, cls.dispatch, assigned=())
    return view

This constructs a local function, sets some properties on it and returns the function to the caller. The function will be called later, when the HTTP request is received. When this function is called, the LoginView is finally constructed and the dispatch() method is called (which is what deals with the HTTP request and returns a response).

So the short answer is that as_view() is needed because the Django code is expecting a function, not an object. This is partly for historical reasons: Django used to exclusively use functions as views, and introduced objects more recently. Now it’s possible to use either objects or functions as views.

The obvious response is to ask why the Django dispatch code cares whether it has a function or an object (or, equivalently, to claim that a function is an object). Python is supposed to use duck typing, so code shouldn’t care what sort of object it has provided it behaves correctly. In this context, “behaves correctly” means that the object is callable. And we’re perfectly capable of creating our own objects that are callable in just the same way functions are:

class LoginView(object):
    def __call__(self, request, *args, **kwargs):
        return self.dispatch(request, args, **kwargs)

If we construct one of these and give it to Django, it should be completely unaware that this is not a normal Python function. In fact, this is true. The Django code that executes the view function looks like this:

resolver_match = resolver.resolve(request.path_info)
callback, callback_args, callback_kwargs = resolver_match
request.resolver_match = resolver_match
 
# Apply view middleware
# ...
 
if response is None:
    wrapped_callback = self.make_view_atomic(callback)
    try:
        response = wrapped_callback(request, *callback_args, **callback_kwargs)
    except Exception as e:
        response = self.process_exception_by_middleware(e, request)

Here callback is just the view function (either a function or the result of calling .as_view() on a view class) that we assigned in the URL pattern. We can ignore what wrapped_callback does for our current purposes, and just assume that it’s some kind of wrapper function around the original callback. So we are indeed just calling the function, and it won’t detect the difference between a real function and a class with a __call__ method.

You can prove this yourself by creating a custom view class that has a __call__ method:

class SpecialView:
    def __call__(self, request, *args, **kwargs):
        return HttpResponse()
 
urlpatterns = [
    url(r'^foo/', SpecialView())
]

Django will happily call your SpecialView instance as if it were a real function.

But notice a key difference between this and the wrapper function generated by Django: If you use SpecialView you have a single object instance for as long as the Django service is running. The Django wrapper function constructs a new instance for every request.

So this is the real reason why .as_view() is desirable: it means that no state is held by the View class between one request and the next. If Django didn’t do this, you’d need to be excessively careful that you didn’t assign to some member of the view that would lead to different behaviour next time the view was run, and you’d end up with a nightmare to debug.

, views.LoginView.as_view(), name='login'), url(r'^logout/

This maps URLs to view classes in a fairly obvious way. A view object is just an instance that handles an HTTP request and returns an appropriate response (actually combining both Model and View, for those of you used to thinking in a more orthodox MVC structure).

The LoginView.as_view() call is actually calling a static method on the LoginView class, which constructs and returns an instance of LoginView. This is basically the Factory Method pattern.

But why can’t this just be:


This isn’t just a cosmetic detail either. Sometimes you want to pass arguments in to customise the view instance, and if you want to do this you have to pass keyword arguments to as_view(). These aren’t actually passed as arguments to __init__() either; keyword arguments to as_view() can only assign to attribues already declared on the class.

So if we want to customise our LoginView, we have to do something like:


First, let’s look at what Django is actually doing, then ask why. Here’s the as_view() method in the base class (minus a little bit of parameter checking code):


This constructs a local function, sets some properties on it and returns the function to the caller. The function will be called later, when the HTTP request is received. When this function is called, the LoginView is finally constructed and the dispatch() method is called (which is what deals with the HTTP request and returns a response).

So the short answer is that as_view() is needed because the Django code is expecting a function, not an object. This is partly for historical reasons: Django used to exclusively use functions as views, and introduced objects more recently. Now it’s possible to use either objects or functions as views.

The obvious response is to ask why the Django dispatch code cares whether it has a function or an object (or, equivalently, to claim that a function is an object). Python is supposed to use duck typing, so code shouldn’t care what sort of object it has provided it behaves correctly. In this context, “behaves correctly” means that the object is callable. And we’re perfectly capable of creating our own objects that are callable in just the same way functions are:


If we construct one of these and give it to Django, it should be completely unaware that this is not a normal Python function. In fact, this is true. The Django code that executes the view function looks like this:


Here callback is just the view function (either a function or the result of calling .as_view() on a view class) that we assigned in the URL pattern. We can ignore what wrapped_callback does for our current purposes, and just assume that it’s some kind of wrapper function around the original callback. So we are indeed just calling the function, and it won’t detect the difference between a real function and a class with a __call__ method.

You can prove this yourself by creating a custom view class that has a __call__ method:


Django will happily call your SpecialView instance as if it were a real function.

But notice a key difference between this and the wrapper function generated by Django: If you use SpecialView you have a single object instance for as long as the Django service is running. The Django wrapper function constructs a new instance for every request.

So this is the real reason why .as_view() is desirable: it means that no state is held by the View class between one request and the next. If Django didn’t do this, you’d need to be excessively careful that you didn’t assign to some member of the view that would lead to different behaviour next time the view was run, and you’d end up with a nightmare to debug.

, views.LogoutView.as_view(), name='logout'), # ... ]

This maps URLs to view classes in a fairly obvious way. A view object is just an instance that handles an HTTP request and returns an appropriate response (actually combining both Model and View, for those of you used to thinking in a more orthodox MVC structure).

The LoginView.as_view() call is actually calling a static method on the LoginView class, which constructs and returns an instance of LoginView. This is basically the Factory Method pattern.

But why can’t this just be:


This isn’t just a cosmetic detail either. Sometimes you want to pass arguments in to customise the view instance, and if you want to do this you have to pass keyword arguments to as_view(). These aren’t actually passed as arguments to __init__() either; keyword arguments to as_view() can only assign to attribues already declared on the class.

So if we want to customise our LoginView, we have to do something like:


First, let’s look at what Django is actually doing, then ask why. Here’s the as_view() method in the base class (minus a little bit of parameter checking code):


This constructs a local function, sets some properties on it and returns the function to the caller. The function will be called later, when the HTTP request is received. When this function is called, the LoginView is finally constructed and the dispatch() method is called (which is what deals with the HTTP request and returns a response).

So the short answer is that as_view() is needed because the Django code is expecting a function, not an object. This is partly for historical reasons: Django used to exclusively use functions as views, and introduced objects more recently. Now it’s possible to use either objects or functions as views.

The obvious response is to ask why the Django dispatch code cares whether it has a function or an object (or, equivalently, to claim that a function is an object). Python is supposed to use duck typing, so code shouldn’t care what sort of object it has provided it behaves correctly. In this context, “behaves correctly” means that the object is callable. And we’re perfectly capable of creating our own objects that are callable in just the same way functions are:


If we construct one of these and give it to Django, it should be completely unaware that this is not a normal Python function. In fact, this is true. The Django code that executes the view function looks like this:


Here callback is just the view function (either a function or the result of calling .as_view() on a view class) that we assigned in the URL pattern. We can ignore what wrapped_callback does for our current purposes, and just assume that it’s some kind of wrapper function around the original callback. So we are indeed just calling the function, and it won’t detect the difference between a real function and a class with a __call__ method.

You can prove this yourself by creating a custom view class that has a __call__ method:


Django will happily call your SpecialView instance as if it were a real function.

But notice a key difference between this and the wrapper function generated by Django: If you use SpecialView you have a single object instance for as long as the Django service is running. The Django wrapper function constructs a new instance for every request.

So this is the real reason why .as_view() is desirable: it means that no state is held by the View class between one request and the next. If Django didn’t do this, you’d need to be excessively careful that you didn’t assign to some member of the view that would lead to different behaviour next time the view was run, and you’d end up with a nightmare to debug.

, views.LoginView(), name='login')

This isn’t just a cosmetic detail either. Sometimes you want to pass arguments in to customise the view instance, and if you want to do this you have to pass keyword arguments to as_view(). These aren’t actually passed as arguments to __init__() either; keyword arguments to as_view() can only assign to attribues already declared on the class.

So if we want to customise our LoginView, we have to do something like:


First, let’s look at what Django is actually doing, then ask why. Here’s the as_view() method in the base class (minus a little bit of parameter checking code):


This constructs a local function, sets some properties on it and returns the function to the caller. The function will be called later, when the HTTP request is received. When this function is called, the LoginView is finally constructed and the dispatch() method is called (which is what deals with the HTTP request and returns a response).

So the short answer is that as_view() is needed because the Django code is expecting a function, not an object. This is partly for historical reasons: Django used to exclusively use functions as views, and introduced objects more recently. Now it’s possible to use either objects or functions as views.

The obvious response is to ask why the Django dispatch code cares whether it has a function or an object (or, equivalently, to claim that a function is an object). Python is supposed to use duck typing, so code shouldn’t care what sort of object it has provided it behaves correctly. In this context, “behaves correctly” means that the object is callable. And we’re perfectly capable of creating our own objects that are callable in just the same way functions are:


If we construct one of these and give it to Django, it should be completely unaware that this is not a normal Python function. In fact, this is true. The Django code that executes the view function looks like this:


Here callback is just the view function (either a function or the result of calling .as_view() on a view class) that we assigned in the URL pattern. We can ignore what wrapped_callback does for our current purposes, and just assume that it’s some kind of wrapper function around the original callback. So we are indeed just calling the function, and it won’t detect the difference between a real function and a class with a __call__ method.

You can prove this yourself by creating a custom view class that has a __call__ method:


Django will happily call your SpecialView instance as if it were a real function.

But notice a key difference between this and the wrapper function generated by Django: If you use SpecialView you have a single object instance for as long as the Django service is running. The Django wrapper function constructs a new instance for every request.

So this is the real reason why .as_view() is desirable: it means that no state is held by the View class between one request and the next. If Django didn’t do this, you’d need to be excessively careful that you didn’t assign to some member of the view that would lead to different behaviour next time the view was run, and you’d end up with a nightmare to debug.

, views.LoginView.as_view(), name='login'), url(r'^logout/

This maps URLs to view classes in a fairly obvious way. A view object is just an instance that handles an HTTP request and returns an appropriate response (actually combining both Model and View, for those of you used to thinking in a more orthodox MVC structure).

The LoginView.as_view() call is actually calling a static method on the LoginView class, which constructs and returns an instance of LoginView. This is basically the Factory Method pattern.

But why can’t this just be:


This isn’t just a cosmetic detail either. Sometimes you want to pass arguments in to customise the view instance, and if you want to do this you have to pass keyword arguments to as_view(). These aren’t actually passed as arguments to __init__() either; keyword arguments to as_view() can only assign to attribues already declared on the class.

So if we want to customise our LoginView, we have to do something like:


First, let’s look at what Django is actually doing, then ask why. Here’s the as_view() method in the base class (minus a little bit of parameter checking code):


This constructs a local function, sets some properties on it and returns the function to the caller. The function will be called later, when the HTTP request is received. When this function is called, the LoginView is finally constructed and the dispatch() method is called (which is what deals with the HTTP request and returns a response).

So the short answer is that as_view() is needed because the Django code is expecting a function, not an object. This is partly for historical reasons: Django used to exclusively use functions as views, and introduced objects more recently. Now it’s possible to use either objects or functions as views.

The obvious response is to ask why the Django dispatch code cares whether it has a function or an object (or, equivalently, to claim that a function is an object). Python is supposed to use duck typing, so code shouldn’t care what sort of object it has provided it behaves correctly. In this context, “behaves correctly” means that the object is callable. And we’re perfectly capable of creating our own objects that are callable in just the same way functions are:


If we construct one of these and give it to Django, it should be completely unaware that this is not a normal Python function. In fact, this is true. The Django code that executes the view function looks like this:


Here callback is just the view function (either a function or the result of calling .as_view() on a view class) that we assigned in the URL pattern. We can ignore what wrapped_callback does for our current purposes, and just assume that it’s some kind of wrapper function around the original callback. So we are indeed just calling the function, and it won’t detect the difference between a real function and a class with a __call__ method.

You can prove this yourself by creating a custom view class that has a __call__ method:


Django will happily call your SpecialView instance as if it were a real function.

But notice a key difference between this and the wrapper function generated by Django: If you use SpecialView you have a single object instance for as long as the Django service is running. The Django wrapper function constructs a new instance for every request.

So this is the real reason why .as_view() is desirable: it means that no state is held by the View class between one request and the next. If Django didn’t do this, you’d need to be excessively careful that you didn’t assign to some member of the view that would lead to different behaviour next time the view was run, and you’d end up with a nightmare to debug.

, views.LogoutView.as_view(), name='logout'), # ... ]

This maps URLs to view classes in a fairly obvious way. A view object is just an instance that handles an HTTP request and returns an appropriate response (actually combining both Model and View, for those of you used to thinking in a more orthodox MVC structure).

The LoginView.as_view() call is actually calling a static method on the LoginView class, which constructs and returns an instance of LoginView. This is basically the Factory Method pattern.

But why can’t this just be:


This isn’t just a cosmetic detail either. Sometimes you want to pass arguments in to customise the view instance, and if you want to do this you have to pass keyword arguments to as_view(). These aren’t actually passed as arguments to __init__() either; keyword arguments to as_view() can only assign to attribues already declared on the class.

So if we want to customise our LoginView, we have to do something like:


First, let’s look at what Django is actually doing, then ask why. Here’s the as_view() method in the base class (minus a little bit of parameter checking code):


This constructs a local function, sets some properties on it and returns the function to the caller. The function will be called later, when the HTTP request is received. When this function is called, the LoginView is finally constructed and the dispatch() method is called (which is what deals with the HTTP request and returns a response).

So the short answer is that as_view() is needed because the Django code is expecting a function, not an object. This is partly for historical reasons: Django used to exclusively use functions as views, and introduced objects more recently. Now it’s possible to use either objects or functions as views.

The obvious response is to ask why the Django dispatch code cares whether it has a function or an object (or, equivalently, to claim that a function is an object). Python is supposed to use duck typing, so code shouldn’t care what sort of object it has provided it behaves correctly. In this context, “behaves correctly” means that the object is callable. And we’re perfectly capable of creating our own objects that are callable in just the same way functions are:


If we construct one of these and give it to Django, it should be completely unaware that this is not a normal Python function. In fact, this is true. The Django code that executes the view function looks like this:


Here callback is just the view function (either a function or the result of calling .as_view() on a view class) that we assigned in the URL pattern. We can ignore what wrapped_callback does for our current purposes, and just assume that it’s some kind of wrapper function around the original callback. So we are indeed just calling the function, and it won’t detect the difference between a real function and a class with a __call__ method.

You can prove this yourself by creating a custom view class that has a __call__ method:


Django will happily call your SpecialView instance as if it were a real function.

But notice a key difference between this and the wrapper function generated by Django: If you use SpecialView you have a single object instance for as long as the Django service is running. The Django wrapper function constructs a new instance for every request.

So this is the real reason why .as_view() is desirable: it means that no state is held by the View class between one request and the next. If Django didn’t do this, you’d need to be excessively careful that you didn’t assign to some member of the view that would lead to different behaviour next time the view was run, and you’d end up with a nightmare to debug.

, views.LoginView(require_staff=True), name=’login’), # … ]

First, let’s look at what Django is actually doing, then ask why. Here’s the as_view() method in the base class (minus a little bit of parameter checking code):


This constructs a local function, sets some properties on it and returns the function to the caller. The function will be called later, when the HTTP request is received. When this function is called, the LoginView is finally constructed and the dispatch() method is called (which is what deals with the HTTP request and returns a response).

So the short answer is that as_view() is needed because the Django code is expecting a function, not an object. This is partly for historical reasons: Django used to exclusively use functions as views, and introduced objects more recently. Now it’s possible to use either objects or functions as views.

The obvious response is to ask why the Django dispatch code cares whether it has a function or an object (or, equivalently, to claim that a function is an object). Python is supposed to use duck typing, so code shouldn’t care what sort of object it has provided it behaves correctly. In this context, “behaves correctly” means that the object is callable. And we’re perfectly capable of creating our own objects that are callable in just the same way functions are:


If we construct one of these and give it to Django, it should be completely unaware that this is not a normal Python function. In fact, this is true. The Django code that executes the view function looks like this:


Here callback is just the view function (either a function or the result of calling .as_view() on a view class) that we assigned in the URL pattern. We can ignore what wrapped_callback does for our current purposes, and just assume that it’s some kind of wrapper function around the original callback. So we are indeed just calling the function, and it won’t detect the difference between a real function and a class with a __call__ method.

You can prove this yourself by creating a custom view class that has a __call__ method:


Django will happily call your SpecialView instance as if it were a real function.

But notice a key difference between this and the wrapper function generated by Django: If you use SpecialView you have a single object instance for as long as the Django service is running. The Django wrapper function constructs a new instance for every request.

So this is the real reason why .as_view() is desirable: it means that no state is held by the View class between one request and the next. If Django didn’t do this, you’d need to be excessively careful that you didn’t assign to some member of the view that would lead to different behaviour next time the view was run, and you’d end up with a nightmare to debug.

, views.LoginView.as_view(), name=’login’), url(r’^logout/

This maps URLs to view classes in a fairly obvious way. A view object is just an instance that handles an HTTP request and returns an appropriate response (actually combining both Model and View, for those of you used to thinking in a more orthodox MVC structure).

The LoginView.as_view() call is actually calling a static method on the LoginView class, which constructs and returns an instance of LoginView. This is basically the Factory Method pattern.

But why can’t this just be:


This isn’t just a cosmetic detail either. Sometimes you want to pass arguments in to customise the view instance, and if you want to do this you have to pass keyword arguments to as_view(). These aren’t actually passed as arguments to __init__() either; keyword arguments to as_view() can only assign to attribues already declared on the class.

So if we want to customise our LoginView, we have to do something like:


First, let’s look at what Django is actually doing, then ask why. Here’s the as_view() method in the base class (minus a little bit of parameter checking code):


This constructs a local function, sets some properties on it and returns the function to the caller. The function will be called later, when the HTTP request is received. When this function is called, the LoginView is finally constructed and the dispatch() method is called (which is what deals with the HTTP request and returns a response).

So the short answer is that as_view() is needed because the Django code is expecting a function, not an object. This is partly for historical reasons: Django used to exclusively use functions as views, and introduced objects more recently. Now it’s possible to use either objects or functions as views.

The obvious response is to ask why the Django dispatch code cares whether it has a function or an object (or, equivalently, to claim that a function is an object). Python is supposed to use duck typing, so code shouldn’t care what sort of object it has provided it behaves correctly. In this context, “behaves correctly” means that the object is callable. And we’re perfectly capable of creating our own objects that are callable in just the same way functions are:


If we construct one of these and give it to Django, it should be completely unaware that this is not a normal Python function. In fact, this is true. The Django code that executes the view function looks like this:


Here callback is just the view function (either a function or the result of calling .as_view() on a view class) that we assigned in the URL pattern. We can ignore what wrapped_callback does for our current purposes, and just assume that it’s some kind of wrapper function around the original callback. So we are indeed just calling the function, and it won’t detect the difference between a real function and a class with a __call__ method.

You can prove this yourself by creating a custom view class that has a __call__ method:


Django will happily call your SpecialView instance as if it were a real function.

But notice a key difference between this and the wrapper function generated by Django: If you use SpecialView you have a single object instance for as long as the Django service is running. The Django wrapper function constructs a new instance for every request.

So this is the real reason why .as_view() is desirable: it means that no state is held by the View class between one request and the next. If Django didn’t do this, you’d need to be excessively careful that you didn’t assign to some member of the view that would lead to different behaviour next time the view was run, and you’d end up with a nightmare to debug.

, views.LogoutView.as_view(), name=’logout’), # … ]

This maps URLs to view classes in a fairly obvious way. A view object is just an instance that handles an HTTP request and returns an appropriate response (actually combining both Model and View, for those of you used to thinking in a more orthodox MVC structure).

The LoginView.as_view() call is actually calling a static method on the LoginView class, which constructs and returns an instance of LoginView. This is basically the Factory Method pattern.

But why can’t this just be:


This isn’t just a cosmetic detail either. Sometimes you want to pass arguments in to customise the view instance, and if you want to do this you have to pass keyword arguments to as_view(). These aren’t actually passed as arguments to __init__() either; keyword arguments to as_view() can only assign to attribues already declared on the class.

So if we want to customise our LoginView, we have to do something like:


First, let’s look at what Django is actually doing, then ask why. Here’s the as_view() method in the base class (minus a little bit of parameter checking code):


This constructs a local function, sets some properties on it and returns the function to the caller. The function will be called later, when the HTTP request is received. When this function is called, the LoginView is finally constructed and the dispatch() method is called (which is what deals with the HTTP request and returns a response).

So the short answer is that as_view() is needed because the Django code is expecting a function, not an object. This is partly for historical reasons: Django used to exclusively use functions as views, and introduced objects more recently. Now it’s possible to use either objects or functions as views.

The obvious response is to ask why the Django dispatch code cares whether it has a function or an object (or, equivalently, to claim that a function is an object). Python is supposed to use duck typing, so code shouldn’t care what sort of object it has provided it behaves correctly. In this context, “behaves correctly” means that the object is callable. And we’re perfectly capable of creating our own objects that are callable in just the same way functions are:


If we construct one of these and give it to Django, it should be completely unaware that this is not a normal Python function. In fact, this is true. The Django code that executes the view function looks like this:


Here callback is just the view function (either a function or the result of calling .as_view() on a view class) that we assigned in the URL pattern. We can ignore what wrapped_callback does for our current purposes, and just assume that it’s some kind of wrapper function around the original callback. So we are indeed just calling the function, and it won’t detect the difference between a real function and a class with a __call__ method.

You can prove this yourself by creating a custom view class that has a __call__ method:


Django will happily call your SpecialView instance as if it were a real function.

But notice a key difference between this and the wrapper function generated by Django: If you use SpecialView you have a single object instance for as long as the Django service is running. The Django wrapper function constructs a new instance for every request.

So this is the real reason why .as_view() is desirable: it means that no state is held by the View class between one request and the next. If Django didn’t do this, you’d need to be excessively careful that you didn’t assign to some member of the view that would lead to different behaviour next time the view was run, and you’d end up with a nightmare to debug.

, views.LoginView(), name=’login’)

This isn’t just a cosmetic detail either. Sometimes you want to pass arguments in to customise the view instance, and if you want to do this you have to pass keyword arguments to as_view(). These aren’t actually passed as arguments to __init__() either; keyword arguments to as_view() can only assign to attribues already declared on the class.

So if we want to customise our LoginView, we have to do something like:


First, let’s look at what Django is actually doing, then ask why. Here’s the as_view() method in the base class (minus a little bit of parameter checking code):


This constructs a local function, sets some properties on it and returns the function to the caller. The function will be called later, when the HTTP request is received. When this function is called, the LoginView is finally constructed and the dispatch() method is called (which is what deals with the HTTP request and returns a response).

So the short answer is that as_view() is needed because the Django code is expecting a function, not an object. This is partly for historical reasons: Django used to exclusively use functions as views, and introduced objects more recently. Now it’s possible to use either objects or functions as views.

The obvious response is to ask why the Django dispatch code cares whether it has a function or an object (or, equivalently, to claim that a function is an object). Python is supposed to use duck typing, so code shouldn’t care what sort of object it has provided it behaves correctly. In this context, “behaves correctly” means that the object is callable. And we’re perfectly capable of creating our own objects that are callable in just the same way functions are:


If we construct one of these and give it to Django, it should be completely unaware that this is not a normal Python function. In fact, this is true. The Django code that executes the view function looks like this:


Here callback is just the view function (either a function or the result of calling .as_view() on a view class) that we assigned in the URL pattern. We can ignore what wrapped_callback does for our current purposes, and just assume that it’s some kind of wrapper function around the original callback. So we are indeed just calling the function, and it won’t detect the difference between a real function and a class with a __call__ method.

You can prove this yourself by creating a custom view class that has a __call__ method:


Django will happily call your SpecialView instance as if it were a real function.

But notice a key difference between this and the wrapper function generated by Django: If you use SpecialView you have a single object instance for as long as the Django service is running. The Django wrapper function constructs a new instance for every request.

So this is the real reason why .as_view() is desirable: it means that no state is held by the View class between one request and the next. If Django didn’t do this, you’d need to be excessively careful that you didn’t assign to some member of the view that would lead to different behaviour next time the view was run, and you’d end up with a nightmare to debug.

, views.LoginView.as_view(), name=’login’), url(r’^logout/

This maps URLs to view classes in a fairly obvious way. A view object is just an instance that handles an HTTP request and returns an appropriate response (actually combining both Model and View, for those of you used to thinking in a more orthodox MVC structure).

The LoginView.as_view() call is actually calling a static method on the LoginView class, which constructs and returns an instance of LoginView. This is basically the Factory Method pattern.

But why can’t this just be:


This isn’t just a cosmetic detail either. Sometimes you want to pass arguments in to customise the view instance, and if you want to do this you have to pass keyword arguments to as_view(). These aren’t actually passed as arguments to __init__() either; keyword arguments to as_view() can only assign to attribues already declared on the class.

So if we want to customise our LoginView, we have to do something like:


First, let’s look at what Django is actually doing, then ask why. Here’s the as_view() method in the base class (minus a little bit of parameter checking code):


This constructs a local function, sets some properties on it and returns the function to the caller. The function will be called later, when the HTTP request is received. When this function is called, the LoginView is finally constructed and the dispatch() method is called (which is what deals with the HTTP request and returns a response).

So the short answer is that as_view() is needed because the Django code is expecting a function, not an object. This is partly for historical reasons: Django used to exclusively use functions as views, and introduced objects more recently. Now it’s possible to use either objects or functions as views.

The obvious response is to ask why the Django dispatch code cares whether it has a function or an object (or, equivalently, to claim that a function is an object). Python is supposed to use duck typing, so code shouldn’t care what sort of object it has provided it behaves correctly. In this context, “behaves correctly” means that the object is callable. And we’re perfectly capable of creating our own objects that are callable in just the same way functions are:


If we construct one of these and give it to Django, it should be completely unaware that this is not a normal Python function. In fact, this is true. The Django code that executes the view function looks like this:


Here callback is just the view function (either a function or the result of calling .as_view() on a view class) that we assigned in the URL pattern. We can ignore what wrapped_callback does for our current purposes, and just assume that it’s some kind of wrapper function around the original callback. So we are indeed just calling the function, and it won’t detect the difference between a real function and a class with a __call__ method.

You can prove this yourself by creating a custom view class that has a __call__ method:


Django will happily call your SpecialView instance as if it were a real function.

But notice a key difference between this and the wrapper function generated by Django: If you use SpecialView you have a single object instance for as long as the Django service is running. The Django wrapper function constructs a new instance for every request.

So this is the real reason why .as_view() is desirable: it means that no state is held by the View class between one request and the next. If Django didn’t do this, you’d need to be excessively careful that you didn’t assign to some member of the view that would lead to different behaviour next time the view was run, and you’d end up with a nightmare to debug.

, views.LogoutView.as_view(), name=’logout’), # … ]

This maps URLs to view classes in a fairly obvious way. A view object is just an instance that handles an HTTP request and returns an appropriate response (actually combining both Model and View, for those of you used to thinking in a more orthodox MVC structure).

The LoginView.as_view() call is actually calling a static class method on the LoginView class, which constructs and returns an instance of LoginView. This is basically the Factory Method pattern.

But why can’t this just be:


This isn’t just a cosmetic detail either. Sometimes you want to pass arguments in to customise the view instance, and if you want to do this you have to pass keyword arguments to as_view(). These aren’t actually passed as arguments to __init__() either; keyword arguments to as_view() can only assign to attribues already declared on the class.

So if we want to customise our LoginView, we have to do something like:


First, let’s look at what Django is actually doing, then ask why. Here’s the as_view() method in the base class (minus a little bit of parameter checking code):


This constructs a local function, sets some properties on it and returns the function to the caller. The function will be called later, when the HTTP request is received. When this function is called, the LoginView is finally constructed and the dispatch() method is called (which is what deals with the HTTP request and returns a response).

So the short answer is that as_view() is needed because the Django code is expecting a function, not an object. This is partly for historical reasons: Django used to exclusively use functions as views, and introduced objects more recently. Now it’s possible to use either objects or functions as views.

The obvious response is to ask why the Django dispatch code cares whether it has a function or an object (or, equivalently, to claim that a function is an object). Python is supposed to use duck typing, so code shouldn’t care what sort of object it has provided it behaves correctly. In this context, “behaves correctly” means that the object is callable. And we’re perfectly capable of creating our own objects that are callable in just the same way functions are:


If we construct one of these and give it to Django, it should be completely unaware that this is not a normal Python function. In fact, this is true. The Django code that executes the view function looks like this:


Here callback is just the view function (either a function or the result of calling .as_view() on a view class) that we assigned in the URL pattern. We can ignore what wrapped_callback does for our current purposes, and just assume that it’s some kind of wrapper function around the original callback. So we are indeed just calling the function, and it won’t detect the difference between a real function and a class with a __call__ method.

You can prove this yourself by creating a custom view class that has a __call__ method:


Django will happily call your SpecialView instance as if it were a real function.

But notice a key difference between this and the wrapper function generated by Django: If you use SpecialView you have a single object instance for as long as the Django service is running. The Django wrapper function constructs a new instance for every request.

So this is the real reason why .as_view() is desirable: it means that no state is held by the View class between one request and the next. If Django didn’t do this, you’d need to be excessively careful that you didn’t assign to some member of the view that would lead to different behaviour next time the view was run, and you’d end up with a nightmare to debug.

Smarter debug logging with q

I stumbled across an interesting looking library completely by chance the other day. It has the impossible-to-Google name of q, so I guess other people might have overlooked it as well.

The idea is to deal with those cases that aren’t supposed to happen, but happen anyway: you’re working on a bug and want to see the value of some intermediate calculation. Ideally there would already be logging for this and you could just crank up the log level, but there never seems to be just the right values being logged. So you end up modifying the code.

There are two very basic things q can help with here:

  • It’s less to import, and less to type
  • It outputs directly to a special file (/tmp/q) that isn’t used for anything else, so logging will work even when STDOUT / STDERR are redirected.

Neither of these is decisive, on it’s own. It’s convenient that you can log the value of a variable by typing:

import q
q(my_variable)

but you could probably rig up your own library to do that in a few minutes.

Much more interesting is the ability to thread debug logging code into your existing code, without having to refactor it to expose loggable variables. This is important, because refactoring to put logging in can often be the cause of further problems.

Suppose you have some code that is using an intermediate calculation that isn’t assigned to a temporary variable:

if thing.flags & (1 << which_flag):
    apply_flag(thing)

If we want to see the value of 1 << which_flag then we have to create a temporary:

flag_value = 1 << which_flag
logger.debug("flag_value = %s", flag_value)
if thing.flags & flag_value:
    apply_flag(thing)

Whereas with q we can do:

if thing.flags & q(1 << which_flag):
    apply_flag(thing)

This works unchanged. It can do this because q() is a function that not only prints its argument but returns its argument unchanged, so wrapping q() around it doesn't change the logic.

This worked well because our sub-expression was already wrapped in parentheses. If you want to tag a single variable to be logged and you don't want to bother putting it in parentheses, you don't have to:

if q/thing.flags & (1 << which_flag):
    apply_flag(thing)

This dumps the value of thing.flags. It's able to do this because the q object has an operator overload defined on it, which customises the __div__ operator when applied to the q object. In fact, Python is seeing this as a division expression, but one that executes custom code that logs the second argument. Of course, it also returns that same value so it doesn't affect the value of the expression.

But what if you want to log the value of the whole if expression? Time for parentheses?

No again. If you want this, you can use a different operators:

if q | thing.flags & (1 << which_flag):
    apply_flag(thing)

This now writes the whole value thing.flags & (1 << which_flag) to the log.

Conclusion

This is interesting stuff. It's both a powerful tool and incredibly compact to type. There are some interesting aspects to the implementation, and I'll probably do a bit of a teardown on it.

I don't think I'll actually start using the library myself, though. The magic operators look like they might actually confuse the issue when I'm debugging. Still, it's great to see that someone came up with this and I think it deserves wider attention.