Rückgabewerte prüfen
Verfasst: Montag 12. November 2007, 00:42
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.
Der Code sieht so aus:
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.
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.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.
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