【python篇】关于函数当中的那些事,轻松拿捏

2024-09-23 20:14:13 浏览数 (2)

函数的基础

函数的定义:使用 def 关键字定义一个函数,以及函数的基本结构,包括函数名、参数列表、函数体和返回值。

代码语言:javascript复制
# 定义一个简单的函数,它接受两个参数并返回它们的和
def add_numbers(a, b):
    return a   b

# 调用函数并打印结果
result = add_numbers(3, 5)
print(result)  # 输出: 8

函数的参数

函数当中有形式参数和实际参数,分别简称形参和实参是非常重要的概念 下面举行一些例子来详细说明

1.位置参数(Positional Arguments)

代码语言:javascript复制
def greet(name, age):
    print(f"Hello, my name is {name} and I am {age} years old.")

# 调用函数
greet("Alice", 25)
#	Hello, my name is Alice and I am 25 years old.

2. 关键字参数(Keyword Arguments)

代码语言:javascript复制
def greet(name, age):
    print(f"Hello, my name is {name} and I am {age} years old.")

# 使用关键字参数调用函数
greet(age=25, name="Bob")
#	Hello, my name is Bob and I am 25 years old.

3. 默认参数(Default Arguments)

代码语言:javascript复制
def greet(name="John", age=30):
    print(f"Hello, my name is {name} and I am {age} years old.")

# 调用函数,使用默认参数
greet()
greet("Alice")		#函数实参有默认值即使用默认值
greet("Alice", 25)
#	Hello, my name is John and I am 30 years old.
#	Hello, my name is Alice and I am 30 years old.
#	Hello, my name is Alice and I am 25 years old.

4. 可变长度参数 *args

args 用于接受任意数量的位置参数。它会将传入的多个参数打包成一个元组。*

代码语言:javascript复制
def print_numbers(*args):
    for num in args:
        print(num)

# 传递多个实参
print_numbers(1, 2, 3, 4, 5)

输出:

代码语言:javascript复制
1
2
3
4
5

5. 可变长度关键字参数 **kwargs

kwargs 用于接受任意数量的关键字参数。它会将传入的多个关键字参数打包成一个字典

代码语言:javascript复制
def print_info(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

# 传递多个关键字参数
print_info(name="Alice", age=25, city="New York")

输出:

代码语言:javascript复制
name: Alice
age: 25
city: New York

6. 强制关键字参数(Keyword-Only Arguments)

在 Python 3 中,可以强制要求某些参数必须通过关键字来传递,而不能通过位置。

代码语言:javascript复制
def describe_pet(pet_name, *, pet_type="dog"):
    print(f"I have a {pet_type} named {pet_name}.")

# 通过关键字传递参数
describe_pet("Max", pet_type="cat")

# 不传递 pet_type,使用默认值
describe_pet("Buddy")

输出:

代码语言:javascript复制
I have a cat named Max.
I have a dog named Buddy.

函数的作用域

局部变量和全局变量:

代码语言:javascript复制
x = 10  # 这是一个全局变量

def example():
    x = 5  # 这是一个局部变量
    print(f"Inside the function, x = {x}")

example()  # 输出: Inside the function, x = 5
print(f"Outside the function, x = {x}")  # 输出: Outside the function, x = 10

#在 example 函数内部定义的 x 是局部变量,它只在函数内部有效,不会影响全局变量 x。因此函数内外的 x 值不同。

global关键字:

global 的定义与作用: 通常情况下,如果你在函数内部定义一个变量,该变量是局部变量,仅在函数内部可见。如果在函数内部需要修改全局变量,必须使用 global 关键字进行声明。 作用: 声明全局变量:global 允许在局部作用域内声明并修改外部作用域(全局作用域)中的变量。 防止局部变量覆盖全局变量:如果没有 global 声明,当你在函数内部赋值时,Python 会默认创建一个新的局部变量,而不是修改全局变量。

代码语言:javascript复制
x = 10  # 全局变量

def modify_global():
    global x
    x = 20  # 修改全局变量
    print(f"Inside the function, x = {x}")

modify_global()  # 输出: Inside the function, x = 20
print(f"Outside the function, x = {x}")  # 输出: Outside the function, x = 20

#使用 global 关键字可以在函数内部修改全局变量。这个例子中,函数内部将全局变量 x 修改为 20,所以函数外的 x 也被改变了。

global 的常见用途 1.计数器或全局状态的维护:在程序中,有时需要一个全局计数器或状态变量,global 可以帮助修改它们的值。 2.全局配置或设置的更新:如果程序中有全局的设置或配置变量,在需要修改这些配置时,可以使用 global。 3.跨函数共享数据:有时候多个函数需要共享某些数据,可以通过 global 声明全局变量来实现。 global 的局限性 尽管 global 可以让函数内部修改全局变量,但在大型程序中滥用全局变量可能会带来以下问题: 1.代码可读性降低:过多的全局变量会使代码难以维护,难以理解哪些函数依赖于哪些全局变量。 2.调试困难:由于全局变量可以在多个地方被修改,跟踪它的值变化可能变得复杂。 模块化难度增加:全局变量往往与模块化设计相冲突,影响代码的复用性和可测试性。

因此,尽量减少使用全局变量。更好的方法是使用函数参数、返回值或类的属性来管理状态。

nonlocal关键字:

nonlocal定义与作用: nonlocal 关键字用于声明一个变量是来自于外层的非全局作用域(通常是闭包中的外部函数)。nonlocal 允许在嵌套函数中修改外层函数中的局部变量,而不是全局变量或当前局部变量。 作用 修改外层函数的局部变量:nonlocal 可以让嵌套函数中的变量绑定到外层函数的局部变量上,避免创建新的局部变量。 闭包的实现:在闭包中,nonlocal 允许嵌套函数修改封闭函数中的变量,从而实现更复杂的功能。

代码语言:javascript复制
def outer_function():
    x = 10
    
    def inner_function():
        nonlocal x
        x = 20
        print(f"Inside the inner function, x = {x}")
    
    inner_function()
    print(f"Inside the outer function, x = {x}")

outer_function()

#nonlocal 用于在嵌套函数中引用外层函数的变量,而不是全局变量。在这个例子中,inner_function 修改了 outer_function 中的 x 值。

nonlocal 常见用途 闭包的实现:nonlocal 常用于闭包中修改外层函数的局部变量,闭包可以记住外层函数的状态,而 nonlocal 可以允许修改这些状态。 nonlocal 的局限性 nonlocal 只能用于嵌套函数中,且仅能修改直接外层函数中的局部变量。它不能用于访问全局变量或更高层的嵌套作用域。 如果没有外层函数中的局部变量,使用 nonlocal 会导致 SyntaxError 错误。

nonlocal 和 global 的区别

global 用于声明一个变量是全局作用域中的变量,允许在函数内部修改全局变量。

nonlocal 用于声明一个变量是外层非全局作用域中的变量,允许在嵌套函数中修改外层函数的局部变量。

函数的进阶

1.函数嵌套(Nested Functions)

Python 支持在一个函数内部定义另一个函数,这被称为嵌套函数。内部函数可以访问外部函数的变量(闭包的概念)。

代码语言:javascript复制
def outer_function(text):
    def inner_function():
        print(text)  # 内部函数可以访问外部函数的变量
    inner_function()

# 调用外部函数
outer_function("Hello from outer function!")
# Hello from outer function!

2.闭包(Closures)

闭包是指内部函数记住并访问它们被定义时的外部作用域的变量,即使外部函数已经返回了。 闭包的三个条件 1.必须有一个嵌套函数:闭包必须包含一个内嵌函数。 2.内嵌函数必须引用外部函数中的变量:这个引用的变量通常是外层函数中的局部变量。 3.外层函数必须返回内嵌函数:返回的内嵌函数可以在外部被调用,且能够访问外层函数的变量。

代码语言:javascript复制
def outer_function(text):
    def inner_function():
        print(text)
    return inner_function

# 调用外部函数,并将返回的函数赋值给变量
my_closure = outer_function("Hello, World!")

# 调用闭包函数
my_closure()  # 输出: Hello, World!

闭包的应用场景 闭包通常用于需要保持某些状态的场景,特别是当你希望将某些状态与一个函数关联,而又不希望使用全局变量时。

示例:计数器

代码语言:javascript复制
def make_counter():
    count = 0  # 闭包中的变量

    def counter():
        nonlocal count
        count  = 1
        return count
    
    return counter

# 创建一个计数器实例
counter_a = make_counter()

print(counter_a())  # 输出: 1
print(counter_a())  # 输出: 2
print(counter_a())  # 输出: 3

# 创建另一个计数器实例
counter_b = make_counter()

print(counter_b())  # 输出: 1
print(counter_b())  # 输出: 2
# make_counter 函数创建了一个闭包,其中的变量 count 是内嵌函数 counter 的状态。
# 每次调用 counter() 时,count 都会增加1,并返回当前的计数。
# 你可以创建多个计数器,每个计数器都有独立的状态,不会互相影响。

闭包的核心:在函数外部可以访问函数内部的局部变量。这使得闭包在保持状态、实现工厂函数(如上面的计数器)、以及创建装饰器时非常有用。

3.装饰器(Decorator)

装饰器的基本概念

一个简单的装饰器结构通常是这样的: 定义一个装饰器函数,它接收一个函数作为参数。 在装饰器函数内部定义一个嵌套函数,这个嵌套函数将在原函数调用时被调用。 嵌套函数可以在执行原函数前后添加新的功能。 装饰器返回嵌套函数,从而替代原函数。

示例:

代码语言:javascript复制
def simple_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

@simple_decorator
def say_hello():
    print("Hello!")

# 调用装饰过的函数
say_hello()

解释: simple_decorator 是装饰器函数,它接收一个函数 func 作为参数。 wrapper 是在装饰器内部定义的嵌套函数,它在调用 func() 之前和之后分别打印一条消息。 @simple_decorator 语法糖用来应用装饰器,它等价于 say_hello = simple_decorator(say_hello)。 当你调用 say_hello() 时,实际执行的是 wrapper 函数,它先打印“Something is happening before the function is called.”,然后调用 say_hello 函数,最后打印“Something is happening after the function is called.”。

装饰器处理带参数的函数

如果被装饰的函数带有参数,装饰器也需要处理这些参数。我们可以修改 wrapper 函数来接受任意数量的参数和关键字参数。

代码语言:javascript复制
def decorator_with_arguments(func):
    def wrapper(*args, **kwargs):
        print(f"Arguments were: {args}, {kwargs}")
        return func(*args, **kwargs)
    return wrapper

@decorator_with_arguments
def greet(name, greeting="Hello"):
    print(f"{greeting}, {name}!")

# 调用装饰过的函数
greet("Alice")
greet("Bob", greeting="Good morning")

解释: wrapper(*args, **kwargs) 能够接收并传递任意数量的位置参数和关键字参数。 当你调用 greet(“Alice”) 或 greet(“Bob”, greeting=“Good morning”) 时,装饰器都会先打印函数的参数,然后执行原始函数。

4.lambda表达式

lambda 表达式,也称为匿名函数,是Python中一种简洁的方式来创建简单的函数。与使用 def 关键字定义的常规函数不同,lambda 表达式可以在一行中定义,并且它没有函数名。因此,它常用于需要快速定义简单函数的场景,特别是当你只打算使用一次的函数。 lambda 表达式的基本语法 lambda 表达式的基本语法如下:

代码语言:javascript复制
lambda 参数1, 参数2, ... : 表达式

基本例子

代码语言:javascript复制
# 一个简单的lambda函数,它将两个参数相加
add = lambda x, y: x   y

# 调用这个lambda函数
result = add(3, 5)
print(result)  # 输出: 8

#lambda x, y: x   y 定义了一个匿名函数,它接收两个参数 x 和 y,并返回它们的和。add(3, 5) 调用了这个 lambda 函数,传入 3 和 5,得到结果 8。

lambda 表达式的常见使用场景 虽然 lambda 表达式可以像常规函数一样使用,但它通常用于需要简单函数的场合,尤其是与高阶函数(如 map, filter, reduce 等)配合使用时。

lambda 表达式的限制 lambda 表达式只能包含一个表达式,不能包含多个语句。 由于 lambda 是匿名的,它没有函数名,因此在调试时可能会不太方便。

5.生成器

生成器的基本概念 生成器函数与普通函数的不同之处在于它使用了yield关键字而不是return。每次调用yield时,生成器会返回一个值,并且暂停执行,直到再次被调用时从暂停的地方继续执行。

代码语言:javascript复制
def simple_generator():
    yield 1
    yield 2
    yield 3

# 使用生成器
gen = simple_generator()

print(next(gen))  # 输出: 1
print(next(gen))  # 输出: 2
print(next(gen))  # 输出: 3

解释: simple_generator 是一个生成器函数,使用 yield 依次返回 1, 2, 3。 当你调用 next(gen) 时,生成器会从上一次暂停的地方继续执行,直到遇到下一个 yield 或结束。 如果生成器已经耗尽所有的值,再调用 next() 会引发 StopIteration 异常。

生成器处理斐波那契数列
代码语言:javascript复制
def fibonacci(n):
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a   b

for num in fibonacci(10):
    print(num)

总结: 生成器是Python中一种高效的工具,能够处理需要延迟计算、节省内存的场景。无论是通过生成器函数还是生成器表达式,它们都提供了一种优雅的方式来处理大量数据,避免了不必要的内存消耗。生成器广泛应用于数据流处理、大文件读取、复杂序列生成等任务中,是Python编程中非常重要的一个概念。

高阶函数

高阶函数(Higher-Order Function)是Python中一个非常重要的概念**,它指的是可以接收一个或多个函数作为参数,或返回一个函数作为结果的函数。**高阶函数是函数式编程的核心思想之一,能够让代码更加简洁和灵活。 高阶函数的特点 接收函数作为参数:高阶函数可以将其他函数作为输入参数传递。 返回一个函数:高阶函数可以将函数作为输出返回。

常见的高阶函数 Python 中有几个常见的内置高阶函数,如 map、filter、reduce、sorted 等。 1. map 函数 map 函数将一个函数应用到一个可迭代对象的每个元素上,并返回一个新的迭代器。

代码语言:javascript复制
# 定义一个简单的函数,将数字平方
def square(x):
    return x ** 2

# 使用 map 函数将 square 应用于每个列表元素
numbers = [1, 2, 3, 4, 5]
squared_numbers = list(map(square, numbers))

print(squared_numbers)  # 输出: [1, 4, 9, 16, 25]

2. filter 函数 filter 函数用于过滤可迭代对象中的元素,返回所有使给定函数返回 True 的元素。

代码语言:javascript复制
# 定义一个函数,判断一个数是否是偶数
def is_even(x):
    return x % 2 == 0

# 使用 filter 函数过滤出偶数
numbers = [1, 2, 3, 4, 5, 6]
even_numbers = list(filter(is_even, numbers))

print(even_numbers)  # 输出: [2, 4, 6]

3. reduce 函数 reduce 函数将一个二元函数累积地应用到可迭代对象的元素上,从而将可迭代对象简化为单个值。reduce 函数在 functools 模块中。

代码语言:javascript复制
from functools import reduce

# 定义一个函数,将两个数相乘
def multiply(x, y):
    return x * y

# 使用 reduce 函数计算列表中所有元素的乘积
numbers = [1, 2, 3, 4, 5]
product = reduce(multiply, numbers)

print(product)  # 输出: 120

4. sorted 函数与 key 参数 sorted 函数可以根据指定的排序规则对可迭代对象进行排序。key 参数是一个高阶函数,用于指定排序的依据。

代码语言:javascript复制
# 对一组单词按其长度进行排序
words = ['apple', 'banana', 'cherry', 'date']

# 使用 sorted 函数和 len 函数作为 key
sorted_words = sorted(words, key=len)

print(sorted_words)  # 输出: ['date', 'apple', 'banana', 'cherry']

实际应用

  1. 函数作为参数传递 高阶函数可以将函数作为参数传递给其他函数,使得代码更加灵活。
代码语言:javascript复制
def apply_function(func, value):
    return func(value)

# 传递不同的函数进行计算
print(apply_function(square, 5))  # 输出: 25
print(apply_function(is_even, 5))  # 输出: False
#apply_function 是一个高阶函数,它接收另一个函数 func 和一个值 value,然后将 func 应用于 value。
  1. 函数作为返回值 高阶函数可以返回另一个函数,这使得可以创建工厂函数或封装某些逻辑。
代码语言:javascript复制
def make_multiplier(n):
    def multiplier(x):
        return x * n
    return multiplier

# 创建一个乘以3的函数
times3 = make_multiplier(3)
print(times3(10))  # 输出: 30

# 创建一个乘以5的函数
times5 = make_multiplier(5)
print(times5(10))  # 输出: 50
#make_multiplier 是一个高阶函数,它返回一个 multiplier 函数。multiplier 函数将一个值乘以给定的因子 n。
#你可以使用 make_multiplier 创建不同的乘法函数,如 times3 和 times5。

0 人点赞