函数的基础
函数的定义:使用 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']
实际应用
- 函数作为参数传递 高阶函数可以将函数作为参数传递给其他函数,使得代码更加灵活。
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。
- 函数作为返回值 高阶函数可以返回另一个函数,这使得可以创建工厂函数或封装某些逻辑。
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。