第8章 函数


提示:

1. 8.函数

8.1 定义函数

函数的定义是指创建一个具有特定功能的代码块。在大多数编程语言(如Python)中,定义函数的基本语法如下:

def 函数名(参数):
    函数体(实现功能的代码)
    return 返回值(可选)

例如,定义一个计算两数之和的函数:

def add(a, b):
    result = a + b
    return result
8.1.1 向函数传递信息

函数可以通过参数接收外部传递的信息,从而实现更灵活的功能。参数就像函数的“输入”,让函数可以根据不同的输入执行不同的操作。
例如,上述add函数中的ab就是接收外部信息的参数,调用时可以传入不同的数值:add(3, 5)会计算3+5,add(10, 20)会计算10+20。

8.1.2 实参和形参
  • 形参(形式参数):函数定义时括号中声明的参数,是函数内部用于接收信息的“占位符”。例如add(a, b)中的ab就是形参。
  • 实参(实际参数):函数调用时传入的具体值,用于填充形参。例如add(3, 5)中的35就是实参。
    简单来说,形参是“函数定义时写的参数名”,实参是“函数调用时传的具体值”。

8.2 传递实参

调用函数时,需要将实参传递给形参,传递方式有多种,目的是确保实参与形参正确匹配。

8.2.1 位置实参

最常见的传递方式,实参的顺序与形参的顺序完全一致。例如:

def describe_pet(animal_type, pet_name):
    print(f"I have a {animal_type} named {pet_name}.")

# 位置实参:第一个实参对应第一个形参,第二个对应第二个
describe_pet("dog", "Buddy")  # 输出:I have a dog named Buddy.

如果顺序错误,结果会不符合预期:describe_pet("Buddy", "dog")会输出“I have a Buddy named dog.”,显然不合理。

8.2.2 关键字实参

通过“形参名=实参值”的形式传递,不需要考虑顺序,直接指定实参对应的形参。例如:

# 关键字实参:明确指定实参对应的形参,顺序无关
describe_pet(animal_type="cat", pet_name="Luna")
describe_pet(pet_name="Momo", animal_type="rabbit")  # 顺序颠倒也不影响

两种方式的输出都是“I have a cat named Luna.”和“I have a rabbit named Momo.”。

8.2.3 默认值

可以在定义函数时给形参指定默认值,调用时如果不传递该参数,则使用默认值。例如:

# 给animal_type设置默认值"dog"
def describe_pet(pet_name, animal_type="dog"):
    print(f"I have a {animal_type} named {pet_name}.")

# 不传递animal_type,使用默认值"dog"
describe_pet("Buddy")  # 输出:I have a dog named Buddy.
# 传递animal_type,覆盖默认值
describe_pet("Luna", "cat")  # 输出:I have a cat named Luna.

注意设置默认值的形参通常放在无默认值形参的后面。

8.2.4 等效的函数调用

通过位置实参、关键字实参和默认值的组合,可以用多种方式调用同一个函数,只要实参与形参能正确匹配,结果就是等效的。例如对于上述describe_pet函数:

describe_pet("Buddy")  # 位置实参(仅传pet_name,animal_type用默认值)
describe_pet(pet_name="Buddy")  # 关键字实参(仅传pet_name)
describe_pet("Momo", "rabbit")  # 位置实参(传两个参数)
describe_pet(animal_type="rabbit", pet_name="Momo")  # 关键字实参(传两个参数)

以上调用的效果完全一致。

8.2.5 避免实参错误

如果传递的实参数量与形参不匹配,或无法正确匹配,会导致错误。例如:

# 形参需要2个,但只传1个实参,会报错
describe_pet("Buddy")  # 如果函数没有默认值,这里会报错:缺少1个位置实参

调用时需确保实参数量、类型与形参匹配。

8.3 返回值

函数执行完成后,可以通过return语句将结果返回给调用者,这个结果就是返回值。

8.3.1 返回简单的值

最基础的返回方式,直接返回一个数值、字符串等。例如:

def get_full_name(first_name, last_name):
    full_name = f"{first_name} {last_name}"
    return full_name  # 返回拼接后的字符串

name = get_full_name("Alice", "Smith")
print(name)  # 输出:Alice Smith
8.3.2 让实参变成可选的

通过给形参设置默认值(如空字符串),让实参可选。例如,处理中间名:

def get_full_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

print(get_full_name("John", "Doe"))  # 输出:John Doe(中间名可选,未传递)
print(get_full_name("John", "Doe", "Michael"))  # 输出:John Michael Doe(传递中间名)
8.3.3 返回字典

函数可以返回复杂数据类型,如字典,用于封装多个相关值。例如:

def build_person(name, age):
    person = {"name": name, "age": age}
    return person  # 返回字典

person = build_person("Bob", 30)
print(person)  # 输出:{'name': 'Bob', 'age': 30}
8.3.4 结合使用函数和 while 循环

函数可以与循环结合,实现重复调用函数的功能。例如,不断接收用户输入并处理:
在 Python 中,while True 是一个 无限循环 的写法,意思是:让循环体里的代码 一直重复执行,直到遇到 break 语句才会停止。
详细解释:
while 是 Python 的循环关键字,后面跟一个 条件表达式。当条件为 True 时,就会执行循环体里的代码;条件为 False 时,循环结束。
True 是 Python 中的布尔值,表示 “真”。所以 while True 就意味着 条件永远为真,循环会无限执行下去(除非用 break 强制退出)。

def greet_user(name):
    return f"Hello, {name}!"

while True:
    print("\nPlease tell me your name (enter 'quit' to stop):")
    name = input()
    if name == "quit":
        break
    print(greet_user(name))  # 循环中调用函数

8.4 传递列表

函数可以接收列表作为实参,便于批量处理数据。

8.4.1 在函数中修改列表

函数接收列表后,可以直接修改列表中的元素,且修改会影响原列表(因为列表是“可变对象”)。例如:

def process_messages(messages, sent_messages):
    while messages:
        current_message = messages.pop()  # 从messages中取出最后一条消息
        print(f"Sending: {current_message}")
        sent_messages.append(current_message)  # 添加到已发送列表

messages = ["Hello!", "How are you?", "Goodbye!"]
sent_messages = []

process_messages(messages, sent_messages)
print("Original messages:", messages)  # 输出:Original messages: [](原列表被修改)
print("Sent messages:", sent_messages)  # 输出:Sent messages: ['Goodbye!', 'How are you?', 'Hello!']
8.4.2 禁止函数修改列表

如果希望函数不修改原列表,可以传递列表的副本(通过列表名[:]创建)。例如:

# 传递messages的副本,原列表不会被修改
process_messages(messages[:], sent_messages)
print("Original messages:", messages)  # 输出:Original messages: ["Hello!", "How are you?", "Goodbye!"](原列表未变)

8.5 传递任意数量的实参

当不确定需要传递多少个实参时,可以使用“任意数量的实参”功能。

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

在形参前加*,表示接收任意数量的位置实参,这些实参会被封装成一个元组。例如:

# *toppings接收任意数量的实参,封装成元组
def make_pizza(size, *toppings):
    print(f"Making a {size}-inch pizza with the following toppings:")
    for topping in toppings:
        print(f"- {topping}")

# 调用时,第一个实参是size(位置实参),后面的都是toppings(任意数量)
make_pizza(12, "pepperoni", "mushrooms")
make_pizza(16, "cheese", "onions", "sausage", "bell peppers")
8.5.2 使用任意数量的关键字实参

在形参前加**,表示接收任意数量的关键字实参,这些实参会被封装成一个字典。例如:

# **user_info接收任意数量的关键字实参,封装成字典
def build_profile(first, last,** user_info):
    profile = {"first_name": first, "last_name": last}
    ## 6.3.1 遍历所有的键值对-items()方法
	# 使用items()方法可返回字典中所有键值对的视图,配合for循环遍历:
    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)
# 输出:{'first_name': 'albert', 'last_name': 'einstein', 'location': 'princeton', 'field': 'physics'}

8.6 将函数存储在模块中

为了代码的整洁和复用,可以将函数存储在独立的文件(称为“模块”)中,然后在其他程序中导入使用。

8.6.1 导入整个模块

模块是一个.py文件,例如my_functions.py中定义了addsubtract函数。导入整个模块的语法:

import my_functions  # 导入整个模块

# 使用模块中的函数:模块名.函数名()
result1 = my_functions.add(3, 5)
result2 = my_functions.subtract(10, 4)
8.6.2 导入特定的函数

只导入模块中需要的函数,语法:

from my_functions import add, subtract  # 只导入add和subtract

# 直接使用函数名,无需加模块名
result1 = add(3, 5)
result2 = subtract(10, 4)
8.6.3 使用 as 给函数指定别名

如果函数名较长或与现有名称冲突,可以用as指定别名:

from my_functions import add as a  # 给add起别名a

result = a(3, 5)  # 用别名调用
8.6.4 使用 as 给模块指定别名

给模块起简短的别名,方便调用:

import my_functions as mf  # 给模块起别名mf

result = mf.add(3, 5)  # 用模块别名调用函数
8.6.5 导入模块中的所有函数

使用*导入模块中所有函数(不推荐,可能导致名称冲突):

from my_functions import *  # 导入所有函数

result1 = add(3, 5)
result2 = subtract(10, 4)

8.7 函数编写指南

为了写出规范、易读的函数,通常需要遵循以下指南:

  • 函数名应使用小写字母,多个单词用下划线连接(如get_full_name),清晰描述函数功能。
  • 形参名也应简洁明了,如pet_namepn更易理解。
  • 函数定义后,建议添加文档字符串(docstring),用"""包裹,说明函数功能、参数、返回值等。例如:
    def add(a, b):
        """计算两个数的和并返回结果。
        
        参数:
            a:第一个加数
            b:第二个加数
        返回:
            两数之和
        """
        return a + b
    
  • 函数功能应单一,一个函数只做一件事,便于复用和维护。
  • 避免在函数中使用全局变量,尽量通过参数传递数据,通过返回值输出结果。

8.8 小结

  • 函数通过def定义,用于封装可重复使用的代码。
  • 形参是函数定义时的占位符,实参是调用时传递的具体值。
  • 实参传递方式包括位置实参、关键字实参,可结合默认值使用。
  • 函数可以返回值(简单值、字典等),也可以处理列表等数据结构。
  • 支持传递任意数量的实参(*接收位置实参,**接收关键字实参)。
  • 函数可存储在模块中,通过导入实现代码复用。
  • 遵循编写指南能提高函数的可读性和可维护性。

函数是编程中实现代码模块化、复用和抽象的重要工具,掌握函数的使用是学好编程的关键一步。


总结

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值