函数
定义:函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
作用:函数能提高应用的模块性,和代码的重复利用率。
函数使用规范:
-
函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
-
任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
-
函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
-
函数内容以冒号 : 起始,并且缩进。
-
return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回None。
def 函数名称(参数列表): // 代码块(实现特定功能的代码) [return [返回值]]
举例:
1、比较数的大小
#!/usr/bin/python3
def max(a, b):
if a > b:
return a
else:
return b
a = 4
b = 5
print(max(a, b))
2、计算面积
#!/usr/bin/python3
# 计算面积函数
def area(width, height):
return width * height
def print_welcome(name):
print("Welcome", name)
#进行函数的调用
print_welcome("Runoob")
w = 4
h = 5
print("width =", w, " height =", h, " area =", area(w, h))
在print中调用的是area()这个函数。
可更改(mutable)与不可更改(immutable)对象(感觉实际使用起来用的不多,看后续会不会用补充)
在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。
-
不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变 a 的值,相当于新生成了 a。
-
可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。
python 函数的参数传递:
-
不可变类型:类似 C++ 的值传递,如整数、字符串、元组。如 fun(a),传递的只是 a 的值,没有影响 a 对象本身。如果在 fun(a) 内部修改 a 的值,则是新生成一个 a 的对象。
-
可变类型:类似 C++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后 fun 外部的 la 也会受影响
python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。
举例:
1、通过id()函数观察——传不可变对象实例
#!/usr/bin/python3
# 计算面积函数
def area(width, height):
return width * height
def print_welcome(name):
print("Welcome", name)
#进行函数的调用
print_welcome("Runoob")
w = 4
h = 5
print("width =", w, " height =", h, " area =", area(w, h))
在print中调用的是area()这个函数。
可以看见在调用函数前后,形参和实参指向的是同一个对象(对象 id 相同),在函数内部修改形参后,形参指向的是不同的 id
2、可变对象在函数里修改了参数,那么在调用这个函数的函数里,原始的参数也被改变了。——传可变对象实例
#!/usr/bin/python3
# 可写函数说明
def changeme( mylist ):
"修改传入的列表"
mylist.append([1,2,3,4])
print ("函数内取值: ", mylist)
return
# 调用changeme函数
mylist = [10,20,30]
changeme( mylist )
print ("函数外取值: ", mylist)
形参和实参
def 函数名称(参数列表): // 代码块(实现特定功能的代码) [return [返回值]]
1、形参
在上例语法格式中:
参数列表:也可以称为形参列表,指的是自定义函数可以接收的参数,个数不限,多个参数之间要用逗号,
分隔。
#例一
# 定义一个空函数。用 pass 语句作为占位符。没有什么实际意义的函数。
def func_pass(): # 不带参数
pass
#例二
# 定义一个求和的函数
def func_sum(num1, num2):
return num1 + num2
2、实参
[接收变量] = 函数名([实参列表]) # 定义函数 def 函数名称([参数1, 参数2, ...]): 函数体 ... [return 返回值] # 调用函数 [接收变量] = 函数名称(参数1, 参数2, ...)
-
接收变量:如果该函数有返回值,我们可以通过一个变量来接收该值,也可以不接收。
-
函数名:要调用的函数的名称。
-
实参列表:在调用函数时传入的参数叫做实际参数,简称实参。指的是在创建函数时要求传入的各个形参的值。
-
函数如果没有参数,函数名后的小括号也不能省略。
# 定义一个求和的函数,有返回值的函数
def func_sum(num1, num2):
return num1 + num2
result = func_sum(2, 3) # 调用函数并传参,还把函数的返回值赋值给了一个变量
print(result)
print(func_sum(2, 3)) # 没有把函数的返回值赋值给一个变量
关键字参数
定义:关键字参数
关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。
使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
#!/usr/bin/python3
#可写函数说明
def printme( str ):
"打印任何传入的字符串"
print (str)
return
#调用printme函数
printme( str = "菜鸟教程")
#!/usr/bin/python3
#可写函数说明
def printinfo( name, age ):
"打印任何传入的字符串"
print ("名字: ", name)
print ("年龄: ", age)
return
#调用printinfo函数
printinfo( age=50, name="runoob" )
默认参数
调用函数时,如果没有传递参数,则会使用默认参数。以下实例中如果没有传入 age 参数,则使用默认值
举例:
#!/usr/bin/python3
#可写函数说明
def printinfo( name, age = 35 ):
"打印任何传入的字符串"
print ("名字: ", name)
print ("年龄: ", age)
return
#调用printinfo函数
printinfo( age=50, name="runoob" )
print ("------------------------")
printinfo( name="runoob" )
#输出结果
名字: runoob
年龄: 50
------------------------
名字: runoob
年龄: 35
不定长参数
当你可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,和上述 2 种参数不同,声明时不会命名。
#基本语法 def functionname([formal_args,] *var_args_tuple ): "函数_文档字符串" function_suite return [expression] #函数定义 def functionname([formal_args,] *var_args_tuple ): def: Python 中定义函数的关键字。 functionname: 函数的名称,按照标识符命名规则。 [formal_args,]: 可选的形式参数列表,可以包含零个或多个参数,参数之间用逗号分隔。 *var_args_tuple: 可变数量的位置参数(tuple),用星号 表示,允许函数接受任意数量的额外参数,并将它们作为元组存储在*var_args_tuple 中。
加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。
举例:
def calculate_sum(*numbers):
"""计算任意数量整数的和"""
total = 0
for num in numbers:
total += num
return total
# 调用函数
result = calculate_sum(1, 2, 3, 4, 5)
print(result) # 输出 15
-
calculate_sum
是函数的名称。 -
*numbers
接收任意数量的位置参数,将它们存储在 元组中。numbers
-
"""计算任意数量整数的和"""
是函数的文档字符串,用于描述函数的作用。 -
total
是在函数体内部计算总和的变量。 -
return total
返回计算出的总和作为函数的结果。
还有一种就是参数带两个星号 **
def functionname([formal_args,] **var_args_dict ): "函数_文档字符串" function_suite return [expression]
加了两个星号 ** 的参数会以字典的形式
#!/usr/bin/python3
# 可写函数说明
def printinfo( arg1, **vardict ):
"打印任何传入的参数"
print ("输出: ")
print (arg1)
print (vardict)
# 调用printinfo 函数
printinfo(1, a=2,b=3)
声明函数时,参数中星号 * 可以单独出现,
def f(a,b,*,c): return a+b+c
如果单独出现星号 *,则星号 * 后的参数必须用关键字传入:
>>> def f(a,b,*,c):
... return a+b+c
...
>>> f(1,2,3) # 报错
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 2 positional arguments but 3 were given
>>> f(1,2,c=3) # 正常
6
>>>
匿名函数
匿名函数的应用场景涵盖了许多需要简洁定义函数的场合,尤其是在需要一次性使用简单逻辑、不需要额外命名函数的情况下特别实用——感觉在实际应用阶段应用的很少。所以就简单的介绍一下
定义:所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。
-
lambda 只是一个表达式,函数体比 def 简单很多。
-
lambda 的主体是一个表达式,而不是一个代码块。仅仅能在 lambda 表达式中封装有限的逻辑进去。
-
lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
-
虽然 lambda 函数看起来只能写一行,却不等同于 C 或 C++ 的内联函数,内联函数的目的是调用小函数时不占用栈内存从而减少函数调用的开销,提高代码的执行速度。
举例:
1、
#语法格式 lambda 参数: 表达式
#实例
square = lambda x: x ** 2
print(square(5))
匿名函数通常用于那些只需要在一处使用且逻辑简单的函数,比如作为参数传递给其他函数,如 sorted
、map
、filter
等。
拿sorted举例:
在 Python 中,可以使用 sorted()
函数结合 lambda
函数来进行排序。
例如,对于一个列表 numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
,如果要按照每个元素的平方值进行升序排序
numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
sorted_numbers = sorted(numbers, key=lambda x: x**2)
print(sorted_numbers)
又比如,对于一个包含元组的列表 students = [('Alice', 85), ('Bob', 90), ('Charlie', 78)]
,如果要按照成绩降序排序,
students = [('Alice', 85), ('Bob', 90), ('Charlie', 78)]
sorted_students = sorted(students, key=lambda x: x[1], reverse=True)
print(sorted_students)
还有map()
map()
函数用于对可迭代对象中的每个元素应用指定的函数,并返回一个新的可迭代对象,其中包含应用函数后的结果。
语法:map(function, iterable)
numbers = [1, 2, 3, 4, 5]
squared_numbers = map(lambda x: x ** 2, numbers)
print(list(squared_numbers))
filter()
filter()
函数用于过滤可迭代对象中的元素,返回一个新的可迭代对象,其中包含使指定函数返回 True 的元素。
语法:filter(function, iterable)
numbers = [1, 2, 3, 4, 5]
even_numbers = filter(lambda x: x % 2 == 0, numbers)
print(list(even_numbers))
总结:大都大同小异,但要注意三种函数使用的格式,不注意会出错哦。
retrun语句
return [表达式] 语句用于退出函数,选择性地向调用方返回一个表达式。不带参数值的 return 语句返回 None。
#!/usr/bin/python3
# 可写函数说明
def sum( arg1, arg2 ):
# 返回2个参数的和."
total = arg1 + arg2
print ("函数内 : ", total)
return total
# 调用sum函数
total = sum( 10, 20 )
print ("函数外 : ", total)
建议在pycharm上进行运行并断点,这样方便更好的理解。
装饰器
定义:装饰器(decorator)是 Python 的一个重要特性,它可以在不修改原函数代码的情况下,为函数添加额外的功能。装饰器本质上是一个函数(或类),它接受一个函数作为参数,并返回一个新的函数。
def decorator_function(original_function):
def wrapper(*args, **kwargs):
# 这里是在调用原始函数前添加的新功能
before_call_code()
result = original_function(*args, **kwargs)
# 这里是在调用原始函数后添加的新功能
after_call_code()
return result
return wrapper
# 使用装饰器
@decorator_function
def target_function(arg1, arg2):
pass # 原始函数的实现
import functools
def my_decorator(func):
@functools.wraps(func) # 保留原函数的属性
def wrapper(*args, **kwargs):
print("函数开始执行")
result = func(*args, **kwargs)
print("函数执行完毕")
return result
return wrapper
# 使用装饰器
@my_decorator
def my_function():
print("这是原函数的内容")
my_function()
在上在第二段代码中,定义了一个名为my_decorator
的装饰器函数。它内部定义了一个wrapper
函数,在wrapper
函数中添加了额外的打印日志的功能,然后返回wrapper
函数。
使用@my_decorator
装饰器来修饰my_function
函数,相当于执行了my_function = my_decorator(my_function)
,将原函数my_function
替换为经过装饰后的wrapper
函数。当调用my_function()
时,实际上执行的是wrapper
函数中的代码,从而实现了在不修改原函数的情况下添加额外功能的目的。
这两段代码是有优劣性分析的,在第二段中有个@functools.wraps(func) ,这个在一段是没有的,这个@functools.wraps(func) ,这种做法能够更好地保留和传递原函数的元数据,是使用装饰器时推荐的一种做法,特别是当你需要在装饰器中访问或者修改原函数的属性时。
装饰器还可以接受参数
import functools
def my_decorator_with_param(param):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"带有参数 {param} 的装饰器:函数开始执行")
result = func(*args, **kwargs)
print(f"带有参数 {param} 的装饰器:函数执行完毕")
return result
return wrapper
return decorator
@my_decorator_with_param("示例参数")
def my_function():
print("这是原函数的内容")
my_function()
在这个示例中,my_decorator_with_param
是一个带有参数的装饰器函数,它返回了一个装饰器函数decorator
,decorator
函数再去装饰原函数。
Python 中还有一些内置的装饰器,例如@staticmethod
(用于将方法转换为静态方法)、@classmethod
(用于将方法转换为类方法)、@property
(用于将类的方法转换为属性)等。
类也可以作为装饰器,只要类实现了__call__
方法,就可以像函数一样使用类来装饰其他函数。
装饰器在 Python 中非常有用,可以用于实现日志记录、性能分析、权限控制、参数校验等各种功能,它使得代码更加简洁、可维护和可扩展。
如果你想创建一个既支持@log
又支持@log('execute')
形式的装饰器
import functools
def log(text=None):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
if text:
print(f"{text} {func.__name__}():")
else:
print(f"{func.__name__}():")
return func(*args, **kwargs)
return wrapper
return decorator if text is None else decorator(func)
# 使用示例
@log
def function1():
pass
@log('execute')
def function2():
pass
这个
@log
def function1():
pass
@log('execute')
def function2():
pass
这个可以理解为在def log(text=None)中,判断text的参数是否有无,有则用@log('execute'),无则用@log