文章目录
一、 函数概要
Python中,函数是一段组织好的、可重用的代码,用于执行一个特定的任务。
函数是一种编程结构,它允许你为代码块定义一个名称(函数名),并通过该名称在程序中的其他位置调用该代码块。使用函数的好处包括代码重用、模块化编程和可读性增强。
1. 函数定义规则:使用def
关键字来定义函数
函数名
:函数名应遵循Python的命名规则,通常是小写字母和下划线的组合(如my_function)。避免使用Python的内置函数名或保留字作为函数名。
参数
:函数可以没有参数,也可以有多个参数,可设置可变参:*args
或**kwargs
。参数列表用圆括号括起来,并在函数体内部使用。
返回值
:函数可以使用return语句返回一个值。如果函数没有return语句或return后面没有跟值,那么函数将返回None。
缩进
:在函数定义中,函数体应该相对于def语句缩进。
文档字符串
:非必需,但建议为函数提供文档字符串来解释函数的功能、参数和返回值。使用函数名.__doc__
访问。
2. 特殊定义方式函数:匿名函数
在Python中,匿名函数(也被称为lambda函数)是一种非常简短、一次性的函数,主要用于定义一个简单的函数对象。它们可以用在任何需要函数作为参数的地方,如排序函数sorted()的key参数,或者map()、filter()等内置函数。
Lambda函数的基本语法:lambda arguments: expression
。arguments
是参数列表(与常规函数定义中的参数列表类似,但不允许使用默认参数、可变参数列表或关键字参数),而expression
是一个单个的表达式,其值就是该lambda函数的返回值。
3. 函数的注意事项
避免全局变量
:尽量避免在函数内部使用全局变量,因为这可能导致代码难以理解和维护。如果需要在函数内部修改全局变量的值,可以使用global关键字,但通常最好避免这样做。关注变量的作用域,本文做了关于递归函数,高阶函数,闭包函数
等案例。
函数的副作用
:函数应该尽可能地只执行其声明的任务,并避免产生意外的副作用(如修改全局变量的值或更改调用它的函数的状态)。
函数的粒度
:函数的粒度应该适中。如果函数太长或太复杂,考虑将其拆分成更小的函数。相反,如果函数太短或只做了一件事,考虑是否可以将它与其他相关功能合并。
错误处理
:函数应该能够处理可能出现的错误和异常情况。可以使用try-except块来捕获和处理异常。
测试
:编写函数后,应该编写测试用例来验证函数的正确性和健壮性。这有助于确保函数在所有预期的情况下都能按预期工作。
二、函数应用示例
以下是一些经典的Python函数案例,它们涵盖了函数的基本用法、参数传递、返回值以及更高级的概念,如默认参数、可变参数、递归函数等。
2.1 简单的加法函数
提示:这里可以添加技术名词解释
def add_numbers(a, b):
"""这个函数接受两个参数并返回它们的和"""
return a + b
# 调用函数
result = add_numbers(3, 4)
print(result) # 输出: 7
注意:定义函数,函数的返回值是函数执行完成后返回给调用者的结果。这个返回值可以是任何数据类型,包括整数、浮点数、字符串、列表、元组、字典、集合、自定义对象,或者在没有明确返回值时默认为None。在函数内部,你可以使用return语句来指定返回值。当return语句被执行时,函数会立即结束并返回指定的值。如果没有return语句,函数会在执行完所有代码后返回None。
函数调用是程序执行函数代码的过程。当你使用函数名并后跟括号(可能包含参数)时,你就调用了该函数。调用函数会触发函数内部的代码执行。
2.2 带默认参数的函数
有默认参数的形参,在函数调用时可以传参也可以不传;没有默认参数的形参,调用时必须传参
def greet(name, greeting='Hello!'):
"""这个函数接受一个参数name和一个默认参数greeting,并返回问候语"""
return f"{greeting}, {name}!"
# 调用函数,只传递一个参数
print(greet('World')) # 输出: Hello, World!
# 调用函数,传递两个参数
print(greet('Python', 'Welcome to')) # 输出: Welcome to, Python!
注意:三引号字符串为函数文档字符串,用于解释函数的功能、参数和返回值。同时,这个字符串也是可以被访问的。可以使用内置的__doc__属性
来访问和打印出这些文档字符串。
# 访问函数的文档字符串
doc_string = greet.__doc__
# 打印出文档字符串
print(doc_string)
2.3 可变参数函数
*args:用于收集非关键字参数(位置参数),这些参数在函数内部被收集为一个元组。args不是固定名,是习惯用名
def sum_numbers(*args):
"""这个函数接受任意数量的参数并返回它们的和"""
return sum(args)
# 调用函数,传递不同数量的参数
print(sum_numbers(1, 2, 3)) # 输出: 6
print(sum_numbers(4, 5, 6, 7)) # 输出: 22
2.4 关键字参数函数
**kwargs:用于收集关键字参数,这些参数在函数内部被收集为一个字典。
def display_info(**kwargs):
"""这个函数接受任意数量的关键字参数并打印它们"""
for key, value in kwargs.items():
print(f"{key}: {value}")
# 调用函数,传递关键字参数
display_info(name='Alice', age=30, city='New York')
# 输出:
# name: Alice
# age: 30
# city: New York
注:可变参数一起使用如下:
def my_function(*args, **kwargs):
print("Positional arguments:")
for arg in args:
print(arg)
print("\nKeyword arguments:")
for key, value in kwargs.items():
print(f"{key}: {value}")
# 调用函数,传入位置参数和关键字参数
my_function(1, 2, 3, name="Alice", age=30)
# 1, 2, 3被args接收,变成元组格式。
# name="Alice", age=30,被kwargs接收,变成键值对格式,字典。
2.5 递归函数
n的阶乘计算
def factorial(n):
"""这个函数使用递归计算n的阶乘"""
if n == 0 or n == 1:
return 1
else:
return n * factorial(n-1)
# 调用函数
print(factorial(5)) # 输出: 120
注:累加也可以递归:else:return n+f(n-1)
def accumulate(n):
"""这个函数使用递归计算n的阶乘"""
if n == 1:
return 1
else:
return n + accumulate(n - 1)
# 调用函数
print(accumulate(100)) # 输出: 5050
2.6 函数作为参数传递(高阶函数)
把函数作为参数,作为返回值使用,那么整个函数就不止一阶,可二阶,三阶也
def apply_func(func, arg):
"""这个函数接受一个函数和一个参数,并调用该函数"""
return func(arg)
def square(x):
"""这个函数返回x的平方"""
return x ** 2
# 调用函数,传递函数作为参数
print(apply_func(square, 5)) # 输出: 25
注:python中一切皆对象,所以返回值可以是整数、浮点数、字符串、列表、元组、字典、集合、自定义对象,函数对象也不例外。同理,参数也可以是函数对象。
2.7 闭包函数(带有内部状态的函数)
闭包函数:通过定义一个外部函数,并在该外部函数中定义一个内部函数来实现闭包;内部函数可以通过引用外部函数的局部变量(包括参数)来形成闭包;这些局部变量在外部函数返回内部函数后仍然被内部函数所引用,而不会被Python的垃圾回收机制回收。
def counter():
count = 0
def increment():
nonlocal count
count += 1
return count
return increment
# 创建一个计数器函数
counter_func = counter()
# 调用计数器函数
print(counter_func()) # 输出: 1
print(counter_func()) # 输出: 2
print(counter_func()) # 输出: 3
print(counter_func()) # 输出: 4
print(counter_func()) # 输出: 5
print(counter_func()) # 输出: 6
注:nonlocal关键字用于在嵌套函数中声明一个变量,该变量引用最近的上层(非全局)作用域中的变量,而不是在全局作用域中查找。
在内部函数increment中,我们使用nonlocal关键字声明了count 。这意味着当我们在这个函数内部引用或修改count 时,我们实际上是在引用或修改counter中的count,而不是在全局作用域中查找或创建一个新的变量。
所以,调用一次counter_func()完成,就是完成一次变量counter_func
的修改,多次调用,就是多次修改。
2.8 装饰器函数
在Python中,装饰器函数是一个接受函数作为参数并返回一个新函数的高阶函数。装饰器函数的主要用途是在不修改原函数代码的情况下,给函数增加额外的功能,如日志记录、性能测量、权限检查等。详细参考python装饰器博客。
def my_decorator(func):
def wrapper(*args, **kwargs):
print("Something is happening before the funct is called.这里你可以去检验参数合不合格,比如用户名有没有注册,手机号码是否合法等等")
result = func(*args, **kwargs)
print("Something is happening after the function is called.")
return result
return wrapper
@my_decorator
def say_hello(name):
print(f"Hello, {name}!")
# 调用函数
say_hello("World")
注:示例中,my_decorator
是一个装饰器函数,它接受一个函数func
作为参数,并定义了一个新的函数wrapper
。wrapper
函数在调用原函数func
之前和之后分别执行了一些额外的操作(在这个例子中是打印一些文本)。然后,my_decorator
返回wrapper
函数。
注意是定义函数时添加装饰。
使用@my_decorator
语法糖,我们将装饰器函数my_decorator
应用到了say_hello
函数上。这样,当我们调用say_hello("World")
时,实际上调用的是wrapper
函数,而不是原始的say_hello
函数。但是,从代码的角度看,我们仍然像是在直接调用say_hello
函数一样。
2.8 匿名函数
计算两个数的和:
add = lambda x, y: x + y
print(add(3, 4)) # 输出:7
对列表中的每个元素乘以2:
numbers = [1, 2, 3, 4, 5]
doubled = map(lambda x: x * 2, numbers)
print(list(doubled)) # 输出:[2, 4, 6, 8, 10]
过滤出列表中的偶数:
numbers = [1, 2, 3, 4, 5]
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers) # 输出:[2, 4]
对列表进行排序(根据字符串长度):
words = ["apple", "banana", "cherry", "date"]
sorted_words = sorted(words, key=lambda w: len(w))
print(sorted_words) # 输出:['date', 'apple', 'cherry', 'banana']
三、小结
- 函数定义,调用;参数,可变参数,关键字参数解析。
- 函数的高阶应用:递归,高阶函数,闭包,装饰器。
- 装饰器函数在Python中非常有用,特别是在需要为多个函数添加相同功能时。通过使用装饰器,我们可以避免重复编写相同的代码,并使得代码更加模块化和可维护。
- 匿名函数短小精悍,非常好用。但它们并不适合定义复杂的函数或包含多个语句的函数。对于更复杂的逻辑,通常应该使用常规的def语句来定义函数。
关注,收藏,多多浏览,经常实践,快速成长吧!