Online Book Reader

Home Category

Learning Python - Mark Lutz [251]

By Root 1890 0
in very flexible ways:

>>> func(*(1, 2), **{'d': 4, 'c': 4})

1 2 4 4

>>> func(1, *(2, 3), **{'d': 4})

1 2 3 4

>>> func(1, c=3, *(2,), **{'d': 4})

1 2 3 4

>>> func(1, *(2, 3), d=4)

1 2 3 4

>>> f(1, *(2,), c=3, **{'d':4})

1 2 3 4

This sort of code is convenient when you cannot predict the number of arguments that will be passed to a function when you write your script; you can build up a collection of arguments at runtime instead and call the function generically this way. Again, don’t confuse the */** syntax in the function header and the function call—in the header it collects any number of arguments, while in the call it unpacks any number of arguments.

* * *

Note


As we saw in Chapter 14, the *pargs form in a call is an iteration context, so technically it accepts any iterable object, not just tuples or other sequences as shown in the examples here. For instance, a file object works after the *, and unpacks its lines into individual arguments (e.g., func(*open('fname')).

This generality is supported in both Python 3.0 and 2.6, but it holds true only for calls—a *pargs in a call allows any iterable, but the same form in a def header always bundles extra arguments into a tuple. This header behavior is similar in spirit and syntax to the * in Python 3.0 extended sequence unpacking assignment forms we met in Chapter 11 (e.g., x, *y = z), though that feature always creates lists, not tuples.

* * *

Applying functions generically

The prior section’s examples may seem obtuse, but they are used more often than you might expect. Some programs need to call arbitrary functions in a generic fashion, without knowing their names or arguments ahead of time. In fact, the real power of the special “varargs” call syntax is that you don’t need to know how many arguments a function call requires before you write a script. For example, you can use if logic to select from a set of functions and argument lists, and call any of them generically:

if :

action, args = func1, (1,) # Call func1 with 1 arg in this case

else:

action, args = func2, (1, 2, 3) # Call func2 with 3 args here

...

action(*args) # Dispatch generically

More generally, this varargs call syntax is useful any time you cannot predict the arguments list. If your user selects an arbitrary function via a user interface, for instance, you may be unable to hardcode a function call when writing your script. To work around this, simply build up the arguments list with sequence operations, and call it with starred names to unpack the arguments:

>>> args = (2,3)

>>> args += (4,)

>>> args

(2, 3, 4)

>>> func(*args)

Because the arguments list is passed in as a tuple here, the program can build it at runtime. This technique also comes in handy for functions that test or time other functions. For instance, in the following code we support any function with any arguments by passing along whatever arguments were sent in:

def tracer(func, *pargs, **kargs): # Accept arbitrary arguments

print('calling:', func.__name__)

return func(*pargs, **kargs) # Pass along arbitrary arguments

def func(a, b, c, d):

return a + b + c + d

print(tracer(func, 1, 2, c=3, d=4))

When this code is run, arguments are collected by the tracer and then propagated with varargs call syntax:

calling: func

10

We’ll see larger examples of such roles later in this book; see especially the sequence timing example in Chapter 20 and the various decorator tools we will code in Chapter 38.

The defunct apply built-in (Python 2.6)

Prior to Python 3.0, the effect of the *args and **args varargs call syntax could be achieved with a built-in function named apply. This original technique has been removed in 3.0 because it is now redundant (3.0 cleans up many such dusty tools that have been subsumed over the years). It’s still available in Python 2.6, though, and you may come across it in older 2.X code.

In short, the following are equivalent prior to Python 3.0:

func(*pargs, **kargs) # Newer call syntax: func(*sequence, **dict)

apply(func, pargs,

Return Main Page Previous Page Next Page

®Online Book Reader