一.函数

函数是带名字的代码块,用于完成具体的任务,可重复使用,当需要在程序中多次执行同一项任务时,无须反复编写完成该任务的代码,只需要调用执行该任务的函数,让python运行其中的代码即可。

python中的函数必须先定义后使用,python提供了许多内建函数,也可以自己创建函数,叫做用户自定义函数。

1.定义函数

语法:

def    函数名(参数列表):

          函数完成的功能(函数体)

          [return 返回]

注意:函数得先定义再使用

2.带参数的函数封装

def print_star_1(rows,cols):

     while rows > 0:

           print("*" * cols)

           rows -= 1


print_star_1(2,3) #调用函数

3.函数参数-形式参数和实际参数

形式参数:函数提供者在定义函数时候,声明的参数;没有分配存储空间,也没有值。

实际参数:函数的调用者在调用函数时候,传递的参数,叫做实际参数。传递的是具体的值,底层会执行赋值操作。

4.函数的参数传递

在python中,类型属于对象,变量是没有类型的

引用的概念

变量和数据是分开的,数据保存在内存中的一个位置,变量中保存着数据在内存中的地址,变量中记录数据的地址,就叫做引用

如果变量已经被定义,当给一个变量赋值时候,本质上是修改了数据的引用,变量不再对之前的数据引用,变量对新赋值的数据引用。

可变与不可变类型对象

不可变类型:如整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身,比如fun(a)内部修改a的值,只是修改另一个复制的对象,不会影响a本身。

def modify_immutable(x):
    x += 1  # 创建新对象,原x不变
    print("函数内x:", x)

num = 10
modify_immutable(num)
print("函数外num:", num)  # 输出10,未被修改
 

可变类型:如列表、字典。fun(la),则是将la真正的传递过去,修改后,fun外部的la也会受到影响

def modify_mutable(lst):
    lst.append(4)  # 直接修改原列表
    print("函数内lst:", lst)

my_list = [1, 2, 3]
modify_mutable(my_list)
print("函数外my_list:", my_list)  # 输出[1, 2, 3, 4]
 

5.不同赋值操作的区别

6.函数可使用的参数形式

必须参数

按照参数的位置进行匹配,调用时必须按定义顺序传入对应数量的值。缺少或多出参数会导致错误。

def greet(name, greeting):
    print(f"{greeting}, {name}!")

greet("Alice", "Hello")  # 正确
greet("Hello", "Alice")  # 顺序错误
 

关键字参数:对顺序没有要求哦

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

# 关键字参数调用
greet(name="Alice", message="Hi")  # 输出: Hi, Alice!
greet(message="Hey", name="Bob")   # 输出: Hey, Bob!
greet(name="Charlie")              # 输出: Hello, Charlie!
 

默认值参数

默认参数在定义时指定默认值,调用时可省略。默认参数必须放在非默认参数之后。

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

greet("Alice")  # 使用默认值
greet("Bob", "Hi")  # 覆盖默认值
 

不定长参数/可变参数

形式一:*参数名 :输出会用元组;

注意⚠️:形式一:如果不定长参数后面还有参数,必须通过关键字参数传递。

形式二:**参数名 :输出会用字典;参数在传递时候必须通过键值对的方式传递

注意⚠️:形式二:如果不定长参数后面还有参数,会错误。

def example_function(*args, **kwargs):
    print("位置参数:", args)
    print("关键字参数:", kwargs)

example_function(1, 2, name="Alice", age=25)
 
"""输出:
位置参数: (1, 2) 他是放在元组里面的
关键字参数: {'name': 'Alice', 'age': 25}

"""

7.解包传参

使用 * 解包可迭代对象

* 运算符可以将列表或元组解包为位置参数。例如:

def func(a, b, c):
    return a + b + c

args = [1, 2, 3]
result = func(*args)  # 等价于 func(1, 2, 3)
 

使用 ** 解包字典

** 运算符可以将字典解包为关键字参数。例如:

def func(a, b, c):
    return a + b + c

kwargs = {'a': 1, 'b': 2, 'c': 3}
result = func(**kwargs)  # 等价于 func(a=1, b=2, c=3)
 

混合使用 * 和 **

可以同时使用 * 和 ** 解包位置参数和关键字参数。例如:

def func(a, b, c, d):
    return a + b + c + d

args = [1, 2]
kwargs = {'c': 3, 'd': 4}
result = func(*args, **kwargs)  # 等价于 func(1, 2, c=3, d=4)
 

8.强制使用位置参数或关键字参数

使用 / 强制位置参数

在函数定义中,使用 / 符号可以强制其左侧的参数必须以位置参数形式传递:

def func(a, b, /, c, d):
    print(a, b, c, d)
func(1, 2, c=3, d=4)  # 正确
func(a=1, b=2, c=3, d=4)  # 错误:a和b不能使用关键字参数

使用 * 强制关键字参数

在函数定义中,使用 * 符号可以强制其右侧的参数必须以关键字参数形式传递:

def func(a, b, *, c, d):
    print(a, b, c, d)
func(1, 2, c=3, d=4)  # 正确
func(1, 2, 3, 4)  # 错误:c和d必须使用关键字参数

同时使用 / 和 *

可以同时使用 / 和 * 来强制某些参数使用位置参数,另一些参数使用关键字参数:

def func(a, b, /, c, *, d):
    print(a, b, c, d)
func(1, 2, c=3, d=4)  # 正确
func(1, 2, 3, d=4)  # 正确
func(a=1, b=2, c=3, d=4)  # 错误:a和b不能使用关键字参数
func(1, 2, 3, 4)  # 错误:d必须使用关键字参数

9.防止函数修改列表

有时候需要函数对列表进行处理,又不希望修改原列表,可以使用copy

使用浅拷贝copy() 方法(浅拷贝)

浅拷贝(copy.copy())仅复制最外层对象,嵌套对象仍为引用。

适用于列表、字典等可变对象,直接调用内置方法:

def change_list(list):
    list[1] = 20

list0 = [1,2,3]
list1 = list0.copy()
change_list(list1)
print(list0) #结果任然为[1,2,3]

使用深拷贝deepcopy()方法

import copy

original = [1, [2, 3]]
shallow_copied = copy.copy(original)
deep_copied = copy.deepcopy(original)

# 修改嵌套列表
shallow_copied[1][0] = 99
deep_copied[1][0] = 100

print(original)         # 输出 [1, [99, 3]]
print(shallow_copied)   # 输出 [1, [99, 3]]
print(deep_copied)      # 输出 [1, [100, 3]]
 

10.函数说明文档

使用help()来查看函数说明文档

def add(a, b):
    """计算两个数的和。

    Args:
        a (int): 第一个加数。
        b (int): 第二个加数。

    Returns:
        int: 两个数的和。
    """
    return a + b
 

help(add)

11.返回值

返回值就是函数完成工作后,给调用者的一个结果。

在函数中使用return关键字可以返回结果,并结束正在执行的函数;

如果return后面跟表达式,在结束函数的同时调用返回一个表达式

如果仅仅是return关键字,后面没有内容,函数执行返回调用返回none

调用函数的一方,可以使用变量来接受函数的返回结果

无返回值与None

若函数无return语句或return后无值,默认返回None。

def no_return():
    pass
result = no_return()  # result为None
 

返回单个值

函数可以直接返回一个值(如整数、字符串、列表等)。

def add(a, b):
    return a + b
result = add(3, 5)  # 返回8
 

返回多个值(元组解包)

Python允许通过return返回多个值,实际是返回一个元组,可通过解包接收。

def get_stats(data):
    return min(data), max(data), sum(data)
min_val, max_val, total = get_stats([1, 2, 3])  # 解包为三个变量

12.函数的嵌套调用

def outer_function():
    print("外部函数开始执行")
    inner_function()
    print("外部函数结束执行")

def inner_function():
    print("内部函数被执行")

outer_function()

"""结果:
"外部函数开始执行"
"内部函数被执行"
"外部函数结束执行"
"""

13.函数的闭包

希望在一个函数的函数体中,访问另外一个函数中定义的变量

def outer():
    a = 10
    b = 20
    def inner():
        print(a,b)
    return inner


outer()() #这个outer()得到的是inner 也可以写成f = outer(),f()
def counter():
    count = 0
    def increment():
        nonlocal count
        count += 1
        return count
    return increment

counter1 = counter()
print(counter1())  # 输出1
print(counter1())  # 输出2
 

在一个函数体中定义另一个函数;

外层的函数的返回值是内层函数对象

在内函数中访问了外函数定义的变量

14.变量的作用域

局部local->嵌套enclosing->全局->global->内建built-in(LEGB)

局部作用域(Local)

在函数内部定义的变量属于局部作用域,仅在该函数内部有效。函数执行结束后,局部变量会被销毁。

def my_function():
    local_var = 10
    print(local_var)  # 输出 10

my_function()
print(local_var)  # 报错:NameError
 

嵌套作用域(Enclosing)

嵌套作用域出现在嵌套函数中。外层函数的变量对内层函数可见,但内层函数的变量对外层函数不可见。

def outer():
    enclosing_var = 20
    def inner():
        print(enclosing_var)  # 输出 20
    retrun inner()

f = outer()
f()

全局作用域(Global)

在函数外部定义的变量属于全局作用域,整个程序都可以访问。若要在函数内部修改全局变量,需使用 global 关键字。

global_var = 30

def modify_global():
    global global_var
    global_var = 40

modify_global()
print(global_var)  # 输出 40
 

内置作用域(Built-in)

内置作用域包含 Python 内置的函数和变量(如 print、len 等)。这些名称在任何地方都可用,除非被局部或全局变量覆盖。

print(len([1, 2, 3]))  # 输出 3

def override_len():
    len = "local_len"
    print(len)  # 输出 "local_len"

override_len()
 

15.全局变量和局部变量

全局变量在函数外部声明,可以在程序的任何地方访问。若需在函数内部修改全局变量,需使用global关键字声明。

x = 10  # 全局变量

def func():
    global x
    x = 20  # 修改全局变量

func()
print(x)  # 输出: 20
 
如果x是列表,对列表已经有的元素进行修改不需要加gloabal,因为这属于修改不属于赋值

局部变量仅在函数或代码块内部有效,函数外部无法访问。局部变量与全局变量同名时,函数内部优先使用局部变量。

x = 10  # 全局变量

def func():
    x = 30  # 局部变量
    print(x)  # 输出: 30

func()
print(x)  # 输出: 10
 

nonlocal用于嵌套函数中,声明变量来自外层函数的局部变量(非全局变量)。它允许在内层函数中修改外层函数的变量。

def outer():
    x = 10  # 外层函数的局部变量
    def inner():
        nonlocal x
        x = 20  # 修改外层函数的变量
    inner()
    print(x)  # 输出: 20

outer()
 

16.函数的递归

递归是一种通过函数调用自身来解决问题的方法。它将问题分解为更小的子问题,直到子问题足够简单可以直接解决。

斐波那契数列:

def fibonacci(n):
    if n <= 1:  # 基线条件
        return n
    else:  # 递归条件
        return fibonacci(n - 1) + fibonacci(n - 2)
 

17.匿名函数

lambda 参数: 表达式  
 

示例:对列表元素平方

square = lambda x: x ** 2  
print(square(3))  # 输出9  
 

匿名函数使用场景

排序与自定义比较sort()

匿名函数可以快速定义排序规则或比较逻辑。例如,按字符串长度排序:

words = ["apple", "banana", "cherry"]
words.sort(key=lambda x: len(x))
 

map()

通过 lambda 快速定义简单操作,与 map 结合实现高效数据处理:

numbers = [1, 2, 3, 4]
squared = map(lambda x: x ** 2, numbers)
print(list(squared))  # 输出 [1, 4, 9, 16]
 

匿名函数与filter结合

匿名函数(lambda)常用于filter中作为筛选条件,避免单独定义函数。lambda函数应返回布尔值,True表示保留该元素。

words = ["apple", "banana", "cherry", "date"]
short_words = filter(lambda word: len(word) < 6, words)
print(list(short_words))  # 输出 ['apple', 'date']
 

18.函数的注释

类型注解(Type Hints)

Python 3.5+支持类型注解,通过->和:标注参数及返回值的类型,增强代码可读性和IDE支持。

def greet(name: str) -> str:
    """生成问候语。"""
    return f"Hello, {name}"
 

更多推荐