Python Functions

Python Functions: Grouping Code under a Name

Most modern programming languages provide you with the capability to group code together under a name; and whenever you use that name, all of the code that was grouped together is invoked and evaluated without having to be retyped every time.

To create a named function that will contain your code, you use the word def, which you can think of as defining a functional block of code.

Try It Out Defining a Function

Try saving the following in your file for Chapter 5, ch5.py.def in_fridge():

    try:

        count = fridge[wanted_food]

    except KeyError:

        count = 0

    return count

How It Works

When you invoke ch5.py (press F5 while in Code Editor) with just the in_fridge function defined, you won’t see any output. However, the function will be defined, and it can be invoked from the interactive Python session that you’ve created.

To take advantage of the in_fridge function, though, you have to ensure that there is a dictionary called fridge with food names in it. In addition, you have to have a string in the name wanted_food. This string is how you can ask, using in_fridge, whether that food is available. Therefore, from the interactive session, you can do this to use the function:

>>> fridge = {‘apples’:10, ‘oranges’:3, ‘milk’:2}

>>> wanted_food = ‘apples’

>>> in_fridge()

10

>>> wanted_food = ‘oranges’

>>> in_fridge()

3

>>> wanted_food = ‘milk’

>>> in_fridge()

2

This is more than just useful — it makes sense and it saves you work. This grouping of blocks of code under the cover of a single name means that you can now simplify your code, which in turn enables you to get more done more quickly. You can type less and worry less about making a mistake as well.

Functions are a core part of any modern programming language, and they are a key part of getting problems solved using Python.

Functions can be thought of as a question and answer process when you write them. When they are invoked, a question is often being asked of them: “How many?,” “What time?,” “Does this exist?” “Can this be changed?” and more. In response, functions will often return an answer — a value that will contain an answer, such as True, a sequence, a dictionary, or another type of data. In the absence of any of these, the answer returned is the special value None.

Even when a function is mainly being asked to just get something simple done, there is usually an implied question that you should know to look for. When a function has completed its task, the questions “Did it work?” or “How did it work out?” are usually part of how you invoke the function.

Choosing a Name

One of the first guidelines to writing functions well is that you should name your functions to reflect their purpose. They should indicate what you want them to do. Examples of this that come with Python that you have seen are print, type, and len.

When you decide on a name, you should think about how it will be invoked in the program. It is always good to name a function so that when it’s called, it will be read naturally by yourself and others later. It is very common to forget the specifics of what you put into a function within a couple of weeks, so the name becomes the touchstone that you use to recall what it’s doing when you return to use it again later.

Describing a Function in the Function

After you’ve chosen a name for your function, you should also add a description of the function. Python enables you to do this in a way that is simple and makes sense.

If you place a string as the first thing in a function, without referencing a name to the string, Python will store it in the function so you can reference it later. This is commonly called a docstring, which is short for documentation string.

Documentation in the context of a function is anything written that describes the part of the program (the function, in this case) that you’re looking at. It’s famously rare to find computer software that is well documented. However, the simplicity of the docstring feature in Python makes it so that, generally, much more information is available inside Python programs than in programs written in other languages that lack this friendly and helpful convention.

The text inside the docstring doesn’t necessarily have to obey the indentation rules that the rest of the source code does, because it’s only a string. Even though it may visually interrupt the indentation, it’s important to remember that, when you’ve finished typing in your docstring, the remainder of your functions must still be correctly indented.

def in_fridge ():

    """This is a function to see if the fridge has a food.

fridge has to be a dictionary defined outside of the function.

the food to be searched for is in the string wanted_food"""

    try:

        count = fridge[wanted_food]

    except KeyError:

        count = 0

    return count

The docstring is referenced through a name that is part of the function, almost as though the function were a dictionary. This name is __doc__, and it’s found by following the function name with a period and the name __doc__. Note that there are two underscores (_) preceding and following doc.

Try It Out Displaying __doc__

You should now exit the interactive session that you entered in the last example and re-invoke ch5.py, because it now has the docstring added to in_fridge. After you’ve done that, you can do the following:

>>> print("%s" % in_fridge.__doc__)

This is a function to see if the fridge has a food.

fridge has to be a dictionary defined outside of the function.

the food to be searched for is in the string wanted_food

How It Works

Functions, like other types you’ve seen, have properties that can be used by following the name of the function with a period and the name of the property. __doc__ is a string like any other and can be easily printed for your reference while you’re in an interactive session.

The function has other information too (a set of information that it maintains that can be viewed with the built-in function dir).

dir shows you all of the properties of the object in which you’re interested, such as a function, including things that Python uses internally:

>>> dir()

[‘__annotations__’, ‘__call__’, ‘__class__’, ‘__closure__’, ‘__code__’,

‘__defaults__’, ‘__delattr__’, ‘__dict__’, ‘__doc__’, ‘__eq__’, ‘__format__’,

‘__ge__’, ‘__get__’, ‘__getattribute__’, ‘__globals__’, ‘__gt__’, ‘__hash__’,

‘__init__’, ‘__kwdefaults__’, ‘__le__’, ‘__lt__’, ‘__module__’, ‘__name__’,

‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’,

__setattr__’,’__sizeof__’, ‘__str__’, ‘__subclasshook__’]

Any of these properties can be accessed using the same notation that you used for getting the data referenced by in_fridge.__doc__, but normally you don’t need to use most of these attributes directly, although it is a good exercise to explore these elements with the type built-in function to see how Python describes them.

The Same Name in Two Different Places

One special property of a function is that it’s the first example you’ve seen of how the names that refer to values can be compartmentalized. What this means is that if you have a name outside of a function, that name refers to a particular value—whether it’s a string, a number, a dictionary, a sequence, or a function. All of these share the same space.

For example, if you create a name for a string and then on the next line create a dictionary and reference it to the same name, the string would no longer be referenced by that name, only the dictionary:

>>> fridge = "Chilly Ice Makers"

>>> print(fridge)

Chilly Ice Makers

>>> fridge = {‘apples’:10, ‘oranges’:3, ‘milk’:2}

>>> print("%s" %  fridge)

{‘apples’: 10, ‘oranges’: 3, ‘milk’: 2}

This makes sense; however, this changes within a function when it’s being used. The function creates a new space in which names can be reused and re-created without affecting the same names if they exist in other spaces in your program. This enables you to write functions without worrying about having to micromanage whether somewhere, in another function, a name that you are using is already being used.

Therefore, when you are writing a function, your function has its names, and another function has its own names, and they are separate. Even when a name in both functions contains all of the same letters, because they’re each in separate functions they are completely separate entities that will reference separate values.

At the same time, if a function is going to be used in a known situation, where you have ensured that a name it needs to use will be defined and have the right data already referenced, it is able to access this global data by using that already-defined name. Python’s ability to do this comes from separating the visibility of a name into separate conceptual areas. Each one of these areas is called a scope.

Scope defines how available any name is to another part of the program. The scope of a name that’s used inside of a function can be thought of as being on a vertical scale. The names that are visible everywhere are at the top level and they are referred to in Python as being global. Names in any particular function are a level below that — a scope that is local to each function. Functions do not share these with other functions at the same level; they each have their own scope.

Any name in the top-level scope can be reused in a lower-level scope without affecting the data referred to by the top-level name:

>>> special_sauce = [‘ketchup’, ‘mayonnaise’, ‘french dressing’]

>>> def make_new_sauce():

…     """This function makes a new special sauce all its own"""

…     special_sauce = ["mustard", "yogurt"]

…     return special_sauce

At this point, there is a special sauce in the top-level scope, and another that is used in the function make_new_sauce. When they are run, you can see that the name in the global scope is not changed:

>>> print("%s" % special_sauce)

[‘ketchup’, ‘mayonnaise’, ‘french dressing’]

>>> new_sauce = make_new_sauce() 

>>> print(special_sauce)

[‘ketchup’, ‘mayonnaise’, ‘french dressing’]

>>> print(new_sauce)

[‘mustard’, ‘yogurt’]

Remember that different functions can easily use the same name for a variable defined inside the function — a name that will make sense in both functions, but reference different values, without conflicting with each other. 

This article is excerpted from chapter 5 "Functions" of the book "Beginning Python: Using Python 2.6 and Python 3.1" by  James Payne (ISBN: 978-0-470-41463-7, Wrox, 2010, Copyright Wiley Publishing Inc.)

Tags:

Comments

One response to “Python Functions”

  1. Anonymous says:

    same name in two different places? Uhh… do we not call it function overloading anymore?

    -NUMBer0001

Leave a Reply

Your email address will not be published. Required fields are marked *