Online Book Reader

Home Category

Learning Python - Mark Lutz [559]

By Root 1698 0

More importantly, by moving the validation specifications into the def header, we essentially commit the function to a single role—since annotation allows us to code only one expression per argument, it can have only one purpose. For instance, we cannot use range-test annotations for any other role.

By contrast, because decorator arguments are coded outside the function itself, they are both easier to remove and more general—the code of the function itself does not imply a single decoration purpose. In fact, by nesting decorators with arguments, we can apply multiple augmentation steps to the same function; annotation directly supports only one. With decorator arguments, the function itself also retains a simpler, normal appearance.

Still, if you have a single purpose in mind, and you can commit to supporting 3.X only, the choice between annotation and decorator arguments is largely stylistic and subjective. As is so often true in life, one person’s annotation may well be another’s syntactic clutter....

Other Applications: Type Testing (If You Insist!)

The coding pattern we’ve arrived at for processing arguments in decorators could be applied in other contexts. Checking argument data types at development time, for example, is a straightforward extension:

def typetest(**argchecks):

def onDecorator(func):

....

def onCall(*pargs, **kargs):

positionals = list(allargs)[:len(pargs)]

for (argname, type) in argchecks.items():

if argname in kargs:

if not isinstance(kargs[argname], type):

...

raise TypeError(errmsg)

elif argname in positionals:

position = positionals.index(argname)

if not isinstance(pargs[position], type):

...

raise TypeError(errmsg)

else:

# Assume not passed: default

return func(*pargs, **kargs)

return onCall

return onDecorator

@typetest(a=int, c=float)

def func(a, b, c, d): # func = typetest(...)(func)

...

func(1, 2, 3.0, 4) # Okay

func('spam', 2, 99, 4) # Triggers exception correctly

In fact, we might even generalize further by passing in a test function, much as we did to add Public decorations earlier; a single copy of this sort of code would suffice for both range and type testing. Using function annotations instead of decorator arguments for such a decorator, as described in the prior section, would make this look even more like type declarations in other languages:

@typetest

def func(a: int, b, c: float, d): # func = typetest(func)

... # Gasp!...

As you should have learned in this book, though, this particular role is generally a bad idea in working code, and not at all Pythonic (in fact, it’s often a symptom of an ex-C++ programmer’s first attempts to use Python).

Type testing restricts your function to work on specific types only, instead of allowing it to operate on any types with compatible interfaces. In effect, it limits your code and breaks its flexibility. On the other hand, every rule has exceptions; type checking may come in handy in isolated cases while debugging and when interfacing with code written in more restrictive languages, such as C++. This general pattern of argument processing might also be applicable in a variety of less controversial roles.

Chapter Summary

In this chapter, we explored decorators—both the function and class varieties. As we learned, decorators are a way to insert code to be run automatically when a function or class is defined. When a decorator is used, Python rebinds a function or class name to the callable object it returns. This hook allows us to add a layer of wrapper logic to function calls and class instance creation calls, in order to manage functions and instances. As we also saw, manager functions and manual name rebinding can achieve the same effect, but decorators provide a more explicit and uniform solution.

As we’ll see in the next chapter, class decorators can also be used to manage classes themselves, rather than just their instances. Because this functionality overlaps with metaclasses, the topic of the next chapter, you’ll have to read ahead for the rest of this story. First, though, work

Return Main Page Previous Page Next Page

®Online Book Reader