Python编程从入门到实践_第八章_函数

第八章:函数


  • 函数(function)是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
  • 要执行函数定义的特定任务,可调用该函数
  • 函数能提高应用的模块性,和代码的重复利用率。在程序中多次执行同一任务,可多次调用该函数,无需反复编写
  • python内置函数:print()
  • 自定义函数

8.1 定义函数

你可以定义一个由自己想要功能的函数,以下是简单的规则:

  • 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号()。
  • 任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数。
  • 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
  • 函数内容以冒号起始,并且缩进。
  • return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
def functionname( parameters ):
    "函数_文档字符串"
    function_suite
    return [expression]  
        
def greet_user():  #定义函数
    "显示简单的问候语"
    print("Hello!")
    
greet_user() # 调用函数     
Hello!

8.1.2 向函数传递信息(参数传递)

def greet_user(username):
    "显示简单的问候语"
    print(f"Hello, {username.title()}")
    
greet_user('jesse') # 函数调用
#greet_user()
Hello, Jesse

8.1.3 形参和实参

  • 形参(parameter):函数完成工作所需的参数 - username
  • 实参(argument):调用函数时传递给函数的参数 - ‘jesse’

8.2 传递实参

  • 函数定义中可以包含多个形参,因此函数调用时也可能包含多个实参
  • 传递实参的方法:
    • 位置实参
    • 关键字实参
    • 列表
    • 字典

8.2.1 位置实参

  • 基于实参的位置顺序 将函数调用中的实参关联到函数定义中的形参
  • 顺序不对容易发生混淆

任务: 定义一个显示宠物信息的函数

def describe_pet(animal_type, pet_name):
    "显示宠物信息"
    print(f"\nI have a {animal_type}." )
    print(f"My {animal_type}'name is {pet_name.title()}.")
    
describe_pet('hamster','harry')
I have a hamster.
My hamster'name is Harry.

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

8.2.2 关键字实参

  • 传递给函数的“名称-值对”,直接在实参中将名称和值关联起来,不会混淆
  • 无需考虑函数调用中实参顺序,还清楚的指出函数调用中各个值的用途
def describe_pet(animal_type, pet_name):
    "显示宠物信息"
    print(f"\nI have a {animal_type}." )
    print(f"My {animal_type}'name is {pet_name.title()}.")
    
describe_pet(animal_type= 'hamster', pet_name='harry')
I have a hamster.
My hamster'name is Harry.

def describe_pet(animal_type, pet_name):
    "显示宠物信息"
    print(f"\nI have a {animal_type}." )
    print(f"My {animal_type}'name is {pet_name.title()}.")
    
describe_pet( pet_name='harry',animal_type= 'hamster')
I have a hamster.
My hamster'name is Harry.

8.2.3 默认值

  • 编写函数时,可给每个形参指定默认值(default value)
  • 调用函数中给形参提供了实参,Python将使用指定的实参值,否则将使用形参的默认值

任务: 将形参animal_type的默认值设置为‘dog’

# 默认值
def describe_pet(pet_name, animal_type= 'dog'):
    "显示宠物信息"
    print(f"\nI have a {animal_type}." )
    print(f"My {animal_type}'name is {pet_name.title()}.")
    
describe_pet(pet_name='willie')
I have a dog.
My dog'name is Willie.
# 忽略默认值
def describe_pet(pet_name, animal_type= 'dog'):
    "显示宠物信息"
    print(f"\nI have a {animal_type}." )
    print(f"My {animal_type}'name is {pet_name.title()}.")
    
describe_pet( pet_name='harry',animal_type= 'hamster')
I have a hamster.
My hamster'name is Harry.

8.2.4 等效的函数调用

  • 混合使用位置实参,关键字实参和默认值
  • 使用哪种调用方式无关紧要
def describe_pet(pet_name, animal_type= 'dog'):
    "显示宠物信息"
    print(f"\nI have a {animal_type}." )
    print(f"My {animal_type}'name is {pet_name.title()}.")

#  animal_type 为默认值 'dog'  
describe_pet('willie') #位置实参
describe_pet(pet_name='willie') #关键字实参
I have a dog.
My dog'name is Willie.

I have a dog.
My dog'name is Willie.
def describe_pet(pet_name, animal_type= 'dog'):
    "显示宠物信息"
    print(f"\nI have a {animal_type}." )
    print(f"My {animal_type}'name is {pet_name.title()}.")

#  animal_type 不为默认值       
describe_pet('harry', 'hamster') #位置实参
describe_pet( pet_name='harry',animal_type= 'hamster') #关键字实参
describe_pet(animal_type= 'hamster', pet_name='harry') #关键字实参
I have a hamster.
My hamster'name is Harry.

I have a hamster.
My hamster'name is Harry.

I have a hamster.
My hamster'name is Harry.

8.2.5 避免实参错误

def describe_pet(pet_name, animal_type):
    "显示宠物信息"
    print(f"\nI have a {animal_type}." )
    print(f"My {animal_type}'name is {pet_name.title()}.")
    
describe_pet()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-15-42ca51a5424d> in <module>
      4     print(f"My {animal_type}'name is {pet_name.title()}.")
      5 
----> 6 describe_pet()

TypeError: describe_pet() missing 2 required positional arguments: 'pet_name' and 'animal_type'

8.3 返回值

  • 函数并非总是直接显示输出,还可以处理一些数据,并返回一个或一组值
  • 函数返回的值称作返回值(return statement )
  • 在函数中,可使用return语句将值返回到调用函数的代码行
  • 返回值可简化主程序

8.3.1 返回简单值

任务: 接受名和姓并返回整洁的姓名

def get_formatted_name(first_name, last_name):
    "返回整洁的姓名"
    full_name = f"{first_name} {last_name}"
    return full_name.title()

musician = get_formatted_name('jimi','hendix')
print(musician)
Jimi Hendix

8.3.2 让实参变成可选的

  • 让实参变成可选的,调用函数时只需在必要是提供额外的信息
  • 可使用默认值让实参变成可选的
def get_formatted_name(first_name,middle_name, last_name):
    "返回整洁的姓名"
    full_name = f"{first_name} {middle_name} {last_name}"
    return full_name.title()

musician = get_formatted_name('jimi','lee', 'hendix')
print(musician)
Jimi Lee Hendix
# 并非所有的人都有中间名,若只提供名和姓,调用函数将不能正确运行
# 需将中间名变成可选的
# 给middle_name 指定一个空字符串,并在用户不提供中间名是不使用该形参
def get_formatted_name(first_name, last_name, middle_name=''):
    "返回整洁的姓名"
    if middle_name:
        full_name = f"{first_name} {middle_name} {last_name}"
    else:
        full_name = f"{first_name} {last_name}"
    return full_name.title()

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

musician = get_formatted_name('jimi', 'hendix','lee')
print(musician)
Jimi Hendix
Jimi Lee Hendix

8.3.3 返回字典

  • 函数可以返回任何数据类型,包括列表和字典等复杂数据结构

任务: 接受姓名的组成部分,并返回一个表示人的字典

def biuld_person(first_name, last_name):
    "返回一个字典,包含有关一个人的信息"
    person = {'first': first_name, 'last': last_name}
    return person

musician = biuld_person('jimi', 'hendix')
print(musician)
Jimi Hendix
def biuld_person(first_name, last_name, age = None):
    "返回一个字典,包含有关一个人的信息"
    person = {'first': first_name, 'last': last_name,}
    if age:
        person['age'] = age
    return person

musician = biuld_person('jimi', 'hendix', age = 27)
print(musician)
{'first': 'jimi', 'last': 'hendix', 'age': 27}

8.3.4 结合使用函数和while循环

任务: 结合使用函数 get_formatted_name()和while循环,和用户打招呼

def get_formatted_name(first_name, last_name):
    "返回整洁的姓名"
    full_name = f"{first_name} {last_name}"
    return full_name.title()

while True:
    print("\nPlease tell me your name:")
    f_name = input("First name: ")
    l_name = input("Last name: ")
    
    formatted_name = get_formatted_name(f_name, l_name)
    print(f"\nHello, {formatted_name}!")
# 无限循环,无法退出
    
def get_formatted_name(first_name, last_name):
    "返回整洁的姓名"
    full_name = f"{first_name} {last_name}"
    return full_name.title()

while True:
    print("\nPlease tell me your name:")
    print("(enter 'q' at any time to quit)")
    
    f_name = input("First name: ")
    if f_name == 'q':
        break
    
    l_name = input("Last name: ")
    if l_name == 'q':
        break
        
    formatted_name = get_formatted_name(f_name, l_name)
    print(f"\nHello, {formatted_name}!")
Please tell me your name:
(enter 'q' at any time to quit)
First name: eric
Last name: matthes

Hello, Eric Matthes!

Please tell me your name:
(enter 'q' at any time to quit)
First name: q

8.4 传递列表

  • 将列表传递给函数后,函数就能直接访问其内容

任务: 将包含名字的列表传递给一个名为greet_users()的函数,该函数问候列表中的每个人

def greet_users(names):
    "向列表中用户发出简单问候"
    for name in names:
        msg = f"Hello, {name.title()}!"
        print(msg)
        
usernames = ['hannah','ty','margot']

greet_users(usernames)
Hello, Hannah!
Hello, Ty!
Hello, Margot!

8.4.1 在函数中修改列表

  • 将列表传递给函数后,函数可以对其修改
  • 在函数中对列表的修改是永久性的

任务: 将打印的设计存储在一个列表中,打印后将其移动到另一个列表中

unprinted_designs = ['phone case', 'robot pendant', 'dodecahedron']
completed_models = []

while unprinted_designs:
    current_design = unprinted_designs.pop()
    print(f"Printing model: {current_design}")
    completed_models.append(current_design)
    
print("\nThe following models have been printed:")
for completed_model in completed_models:
    print(completed_model)
Printing model: dodecahedron
Printing model: robot pendant
Printing model: phone case

The following models have been printed:
dodecahedron
robot pendant
phone case
def print_models(unprinted_designs, completed_models):
    while unprinted_designs:
        current_design = unprinted_designs.pop()
        print(f"Printing model: {current_design}")
        completed_models.append(current_design)
        
def show_completed_models(completed_models):
    print("\nThe following models have been printed:")
    for completed_model in completed_models:
        print(completed_model)
        
unprinted_designs = ['phone case', 'robot pendant', 'dodecahedron']
completed_models = []

print_models(unprinted_designs, completed_models)
show_completed_models(completed_models)
Printing model: dodecahedron
Printing model: robot pendant
Printing model: phone case

The following models have been printed:
dodecahedron
robot pendant
phone case

8.4.2 禁止函数修改列表

  • 将列表的副本传递给函数,函数所做的修改只影响副本,原件不受影响
  • 传递列表副本——function_name(list_name[:])
  • 传递列表——function_name(list_name)

8.5 传递任意数量的实参

  • 预先不知道函数要接受多少实参
  • Python允许函数从调用语句中收集任意数量的实参
  • *arg

任务: 制作披萨需要接受很多配料,但无法预先确定顾客要多少种配料

def make_pizza(*toppings):
    "打印顾客所有配料"
    print(toppings)
    
make_pizza('pepperoni')
make_pizza('pepperoni','mushrooms','extra cheese')
('pepperoni',)
('pepperoni', 'mushrooms', 'extra cheese')

8.5.1 结合使用位置实参和任意数量实参

  • 要让函数接受不同类型的实参,需在函数定义中将接纳任意数量实参的形参放在最后
  • Python 先匹配位置实参和关键字实参,在将余下的实参都收纳到最后一个形参中
def make_pizza(size, *toppings):
    "打印顾客所有配料"
    print(f"\nMaking a {size}-inch pizza with the following toppings:")
    for topping in toppings:
        print(f"-{topping}")
    
make_pizza(16,'pepperoni')
make_pizza(12,'pepperoni','mushrooms','extra cheese')
Making a 16-inch pizza with the following toppings:
-pepperoni

Making a 12-inch pizza with the following toppings:
-pepperoni
-mushrooms
-extra cheese

8.5.2 使用任意数量的关键字实参

  • 需要接受任意数量的实参,但预先不知道传递给函数的是什么样的信息
  • 将函数编写为能够接受任意数量的键值对——调用语句提供多少就接受多少
  • **kwargs

任务: 创建用户简介,知道将接受有关用户的信息,但不确定会是什么样的信息

def build_profile(first, last, **use_info):
    "创建一个字典,其中包含我们知道的有关用户的一切"
    use_info['first_name'] = first
    use_info['last_name'] = last
    return use_info

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

print(user_profile)
{'location': 'princeton', 'field': 'physics', 'first_name': 'albert', 'last_name': 'einstein'}

8.6 将函数存储在模块(Module)中

  • 使用函数的好处是可以将代码块和主程序分离
  • 将函数存储在称为模块(Module)的独立文件中,再将模块导入到主程序中
  • 通过将函数存储在独立的文件中,可以隐藏程序代码的细节,将重点放在程序的高层逻辑上
  • 模块是扩展名为.py的文件,包含要导入到程序中的代码
  • import 语句允许在当前运行的程序文件中使用模块中的代码

8.6.1 导入整个模块

  • import module_name
import pizza

#module_name.function_name()
pizza.make_pizza(16,'pepperoni')
pizza.make_pizza(12,'pepperoni','mushrooms','extra cheese')
Making a 16-inch pizza with the following toppings:
- pepperoni

Making a 12-inch pizza with the following toppings:
- pepperoni
- mushrooms
- extra cheese

8.6.2 导入特定函数

  • from module_name import function_1, function_1
from pizza import make_pizza

make_pizza(16,'pepperoni')
make_pizza(12,'pepperoni','mushrooms','extra cheese')
Making a 16-inch pizza with the following toppings:
- pepperoni

Making a 12-inch pizza with the following toppings:
- pepperoni
- mushrooms
- extra cheese

8.6.3 使用as给函数指定别名

  • from module_name import function_name as fn
from pizza import make_pizza as mp

mp(16,'pepperoni')
mp(12,'pepperoni','mushrooms','extra cheese')
Making a 16-inch pizza with the following toppings:
- pepperoni

Making a 12-inch pizza with the following toppings:
- pepperoni
- mushrooms
- extra cheese

8.6.4 使用as给模块指定别名

  • import module_name as mn
import pizza as p

p.make_pizza(16,'pepperoni')
p.make_pizza(12,'pepperoni','mushrooms','extra cheese')
Making a 16-inch pizza with the following toppings:
- pepperoni

Making a 12-inch pizza with the following toppings:
- pepperoni
- mushrooms
- extra cheese

8.6.5 导入模块中所有函数

  • from module_name import *
from pizza import *

make_pizza(16,'pepperoni')
make_pizza(12,'pepperoni','mushrooms','extra cheese')
Making a 16-inch pizza with the following toppings:
- pepperoni

Making a 12-inch pizza with the following toppings:
- pepperoni
- mushrooms
- extra cheese

8.7 函数编写指南

  1. 给函数指定描述性名称,且只在其中是用小写字母和下划线

  2. 每个函数都应包含简要的阐述其功能的注释,该注释应紧跟在函数定义后面,且采用文档字符串格式

  3. 给形参指定默认值时,等号两边不要有空格,对于函数调用中的关键字实参,也应遵循这种规定

  4. 如果形参过多,导致函数定义的长度超过了79字符,可在函数定义中按输入左括号后按回车键,并在下一行按两次Tab键,从而将形参列表和只缩进一层的函数体区分开来,如下

def function_name(
        parameter_0,parameter_1,parameter_2,
        parameter_3,parameter_4,parameter_5):
    function_body...
  1. 如果程序或者模块包含多个函数,可使用两个空行将相邻的函数分开,这让更容易知道前一个函数在什么地方结束,下一个函数从什么地方开始
  2. 所有的import语句都应放在文件的开头,唯一例外的情形是,在文件的开头使用了注释来描述整个程序

总结

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值