Seite 1 von 1

Rückgabewerte prüfen

Verfasst: Montag 12. November 2007, 00:42
von Leonidas
Hi,

Heute gibt es von mir ein Snippet, bei dem ich mir gedacht habe, dass es andere Leute auch brauchen könnten.

Wie man Dekorator-Funktionen schreibt ist ziemlich simpel, ich fand es hingegen schwerer einen Dekorator zu schreiben der Parameter nimmt. Wenn man nicht weiß, wie man herangehen soll ist das gar nicht so einfach wie man denken würde, da man dafür zwei innere Funktionen braucht.
What's new in Python 2.4 hat geschrieben:Decorator functions can take arguments. If arguments are supplied, your decorator function is called with only those arguments and must return a new decorator function; this function must take a single function and return a function, as previously described.
Ich habe mir nun einen Dekorator geschrieben, der die Rückgabewerte der gewrappten Funktion prüft und wahlweise eine Warnung oder eine Exception wirft. Das ist in der Tat eine Art Emulation von Static Typing. Wobei es aber besser ist als das, denn ich brauche es eigentlich nur um festzustellen, welche Funktion keine Werte (also `None`) zurückgibt - ansonsten steht es der Funktion frei andere Werte auszugeben. Ich habe in letzter Zeit viele Funktionen geschrieben, die nichts zurückgeben, jetzt muss ich schauen dass sie etwas sinnvolles zurückgeben und dafür ist dieser Dekorator gut.

Der Code sieht so aus:

Code: Alles auswählen

import warnings

class NoneWarning(Warning):
    """A subclass of warning which is issued when a function returns None"""

def ensure_not_none(warn=True):
    """Decorator for some kind of type checking. It ensures that the function
    does not return None.

    Usage is simple: you just need to write a function, and either use the
    @decorator syntax on functions or use the wrapping syntax known from earlier
    Python versions. You can specify a parameter which defines whether to
    display a `NoneWarning` (default behaviour) or to raise an `AssertionError`.

    This is far from perfect, as the _value_check function should behave
    *exactly* as the wrapped function except for the return value
    checking but we don't intend to overengineer.

    Python 2.5 has a very nifty function called functools.update_wrapper,
    but as we're currently on Python 2.4 mostly, this is not yet an option.

    For more documentation about how to write decorators in Python read
    <http://www.phyast.pitt.edu/~micheles/python/documentation.html>"""

    def _wrapper(fn):
        def _value_check(*args, **kwargs):
            """Wrapper function which checks the return value
            (this docstring will be overridden by re-setting __doc__ anyway)"""

            # call the wrapped function
            val = fn(*args, **kwargs)
            # check the return value
            if val is None:
                # it doesn't matter what we do here. We could just as well
                # issue a warning message using the warnings module.
                if warn:
                    # show a warning, adjust the stack level of the warning
                    warnings.warn('Returned None', NoneWarning, stacklevel=2)
                else:
                    # no, don't warn - raise exceptions
                    raise AssertionError('Returned None')
            # if the value was not None, we can return it
            return val

        # set up some voodoo to make the inner function seem to be like the
        # wrappend function (this is the part which functools.update_wrapper
        # solves)
        _value_check.__doc__ = fn.__doc__
        _value_check.__name__ = fn.__name__
        _value_check.__module__ = fn.__module__

        # return the value-checking wrapper
        return _value_check

    # return the _wrapper function from the inner which is another wrapper
    return _wrapper