学习python的第十二天之函数——函数用法

学习python的第十二天之函数——函数用法

def函数

Python 中的函数是一段组织好的、可重复使用的、用来实现单一或相关联功能的代码块。函数通过定义可以提高应用的模块性和代码的重复利用率。

  • 目的:减少代码冗余,使一些重复的代码定义在函数中

  • 场景:

    1. 代码重用‌:
      • 通过定义函数,可以避免重复编写相同的代码。只需调用函数即可重复使用其功能。
    2. 模块化设计‌:
      • 函数可以将代码分解为更小、更易于管理的模块。每个模块(函数)负责特定的任务,使得整体代码结构更加清晰。
    3. 抽象和封装‌:
      • 函数提供了一种抽象层,隐藏了具体的实现细节,只暴露必要的接口。这有助于保护代码并简化复杂系统的开发。
    4. 参数化‌:
      • 函数可以接受参数,使得它们能够处理不同的输入数据,从而增强了代码的灵活性和通用性。
    5. 递归‌:
      • 函数可以递归调用自身,这是解决某些问题(如树遍历、图搜索、分治算法等)的有效方法。
    6. 事件处理‌:
      • 在图形用户界面(GUI)编程或事件驱动的编程中,函数通常用作事件处理器,响应用户的输入或系统事件。
    7. 数据处理和分析‌:
      • 在数据科学、机器学习和统计分析中,函数用于执行数据清洗、转换、分析和可视化等任务。
    8. 文件操作‌:
      • 函数常用于封装文件读写操作,使得代码更加整洁,并减少错误发生的可能性。
    9. 网络编程‌:
      • 在网络应用中,函数用于处理网络连接、数据传输和协议解析等任务。
    10. API 调用和集成‌:
      • 函数常用于封装对外部API的调用,使得与第三方服务的集成更加简单和可靠。
    11. 测试和调试‌:
      • 在单元测试和集成测试中,函数是测试的基本单元。通过编写测试函数,可以验证代码的正确性和稳定性。
    12. 插件和扩展‌:
      • 在许多框架和系统中,函数用作插件或扩展点,允许开发者添加自定义功能。
    13. 回调函数‌:
      • 在异步编程或事件处理中,回调函数用于在特定事件发生时执行特定的代码。
    14. 装饰器‌:
      • Python 支持装饰器,这是一种特殊的函数,用于修改或扩展其他函数的行为。
    15. 配置和初始化‌:
      • 函数常用于程序的配置和初始化过程,如设置数据库连接、加载配置文件等。
  • 格式:

    def functionName(parameters):
        """
        函数的文档字符串(可选)
        """
        # 函数体
        # 这里执行功能实现
        return value  # 返回值(可选)
    
    • def 是定义函数的关键字。
    • functionName 是函数的名称,用于标识函数。
    • parameters 是函数可接受的参数,用于传递和接收数据。参数是可选的;函数也可以不接受任何参数。
    • 函数体部分是函数被调用时,Python 将执行的代码块。
    • return 语句用于从函数中返回一个值。如果函数没有返回值或者没有写 return 语句,函数默认返回 None

定义函数和调用

def add(a, b):
    """
    这个函数接收两个参数并返回它们的和
    """
    return a + b

# 调用函数
result = add(5, 3)  # 调用定义的add函数
print(result)  # 输出:8

函数的参数

Python 函数的参数可以是以下几种类型:int、str、float、bool、list、tuple、dict、set

例外,函数参数还可以传递函数!学习python的第十四天之函数——函数的作用域

  1. 必备参数‌:必须传递给函数,否则函数将无法调用。
  2. 关键字参数‌:使用关键字(即变量名)来指定传递给函数的值。
  3. 默认参数‌:为参数设置默认值,如果在调用函数时没有传递该参数,则使用默认值。
  4. 不定长参数‌:可以传递任意数量的参数,包括两种形式:*args(用于接收非关键字参数)和 **kwargs(用于接收关键字参数)。
    • *args (argument)是用来接收任意数量的位置参数的,这些参数会被自动组装成一个元组(tuple)。
    • **kwargs(keyword argument) 是用来接收任意数量的关键字参数的。这些参数会被自动组装成一个字典(dictionary),其中键是参数名,值是对应的参数值。
函数的形参和实参

函数是组织代码、实现特定功能的重要结构。函数定义时涉及的参数称为形参(形式参数),而函数调用时传入的参数则称为实参(实际参数)。

  • 形参(形式参数)

    形参是函数定义时使用的变量,它们代表了函数调用时将要接收的值。形参在函数体内部使用,以执行特定的操作。

  • 实参(实际参数)

    实参是函数调用时实际传递给函数的值。这些值被赋给形参,以供函数在内部使用。

# 位置参数和默认参数,message默认'Hello!'

def greet(name, message="Hello!"):
    print(f"{message}, {name}.")

greet("Alice")  # 输出:Hello!, Alice. name是位置参数,message是默认参数
greet("Bob", "Hi!")  # 输出:Hi!, Bob. name是位置参数,message是位置参数
# 不定长参数(位置参数和关键字参数)

def myFunction(*args, **kwargs):
    for arg in args:
        print(arg)
    for key, value in kwargs.items():
        print(f"{key} = {value}")

myFunction(1, 2, 3, name="Alice", age=25) # 1, 2, 3是位置参数;name="Alice", age=25是关键字参数
# 输出:
# 1
# 2
# 3
# name = Alice
# age = 25
# 函数作为参数
def func1():
    print('调用了函数func1')
    
def func2(f):
    f()
    
func2(func1)
# 输出: 调用了函数func1

拆包和装包

“拆包”(unpacking)和"装包"(packing)是处理序列(如列表、元组等)中元素的两种常用操作。这些操作在函数参数传递和返回值处理时特别有用。

  • 拆包(Unpacking)

拆包是指将序列中的元素提取出来,作为独立的变量使用。在函数调用时,可以使用星号 * 来拆包序列,将其元素作为位置参数传递给函数。

list1 = [1, 2, 3]
print(*list1)
# 输出: 1 2 3

dict1 = {1: 'one', 2: 'two', 3: 'three'}
print(*dict1)
# 输出: one two three

tuple1 = (1, 2, 3)
print(*tuple1)
# 输出: 1 2 3

set1 = {1, 2, 3}
print(*set1)
# 输出: 1 2 3

list2 = ['Bob', 25]
info_1 = 'My name is {} and I am {} years old.'.format(*list2)
print(info_1) #--> My name is Bob and I am 25 years old.

dict2 = {'name': 'Charlie', 'age': 35}
info_2 = 'My name is {name} and I am {age} years old.'.format(**dict2)
print(info_2) #--> My name is Charlie and I am 35 years old.
  • 拆包列表或元组作为函数参数
def greet(first_name, last_name):
    print(f"Hello, {first_name} {last_name}!")

names = ['John', 'Doe']
greet(*names)  # 输出:Hello, John Doe!

在这个例子中,names 列表被拆包成两个独立的参数 first_name 和 last_name,然后传递给 greet 函数。

  • 字典拆包作为函数参数(Python 3.5+)

    在 Python 3.5 及更高版本中,还可以使用双星号 ** 来拆包字典,将其键值对作为关键字参数传递给函数。

def print_info(name, age):
    print(f"Name: {name}, Age: {age}")

info = {'name': 'Alice', 'age': 30}
print_info(**info)  # 输出:Name: Alice, Age: 30
  • 装包(Packing)

装包是指将多个独立的变量组合成一个序列。在函数定义时,可以使用星号 * 来将位置参数装包成元组,或使用双星号 ** 来将关键字参数装包成字典。

  • 装包位置参数
def sum_all(*numbers):
    return sum(numbers)

print(sum_all(1, 2, 3, 4))  # 输出:10

在这个例子中,sum_all 函数接受任意数量的位置参数,并将它们装包成 numbers 元组。

  • 装包关键字参数
def print_kwargs(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_kwargs(city="New York", country="USA")
# 输出:
# city: New York
# country: USA

在这个例子中,print_kwargs 函数接受任意数量的关键字参数,并将它们装包成 kwargs 字典。

综合示例
示例1:
def func(a, b=0,):
    print(a)
    print(b)
    
func(1)  # a位置参数、b默认参数
# 输出:
# 1
# 0
    
func(1, 2)  # a位置参数、b位置参数
# 输出:
# 1
# 2

func(a=1, b=2)  # a关键字参数、b关键字参数
# 输出:
# 1
# 2

func(1, b=2)  # 在没有不定长参数,指定位置参数赋值时,指定赋值必须在最后,a位置参数,b关键字参数
# 输出:
# 1
# 2

# func(a=1, 2) 报错,关键字参数不能放在前面
# func(2, a=1) 报错,关键字参数a多重赋值
示例2:
def func(a, b=0, *c):
    print(a)
    print(b)
    print(c)
    
func(1, 2, 3, 4, 5, 6)  # 均为位置参数
# 输出: 
# 1
# 2
# (3, 4, 5, 6)

func(1)  # 位置参数,默认参数
# 或func(a=1) 
# 输出: 
# 1
# 0
# ()

func(1, 2) # 均为位置参数
# 输出: 
# 1
# 2
# ()

# func(a=1, 2, 3) 报错,关键字参数不能放在前面
# func(2, 3, a=1) 报错,关键字参数a多重赋值
# func(a=1, b=2, 3) 报错,关键字参数不能放在前面
#只要函数定义中出现不定长参数,则在使用关键字参数的时候就要慎重!
示例3:
# def func(*a, b): 报错,因为b无法拿到值,值全部都会给a
def func(*a, b=0): # 这样就没意义了
    print(a)
    print(b)
    
func(1, 2, 3)
# 输出:
# (1, 2, 3)
# 0

func(1, 2, 3, 4)
# 输出:
# (1, 2, 3, 4)
# 0

func(1, 2, 3, 4, b=5) # 可以通过关键字赋值给b
# 输出:
# (1, 2, 3, 4)
# 5
示例4:
def combine_and_print(*args, **kwargs):
    # 装包位置参数成元组
    print("Args:", args)
    # 装包关键字参数成字典
    print("Kwargs:", kwargs)

    # 拆包元组和字典
    first_arg, *rest_args = args
    print("First arg:", first_arg)
    print("Rest args:", rest_args)

    for key, value in kwargs.items():
        print(f"{key.upper()}: {value}")

# 调用函数并拆包列表和字典
data = [1, 2, 3]
meta = {'name': 'Bob', 'age': 25}
combine_and_print(*data, **meta)

# 输出:
# Args: (1, 2, 3)
# First arg: 1
# Rest args: [2, 3]
# NAME: Bob
# AGE: 25

在这个示例中,我们定义了一个函数 combine_and_print,它接受任意数量的位置参数和关键字参数。然后,我们演示了如何在函数内部拆包和装包这些参数。

函数在内存中的形式

函数是对象,和其他对象一样,它们在内存中占据空间。当你定义一个函数时,Python 会为这个函数创建一个函数对象,并将其存储在内存中。这个函数对象包含了函数的代码、名称、以及其他一些元数据(如默认参数值、注解等)。

  1. 函数定义‌:
    当你使用 def 关键字定义一个函数时,Python 会创建一个函数对象,并将其赋值给函数名。例如:

    def my_function():
        print("Hello, World!")
    

    在这里,my_function 是一个指向函数对象的引用。

  2. 函数对象的存储‌:
    函数对象存储在 Python 的堆内存中(与栈内存相对,栈内存通常用于存储局部变量和函数调用帧)。堆内存是用于存储动态分配的对象(如列表、字典、函数等)的区域。

  3. 函数名和引用‌:
    函数名(如 my_function)实际上是对函数对象的引用。你可以将这个函数对象赋值给其他变量,从而创建新的引用:

    another_reference = my_function
    another_reference()  # 输出 "Hello, World!"
    
  4. 函数对象的属性‌:
    函数对象有许多属性,如 __name__(函数名)、__code__(编译后的字节码)、__defaults__(默认参数值)、__globals__(全局命名空间)等。这些属性存储在函数对象的内部结构中。

  5. 垃圾回收‌:
    当没有引用指向一个函数对象时,该函数对象会成为垃圾回收的目标。Python 的垃圾回收机制会定期清理不再使用的对象,以释放内存。

  6. 闭包‌:
    闭包是一种特殊的函数,它可以捕获并记住其外部作用域中的变量。这些变量也被存储在闭包对象的内部结构中,使得闭包可以在其外部作用域不再存在的情况下仍然访问这些变量。

  7. 调用函数‌:
    当你调用一个函数时,Python 会在栈内存中创建一个新的帧(frame),用于存储局部变量、参数和其他与函数调用相关的信息。这个帧在函数调用结束时会被销毁。

函数传参中的传值和传址问题

学习python的第十三天之函数——函数传参中的传值和传址问题

匿名函数

匿名函数是指使用 lambda 关键字定义的简单函数。与普通的函数定义方式(使用 def 关键字)不同,匿名函数通常在一行内完成定义,并且不需要显式地指定函数名。这种函数特别适合实现一些简单的、临时的功能,避免了为这些小功能定义完整函数的繁琐。

语法:lambda 参数列表: 表达式

  • 参数列表‌:可以包含多个参数,参数之间用逗号分隔。
  • 表达式‌:只能有一个表达式,这个表达式的计算结果会被匿名函数返回。

两个数相加

add = lambda x, y: x + y
print(add(3, 5))  # 输出 8

计算两个数的乘积

multiply = lambda x, y: x * y
print(multiply(4, 5))  # 输出 20

判断一个数是否为偶数

is_even = lambda x: x % 2 == 0
print(is_even(4))  # 输出 True
print(is_even(3))  # 输出 False
使用场景

匿名函数常用于需要函数对象的地方,比如:

  • 作为函数参数‌:匿名函数可以直接作为其他函数的参数,特别是在需要传递简单函数逻辑时。

  • 排序、过滤等操作中‌:在 sorted()filter()map() 等内置函数中,匿名函数常用于指定排序规则、过滤条件或映射逻辑。

在内置函数中使用匿名函数

  1. 排序
list1 = [('李四', 52, 168), ('张三', 18, 183), ('王五', 36, 175)]

sorted_list1 = sorted(list1)
print(sorted_list1)  # 输出  [('张三', 18, 183), ('李四', 52, 168), ('王五', 36, 175)]

# 按年龄排序,升序
sorted_list2 = sorted(list1, key=lambda x: x[1])
print(sorted_list2)  # 输出  [('张三', 18, 183), ('王五', 36, 175), ('李四', 52, 168)]

# 按身高排序,降序
sorted_list3 = sorted(list1, key=lambda x: x[2], reverse=True)
print(sorted_list3)  # 输出  [('张三', 18, 183), ('王五', 36, 175), ('李四', 52, 168)]

# 按身高排序,降序(等效使用def定义函数)
def sorted_list(a):
    x = a[2]
    return x

sorted_list4 = sorted(list1, key=sorted_list, reverse=True)
print(sorted_list4)  # 输出  [('张三', 18, 183), ('王五', 36, 175), ('李四', 52, 168)]
  1. 过滤
even_numbers = filter(lambda x: x % 2 == 0, numbers)
print(list(even_numbers))  # 输出 [2, 4]
  1. 映射
squares = map(lambda x: x ** 2, numbers)
print(list(squares))  # 输出 [25, 4, 9, 1, 16]
注意事项
  • 匿名函数虽然简洁,但不易于阅读和维护,特别是对于复杂的逻辑。
  • 匿名函数没有函数名,因此不能直接通过函数名来调用它。通常,我们会将匿名函数赋值给一个变量,然后通过这个变量来调用它。
  • 由于匿名函数只能包含一个表达式,因此它不适合实现复杂的逻辑。对于复杂的逻辑,还是应该使用 def 关键字来定义完整的函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值