【Python】Basics - Functions

Posted by 西维蜀黍 on 2019-09-18, Last Modified on 2024-05-07

defining a function

Here’s a simple function named greet_user() that prints a greeting:

def greet_user():
		"""Display a simple greeting."""
		print("Hello!")
		greet_user()

Keyword Arguments

A keyword argument is a name-value pair that you pass to a function. You directly associate the name and the value within the argument, so when you pass the argument to the function, there’s no confusion (you won’t end up with a harry named Hamster). Keyword arguments free you from having to worry about correctly ordering your arguments in the function call, and they clarify the role of each value in the function call.

Let’s rewrite pets.py using keyword arguments to call describe_pet():

def describe_pet(animal_type, pet_name):
    """Display information about a pet.""" 
    print("\nI have a " + animal_type + ".") 
    print("My " + animal_type + "'s name is " + pet_name.title() + ".")

describe_pet(animal_type='hamster', pet_name='harry')

The function describe_pet() hasn’t changed. But when we call the func-tion, we explicitly tell Python which parameter each argument should be matched with. When Python reads the function call, it knows to store the argument ‘hamster’ in the parameter animal_type and the argument ‘harry’ in pet_name. The output correctly shows that we have a hamster named Harry.

The order of keyword arguments doesn’t matter because Python knows where each value should go. The following two function calls are equivalent:

describe_pet(animal_type='hamster', pet_name='harry') 
describe_pet(pet_name='harry', animal_type='hamster')

Default Values

When writing a function, you can define a default value for each parameter. If an argument for a parameter is provided in the function call, Python uses the argument value. If not, it uses the parameter’s default value. So when you define a default value for a parameter, you can exclude the corresponding argument you’d usually write in the function call. Using default values can simplify your function calls and clarify the ways in which your functions are typically used.

For example, if you notice that most of the calls to describe_pet() are being used to describe dogs, you can set the default value of animal_type to ‘dog’. Now anyone calling describe_pet() for a dog can omit that information:

def describe_pet(pet_name, animal_type='dog'):
		"""Display information about a pet.""" 
    print("\nI have a " + animal_type + ".") 
    print("My " + animal_type + "'s name is " + pet_name.title() + ".")

describe_pet(pet_name='willie')

We changed the definition of describe_pet() to include a default value, ‘dog’, for animal_type. Now when the function is called with no animal_type specified, Python knows to use the value ‘dog’ for this parameter:

I have a dog.
My dog's name is Willie.

Equivalent Function Calls

All of the following calls would work for this function:

# A dog named Willie. 
describe_pet('willie') 
describe_pet(pet_name='willie')

# A hamster named Harry.
describe_pet('harry', 'hamster') 
describe_pet(pet_name='harry', animal_type='hamster') 
describe_pet(animal_type='hamster', pet_name='harry')

return Values

A function doesn’t always have to display its output directly. Instead, it can process some data and then return a value or set of values. The value the function returns is called a return value. The return statement takes a value from inside a function and sends it back to the line that called the function. Return values allow you to move much of your program’s grunt work into functions, which can simplify the body of your program.

Returning a Simple Value

Let’s look at a function that takes a first and last name, and returns a neatly formatted full name:

def get_formatted_name(first_name, last_name):	
		"""Return a full name, neatly formatted."""
		full_name = first_name + ' ' + last_name
		return full_name.title()

musician = get_formatted_name('jimi', 'hendrix') 
print(musician)

Making an Argument Optional

def get_formatted_name(first_name, last_name, middle_name=''):
	"""Return a full name, neatly formatted.""" 
	if middle_name:
		full_name = first_name + ' ' + middle_name + ' ' + last_name
	else:
		full_name = first_name + ' ' + last_name
	return full_name.title()

musician = get_formatted_name('jimi', 'hendrix') 
print(musician)

musician = get_formatted_name('john', 'hooker', 'lee') 
print(musician)

In this example, the name is built from three possible parts. Because there’s always a first and last name, these parameters are listed first in the function’s definition. The middle name is optional, so it’s listed last in the definition, and its default value is an empty string.

Passing an arbitrary number of arguments

Sometimes you won’t know ahead of time how many arguments a function needs to accept. Fortunately, Python allows a function to collect an arbitrary number of arguments from the calling statement.

For example, consider a function that builds a pizza. It needs to accept a number of toppings, but you can’t know ahead of time how many toppings a person will want. The function in the following example has one param-eter, *toppings, but this parameter collects as many arguments as the calling line provides:

def make_pizza(*toppings):
		"""Print the list of toppings that have been requested.""" 
		print(toppings)

make_pizza('pepperoni') 
make_pizza('mushrooms', 'green peppers', 'extra cheese')

The asterisk in the parameter name *toppings tells Python to make an empty tuple called toppings and pack whatever values it receives into this tuple. The print statement in the function body produces output showing that Python can handle a function call with one value and a call with three values. It treats the different calls similarly. Note that Python packs the arguments into a tuple, even if the function receives only one value:

('pepperoni',) 
('mushrooms', 'green peppers', 'extra cheese')

Now we can replace the print statement with a loop that runs through the list of toppings and describes the pizza being ordered:

def make_pizza(*toppings):
		"""Summarize the pizza we are about to make.""" 
		print("\nMaking a pizza with the following toppings:") 
		for topping in toppings:
			print("- " + topping)

make_pizza('pepperoni') 
make_pizza('mushrooms', 'green peppers', 'extra cheese')

Using Arbitrary Keyword Arguments

Sometimes you’ll want to accept an arbitrary number of arguments, but you won’t know ahead of time what kind of information will be passed to the function. In this case, you can write functions that accept as many key-value pairs as the calling statement provides. One example involves building user profiles: you know you’ll get information about a user, but you’re not sure what kind of information you’ll receive. The function build_profile() in the following example always takes in a first and last name, but it accepts an arbitrary number of keyword arguments as well:

def build_profile(first, last, **user_info):
		"""Build a dictionary containing everything we know about a user.""" 
		profile = {} 
		profile['first_name'] = first 
		profile['last_name'] = last 
		for key, value in user_info.items():
			profile[key] = value 
		return profile

user_profile = build_profile('albert', 'einstein', location='princeton', field='physics') print(user_profile)

The definition of build_profile() expects a first and last name, and then it allows the user to pass in as many name-value pairs as they want. The double asterisks before the parameter **user_info cause Python to create an empty dictionary called user_info and pack whatever name-value pairs it receives into this dictionary. Within the function, you can access the name-value pairs in user_info just as you would for any dictionary.

In the body of build_profile(), we make an empty dictionary called profile to hold the user’s profile. At u we add the first and last names to this dictionary because we’ll always receive these two pieces of information from the user. At v we loop through the additional key-value pairs in the dictionary user_info and add each pair to the profile dictionary. Finally, we return the profile dictionary to the function call line.

We call build_profile(), passing it the first name ‘albert’, the last name ’einstein’, and the two key-value pairs location=‘princeton’ and field=‘physics’. We store the returned profile in user_profile and print user_profile:

{'first_name': 'albert', 'last_name': 'einstein', 'location': 'princeton', 'field': 'physics'}

The returned dictionary contains the user’s first and last names and, in this case, the location and field of study as well. The function would work no matter how many additional key-value pairs are provided in the function call.

You can mix positional, keyword, and arbitrary values in many different ways when writing your own functions. It’s useful to know that all these argument types exist because you’ll see them often when you start reading other people’s code. It takes practice to learn to use the different types correctly and to know when to use each type. For now, remember to use the simplest approach that gets the job done. As you progress you’ll learn to use the most efficient approach each time.

Reference

  • Python Crash Course (2nd Edition) : A Hands-On, Project-Based Introduction to Programming
  • Learning Python