def setter_decorator(fset):
    """
    Define a write-only property that, in addition to the given setter function, also
    provides a setter decorator defined as the property's getter function.

    This allows one to set the property either through traditional assignment, as a
    method argument, or through decoration::

        class Widget(object):
            @setter_decorator
            def handler(self, value):
                self._handler = value

        widget = Widget()

        # Method 1: Traditional assignment
        widget.handler = lambda input: process(input)

        # Method 2: Assignment via method argument
        widget.handler(lambda input: process(input))

        # Method 3: Assignment via decoration
        @widget.handler
        def handler(input):
            return process(input)

        # Method 3b: Assignment via decoration with extraneous parens
        @widget.handler()
        def handler(input):
            return process(input)
    """

    def fget(self):
        def inner(value):
            fset(self, value)

        def outer(value=None):
            if value:
                # We are being called with the desired value, either directly or
                # as a decorator.
                inner(value)
            else:
                # Assume we are being called as a decorator with extraneous parens,
                # so return the setter as the actual decorator.
                return inner

        return outer

    fdoc = fset.__doc__

    return property(fget, fset, None, fdoc)
Define a write-only property that, in addition to the given setter function, also
    provides a setter decorator defined as the property's getter function.

    This allows one to set the property either through traditional assignment, as a
    method argument, or through decoration::

        class Widget(object):
            @setter_decorator
            def handler(self, value):
                self._handler = value

        widget = Widget()

        # Method 1: Traditional assignment
        widget.handler = lambda input: process(input)

        # Method 2: Assignment via method argument
        widget.handler(lambda input: process(input))

        # Method 3: Assignment via decoration
        @widget.handler
        def handler(input):
            return process(input)

        # Method 3b: Assignment via decoration with extraneous parens
        @widget.handler()
        def handler(input):
            return process(input)