Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Beginning Python (2005)

.pdf
Скачиваний:
158
Добавлен:
17.08.2013
Размер:
15.78 Mб
Скачать

Functions

Using these files enables you to type any example only once. After an example has been typed in and saved, you can run it with python -i <filename>. The -i tells python to read your program file, and then lets you continue to interact with Python, instead of exiting immediately, which is what it normally would do. Within codeEditor, you can do this automatically by selecting Run with Interpreter from the File menu.

Try It Out

Run a Program with Python -i

To show how you can take advantage of running python -i or Run with Interpreter, enter the following code into a file called ch5-demo.py:

a = 10 b = 20

print “A added to B is %d” % (a + b)

Now when you invoke Python with the -i option, you will be in a Python interactive session that looks like the following:

A added to B is 30

>>>

How It Works

The code you entered into your ch5-demo.py file has all been evaluated now, and you can continue to interact with the values of a and b, as well as expand upon it, just as though you’d entered them by hand. This will save you time as the examples get longer. Now that you know all of this, some things will be demonstrated in the shell first, but that you can save yourself to be run later. Other things will

be shown as code within a file that needs to be saved and run. You’ll be seeing programs in files because either the material being covered doesn’t demonstrate an idea that is best shown off by forcing you to do the extra work of typing in the same thing over and over, or of having you interact with it. Or it’s simply too long to subject you to entering over and over each time you want to test it.

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

61

TEAM LinG

Chapter 5

How It Works

When you invoke ch5.py 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.

62

TEAM LinG

Functions

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__.

Try It Out

Displaying __doc__

You should now exit the interactive session that you entered in the last example and re-invoke ch5.py, since 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).

63

TEAM LinG

Chapter 5

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(in_fridge)

[‘__call__’, ‘__class__’, ‘__delattr__’, ‘__dict__’, ‘__doc__’, ‘__get__’, ‘__getattribute__’, ‘__hash__’, ‘__init__’, ‘__module__’, ‘__name__’, ‘__new__’,

‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__str__’, ‘func_closure’, ‘func_code’, ‘func_defaults’, ‘func_dict’, ‘func_doc’, ‘func_globals’, ‘func_name’]

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”

>>>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.

64

TEAM LinG

Functions

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.

Making Notes to Yourself

Python has an additional feature of the language to help you to keep track of your program. Everything that you type into a program, even if it doesn’t change how the program behaves (like docstrings) up to this point, has been processed by Python. Even unused strings will cause Python to create the string just in case you were going to use it.

In addition to unneeded strings, every programming language gives you the capability to place comments within your code that don’t have any affect whatsoever on the program. They are not there for Python to read but for you to read.

If at any point a line has the # character and it’s not in a string, Python will ignore everything that follows it. It will only begin to evaluate statements by continuing on the next line and reading the remainder of the program from there.

Try It Out

Experimenting with Comments

If you test out comments interactively you can see how they’re different from strings when Python reads them:

>>>“This is a string” ‘This is a string’

>>># This is a comment

>>>“This is a string” # with a comment at the end ‘This is a string’

65

TEAM LinG

Chapter 5

How It Works

When a comment appears by itself, Python ignores it and returns with the prompt asking for your next request, trying to prompt you to enter a statement that it can evaluate. When a comment appears on a line with something that can be evaluated, even just a string, Python knows that you have already given your instructions to it.

Normally, comments will appear in program files. It’s unlikely you’ll ever bother entering comments as annotations in your interactive sessions, but that’s how you’ll want to use them in your program files.

In addition, when you want to test changes in a program, it’s very useful to use comments to disable a line (or more than one line) of code that is causing problems by placing a comment in front of it. Be careful, though. A comment does affect the indentation that Python pays strict attention to. You need to be careful to place comments that are within functions at the proper indentation level, because if you don’t, Python will treat the comment as though it has closed out that function, if ...: block, or other cause of indentation, and that’s almost certainly not what you want!

Keeping comments at the same indentation level also makes reading the comment much easier because it is obvious to which part of the code the comment applies.

Asking a Function to Use a Value You Provide

In the in_fridge example, the values used by the function were in the global scope. The function in_fridge only operated on already defined values whose names were already visible to the whole program. This works only when you have a very small program.

When you move to larger programs consisting of hundreds, thousands, or more lines of code (the length of a program is often measured in terms of the numbers of lines it contains), you usually can’t count on the global availability of a particular name — it may be changed, based on decisions made by other people and without your involvement! Instead, you can specify that a function will, every time it is invoked, require that it be given the values that you want it to work with.

With many of the examples in the book, those that progress by offering different and improved versions of themselves can be added to the same file unless you are instructed to explicitly change the function you are working on.

You don’t always need to remove the prior revision of a function, since the next version will simply “bump” it. This gives you the opportunity to look at the changes that are being made to the function by comparing the old to the new.

As long as the most recent version is at the bottom of the file when you load it, that version will be used.

This can be a useful practice when you’re writing your own programs as well. There’s little as painful as fiddling with a piece of code that was working and then not remembering how to return it to a working state.

66

TEAM LinG

Functions

These values are the specifications or parameters that the function will use to do its job. When the function is invoked, these parameters can be names that reference data, or they can be static data such as a number like 5 or a string. In all cases, the actual data will enter the scope of the called function instead of being global.

Notice that, in the following code, def — the definition of the function — has now changed so that it specifies that the function will expect two parameters by naming them in the tuple that follows the function name. Those parameters will enter and remain in the scope of the in_fridge function, and they’ll be seen as the names some_fridge and desired_item.

def in_fridge(some_fridge, desired_item):

“””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 = some_fridge[desired_item] except KeyError:

count = 0 return count

When you invoke a function with parameters, you specify the values for the parameters by placing the values or the names you want to use between the parentheses in the invocation of the in_fridge function, separated by commas. You’ve already done this with functions like len.

Try It Out

Invoking a Function with Parameters

Once again, you should re-invoke an interactive Python session by running python -i ch5.py or use Run with Interpreter so that you will have an interactive session with the new in_fridge function defined:

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

>>>wanted_food = “oranges”

>>>in_fridge(fridge, wanted_food)

3

How It Works

The fridge dictionary and the wanted_food string are given as parameters to the new in_fridge function. After the scope of the function is entered, the dictionary referenced by fridge is now referenced by the name some_fridge. At the same time, the string “oranges”, referenced by wanted_food, is associated with the name desired_item upon entering the scope of the in_fridge function. After this set-up is done, the function has the information it needs to do its job.

To further demonstrate how this works, you can use un-named values — data that isn’t referenced from names:

>>> in_fridge({‘cookies’:10, ‘broccoli’:3, ‘milk’:2}, “cookies”)

10

These values are brought into the scope of the in_fridge function and assigned by the definition of the function to the names that are used inside of the functions. The proof of this is that there is no longer a global top-level name to be referenced from within the function.

67

TEAM LinG

Chapter 5

Checking Your Parameters

The parameters that you intend to be used could be expecting different types than what they are given when the function is called. For example, you could write a function that expects to be given a dictionary but by accident is instead given a list, and your function will run until an operation unique to a dictionary is accessed. Then the program will exit because an exception will be generated. This is different from some other languages, which try to ensure that the type of each parameter is known, and can be checked to be correct.

Python does not check to see what kind of data it’s associating to the names in a function. In most cases this isn’t a problem because an operation on the provided data will be specific to a type, and then fail to work properly if the type of data that the name references is not correct.

For instance, if in_fridge is given a number instead of a dictionary, Python, when trying to access the number as though it were a dictionary, will raise an error that the except: will not catch.. A TypeError will be generated indicating that the type Python tried to operate on isn’t capable of doing what Python expected:

>>> in_fridge(4, “cookies”) Traceback (most recent call last):

File “<stdin>”, line 1, in ?

File “<stdin>”, line 7, in in_fridge TypeError: unsubscriptable object

In this case, you’ve been shown a number being given to a function where you know that the function expects to operate on a dictionary. No matter what, a number does not have a property where a name can be used as the key to find a value. A number doesn’t have keys and it doesn’t have values. The idea is that in any context, finding 4(“cookies”) can’t be done in Python, and so an exception is raised.

The term unsubscriptable is how Python indicates that it can’t find a way to follow a key to a value the way it needs to with a dictionary. Subscripting is the term for describing when you access an element in a list or a tuple as well as a dictionary, so you can encounter this error in any of those contexts.

This behavior — not requiring you to specifically define what type you expect, and allowing you to flexibly decide how you want to treat it — can be used to your advantage. It enables you to write a single function that handles any kind of input that you want. You can write a single function that can take more than one type as its parameter and then decide how the function should behave based on the type it is given. Which approach you take depends on what you need to do in your own program.

To determine the type of some data, remember that you can use the type built-in function, which was introduced in Chapter 2. Using the output of this, you can verify the type of variable in the beginning of your functions:

def make_omelet(omelet_type):

“””This will make an omelet. You can either pass in a dictionary that contains all of the ingredients for your omelet, or provide a string to select a type of omelet this function already knows

about”””

if type(omelet_type) == type({}):

print “omelet_type is a dictionary with ingredients” return make_food(omelet_type, “omelet”)

68

TEAM LinG

Functions

elif type(omelet_type) == type(“”):

omelet_ingredients = get_omelet_ingredients(omelet_type) return make_food(omelet_ingredients, omelet_type)

else:

print “I don’t think I can make this kind of omelet: %s” % omelet_type

By itself, this definition of make_omelet won’t work because it relies on a few functions that you haven’t written yet. You will sometimes do this as you program — create names for functions that need to be written later. You’ll see these functions later in this chapter, at which point this code will become fully useable.

Try It Out

Determining More Types with the type Function

The following should be entered after loading your ch5.py file with python -i or the Run with Interpreter command:

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

>>>type(fridge)

<type ‘dict’>

>>>type({}) <type ‘dict’>

>>>type(“Omelet”) <type ‘str’>

>>>type(“”) <type ‘str’>

How It Works

The first thing to note here is that the type function returns a type object. You can use this type object in tests — it can be compared to another type object.

Try It Out

Using Strings to Compare Types

There is one other feature you can use here. You have seen that for the print function, many objects in Python can be represented as strings. This is because many objects have a built-in capability to convert themselves into strings for the times when that’s needed.

For example, an alternative way of writing the preceding comparison could be as follows:

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

>>>str(type(fridge))

“<type ‘dict’>”

>>> if str(type(fridge)) == “<type ‘dict’>”:

... print “They match!”

...

They match!

How It Works

Because you can find out ahead of time what the string representation of a type object looks like, you can use that string to compare to a type object that has been rendered into a string by the str function.

69

TEAM LinG

Chapter 5

Setting a Default Value for a Parameter — Just in Case

There is one more trick available to you to ensure that your functions will be easier to use. Every parameter to a function needs to have a value. If values aren’t assigned to the names of all of the required parameters, a function will raise an error — or worse, it could somehow return data that is wrong.

To avoid this condition, Python enables you to create functions with default values that will be assigned to the parameter’s name if the function is invoked without that parameter being explicitly provided in its invocation. You’ve already seen this behavior — for instance, with the pop method of lists, which can either be told to work on a particular element in a list, or if no value is given, will automatically use the last element.

You can do this in your own functions by using the assignment operator (the = sign) in the parameter list when you define them. For instance, if you wanted a variation on make_omelet that will make a cheese omelet by default, you have only to change its definition and nothing else.

Try It Out

Setting a Default Parameter

Cut and paste the entire make_omelet of the function to the following, you’ll

function. Then, by changing only the definition in your new copy get the behavior of having a cheese omelet by default:

def make_omelet2(omelet_type = “cheese”):

How It Works

This definition doesn’t change the way that any of the remaining code in the function behaves. It sets up omelet_type only if it hasn’t been defined when the make_omelet2 function is invoked.

This still enables you to specify an omelet by using a dictionary or a different kind of omelet! However, if make_omelet is defined this way, you can call it without any particular kind of omelet being specified; and instead of bailing out on you, the function will make you a cheese omelet.

Doing this same thing to make_omelet is the first step toward writing a make_omelet function that will be able to behave in a friendly and obvious way. Remember, though, that you still need to write other functions! The goal is to have output like the following:

>>> make_omelet()

Adding 2 of eggs to make a cheese Adding 2 of cheddar to make a cheese Adding 1 of milk to make a cheese Made cheese

‘cheese’

>>> make_omelet(“western”)

Adding 1 of pepper to make a western Adding 1 of ham to make a western Adding 1 of onion to make a western Adding 2 of eggs to make a western

Adding 2 of jack_cheese to make a western Adding 1 of milk to make a western

Made western ‘western’

70

TEAM LinG