Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decorator classes in Python

I want to construct classes for use as decorators with the following principles intact:

  1. It should be possible to stack multiple such class decorators on top off 1 function.
  2. The resulting function name pointer should be indistinguishable from the same function without a decorator, save maybe for just which type/class it is.
  3. Ordering off the decorators should not be relevant unless actually mandated by the decorators. Ie. independent decorators could be applied in any order.

This is for a Django project, and the specific case I am working on now the method needs 2 decorators, and to appear as a normal python function:

@AccessCheck @AutoTemplate def view(request, item_id) {} 

@AutoTemplate changes the function so that instead of returning a HttpResponse, it just returns a dictionary for use in the context. A RequestContext is used, and the template name is inferred from the method name and module.

@AccessCheck adds additional checks on the user based on the item_id.

I am guessing it's just to get the constructor right and copy the appropriate attributes, but which attributes are these?

The following decorator won't work as I describe:

class NullDecl (object):     def __init__ (self, func):         self.func = func     def __call__ (self, * args):         return self.func (*args) 

As demonstrated by the following code:

@NullDecl @NullDecl def decorated():     pass  def pure():     pass  # results in set(['func_closure', 'func_dict', '__get__', 'func_name', # 'func_defaults', '__name__', 'func_code', 'func_doc', 'func_globals']) print set(dir(pure)) - set(dir(decorated)); 

Additionally, try and add "print func.name" in the NullDecl constructor, and it will work for the first decorator, but not the second - as name will be missing.

Refined eduffy's answer a bit, and it seems to work pretty well:

class NullDecl (object):     def __init__ (self, func):         self.func = func         for n in set(dir(func)) - set(dir(self)):             setattr(self, n, getattr(func, n))      def __call__ (self, * args):         return self.func (*args)     def __repr__(self):         return self.func 
like image 563
Staale Avatar asked Mar 20 '09 13:03

Staale


People also ask

Can we use decorator on class in Python?

In Python, decorators can be either functions or classes. In both cases, decorating adds functionality to existing functions. When we decorate a function with a class, that function becomes an instance of the class.

What is decorator in Python?

A decorator is a design pattern in Python that allows a user to add new functionality to an existing object without modifying its structure. Decorators are usually called before the definition of a function you want to decorate.

What are different types of decorators in Python?

In fact, there are two types of decorators in Python — class decorators and function decorators — but I will focus on function decorators here. Before we get into the fun details of how a basic decorator works and how to implement your own decorators, let's see why we need them in the first place.

How do you call a class decorator in Python?

To decorate a method in a class, first use the '@' symbol followed by the name of the decorator function. A decorator is simply a function that takes a function as an argument and returns yet another function. Here, when we decorate, multiply_together with integer_check, the integer function gets called.


1 Answers

A do-nothing decorator class would look like this:

class NullDecl (object):    def __init__ (self, func):       self.func = func       for name in set(dir(func)) - set(dir(self)):         setattr(self, name, getattr(func, name))     def __call__ (self, *args):       return self.func (*args) 

And then you can apply it normally:

@NullDecl def myFunc (x,y,z):    return (x+y)/z 
like image 118
eduffy Avatar answered Sep 28 '22 17:09

eduffy