title: Python: Decorators: How does the following code work?
body: <p><strong>Are the comments in the following code correct? Particularly the "instance =..." one?</strong></p>
  
  <pre><code># This does nothing.
  
  class donothing(object):
      def __init__(self, func):
          """
          The 'func' argument is the function being decorated because in this
          case, we're not instantiating the decorator class. Instead we are just
          using the class object as a callable (a class is always callable as this
          is how an instance is returned) to use as a decorator, which means that
          it is being instantiated upon definition of the decorated function and
          the decorated function is being passed in as an argument to the class's
          __init__ method.
          """
          self.func = func
  
      def __call__(self, *args, **kwargs):
          """
          The __call__ function is called when the decorated function is called
          because the function has be eaten by the decorator class. Now it's up to
          the this method to return a call to the original function. The arguments
          are passed in as args, kwargs to be manipulated.
          """
          # Returns original function call with original arguments.
          return self.func(*args, **kwargs)
  
  @donothing
  def printer(text):
      print(text)
  
  printer('hello world')
  
  # The printer function is now an alias for the donothing instance created, so
  # the preceding was the same as:
  #
  # instance = donothing(printer)
  # instance('hello world')
  #
  
  
  # Next example:
  
  class checkforkeysinparams(object):
      def __init__(self, required):
          self.required = set(required)
  
      def __call__(self, params):
          def wrapper(params):
              missing = self.required.difference(params)
              if missing:
                  raise TypeError('Missing from "params" argument: %s' % ', '.join(sorted(missing)))
          return wrapper
  
  
  # Apply decorator class, passing in the __init__'s 'required' argument.
  
  @checkforkeysinparams(['name', 'pass', 'code'])
  def complex_function(params):
      # Obviously these three are needed or a KeyError will be raised.
      print(params['name'])
      print(params['pass'])
      print(params['code'])
  
  
  # Create params to pass in. Note, I've commented out one of the required params.
  
  params = {
      'name': 'John Doe',
      'pass': 'OpenSesame',
      #'code': '1134',
  }
  
  # This call will output: TypeError: Missing from "params" argument: code
  
  complex_function(params=params)
  </code></pre>