Page 29 - MSDN Magazine, November 2019
P. 29
The triple-quoted string is what’s often called a “here-doc” multi- line string literal—it will capture everything inside the pair of triple quotes, including whitespace, making it useful for documentation purposes. Additionally, Python will do something quite special to this string—it will capture it into a property on the function itself, and make it discoverable at runtime via the “__doc__” property name. To see what this means, try calling this bit of Python after the function has been defined:
print(theKnightsWhoSayNi.__doc__)
Lo and behold—helpful documentation about the function is printed to the command line! And it turns out that this “__doc__” is not the only interesting thing on the function—if you do a dir on the function name, a whole slew of interesting things (properly called “attributes”) appear:
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
Clearly, Python is doing a fair bit of interesting organization and structuring of functions under the hood.
Customizing Arguments
In some cases, you want arguments to be optional, meaning you want to provide a default value to the parameter in the event the caller doesn’t provide one. This is done by providing said value in the function definition:
def theKnightsWhoSayNi(gift = None):
"""In order to continue your quest for Camelot, you must bring the Knights gifts. Do not mess with these guys, for they say 'Ni' at the slightest provocation!"""
if gift == "shrubbery":
return ("You must now cut down the tallest tree" "in the forest... with... A HERRING!!!!")
else:
return "You must bring us... A SHRUBBERY!!!"
Now the function can be invoked with either one parameter or none. None, by the way, is the closest equivalent Python has to null or nil in other languages.
Python also has what they call “keyword parameters,” which allows you to use named parameters in function calls instead of (or in addition to) positional ones. This means that if you have a function defined with a few default values, like so:
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'): print("-- This parrot wouldn't", action, end=' ')
print("if you put", voltage, "volts through it.")
print("-- Lovely plumage, the", type)
print("-- It's", state, "!")
You can then call the function in a variety of different ways, either by using positional arguments (the normal way) or by key- word arguments, like this:
parrot(1000)
parrot(type='Turkish Red', action='caw', voltage=1000)
In any case, all non-default parameters must have a value, and keyword arguments can only appear after all positional arguments do. If you prefer to pass a dictionary for the arguments, put two asterisks in front of the dictionary parameter at the point of call:
d = {"voltage": "a million", "state":"bleedin' demised"} parrot(**d)
Python also allows for arbitrary argument lists, akin to the “params” modifier from C#, if the parameter is declared with an msdnmagazine.com
asterisk preceding its name. This will then capture all positional arguments after that point into a single list for processing, like so:
def order(bread, sides, *fixings): print("Making you a Spam-on-", bread) print(" with", sides)
for f in fixings:
print(" and", f) print("Enjoy!")
order("white", "pickles")
order("wheat", "radishes", "pickles", "chips", "pint o' lager")
Nothing prevents you from writing all your functions to take one arbitrary argument list, just as you can do in ECMAScript, but most of the time that’s not idiomatic Python and will likely get somebody to chase you with a herring.
Anonymous Functions
Python also supports functions-as-first-class-citizens out of the box, in terms of passing a function as a parameter, such as what you might use in the map global function, which executes a func- tion over each element of a list:
items = ["bread", "eggs", "milk"] def spametize(item): return "spam"
spamCafeOrder = map(spametize, items) print("We need to go to the market and get:") for it in spamCafeOrder: print(it)
In some cases, you want arguments to be optional, meaning you want to provide a default value to the parameter in the event the caller doesn’t provide one.
But when working with functions, it’s often useful to define a function anonymously. In Python, you do this via the “lambda” key- word, which replaces the “def ” and function name in the definition:
def add(lhs, rhs): return lhs + rhs def makeAdder(lhs):
return lambda rhs: add(lhs, rhs)
addFive = makeAdder(5) print(addFive(12)) # prints 17
Unlike other languages, Python insists that lambda functions be restricted to small-use scenarios: A given lambda-defined func- tion can only consist of a single expression (such as the add call in the preceding example).
Wrapping Up
Python functions are among the core building blocks of the plat- form, and every bit as important as classes and objects. Unlike some of the “traditional” object-oriented languages (C#/C++/ Java), Python not only doesn’t fear global functions, it embraces them as a key design tool.
November 2019 17