函数的创建

定义函数指创建一个新的函数

调用函数指使用这个函数

def 函数名(参数):
    代码块
    return 返回值

1.def是保留字,表示创建一个函数

2.函数名表示被定义的函数的名称,函数名可以由用户任意指定,但要遵守命名规则。

3.参数表示该函数可以接收到的数据

5.return用于将函数执行后的数据返回给调用函数

函数的调用

使用形式

函数名(参数)

如果先写调用函数再写定义函数,代码程序将无法运行

函数的复用

函数的复用指的是在编程中,编写一个函数后,可以在程序的多个地方重复使用它,而不需要每次都重新编写相同的代码。

# 定义一个加法函数
def add(a, b):
    """返回两个数的和"""
    return a + b

# 第一次使用:计算 10 和 20 的和
result1 = add(10, 20)
print(f"10 + 20 = {result1}")  # 输出: 10 + 20 = 30

# 第二次使用:计算 5.5 和 3.3 的和
result2 = add(5.5, 3.3)
print(f"5.5 + 3.3 = {result2}")  # 输出: 5.5 + 3.3 = 8.8

# 第三次使用:计算两个变量的和
x = 100
y = 200
result3 = add(x, y)
print(f"{x} + {y} = {result3}")  # 输出: 100 + 200 = 300

# 第四次使用:在另一个表达式中使用
total = add(1, 2) + add(3, 4)
print(f"Total: {total}") # 输出: Total: 10

return返回值

return语句用于将函数中的数据返回给调用函数

示例 1:返回一个计算结果

def add(a, b):
    return a + b  # 返回 a 和 b 的和

result = add(3, 5)
print(result)  # 输出: 8

示例 2:返回一个布尔值

def is_even(n):
    return n % 2 == 0  # 如果 n 是偶数,返回 True,否则返回 False

print(is_even(4))  # 输出: True
print(is_even(7))  # 输出: False

示例 3:提前返回(终止函数执行)

def check_age(age):
    if age < 18:
        return "未成年,禁止访问"  # 提前返回,后面的代码不会执行
    return "成年,允许访问"

message = check_age(16)
print(message)  # 输出: 未成年,禁止访问

示例 4:返回多个值

会以元组形式返回

def get_user_info():
    name = "Alice"
    age = 25
    return name, age  # 本质上是返回一个元组 (name, age)

username, userage = get_user_info()
print(username)  # 输出: Alice
print(userage)   # 输出: 25

示例 5:没有显式返回值(默认返回 None)

def greet(name):
    print(f"Hello, {name}!")  # 没有 return 语句

result = greet("Bob")
print(result)  # 输出: None

核心要点

  • return 可返回任意类型的值(数字、字符串、列表、字典等)。
  • 函数中可以有多个 return,但只有第一个被执行的 return 会生效(后续代码终止)。
  • 若函数没有显式写 return,默认返回 None

函数的参数

形参和实参

def 函数名(形参1,形参2,...):
   代码块
   return 返回值
函数名(实参1,实参2,...)

1. 默认参数 (Default Arguments)

定义:在定义函数时,可以为参数指定一个默认值。当调用函数时,如果没有为这个参数提供值,它就会自动使用这个默认值。

语法

def function_name(param1, param2=default_value):
    # 函数体

示例

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

# 只提供必须的参数
greet("Alice")  # 输出: Hello, Alice!

# 提供所有参数,覆盖默认值
greet("Bob", "Good morning")  # 输出: Good morning, Bob!

注意:带默认值的参数必须放在没有默认值的参数后面。


2. 可变参数 (Variable-length Arguments)

定义:当你不确定函数会接收多少个位置参数时,可以使用可变参数。它会将所有多余的位置参数收集到一个 ** 元组(tuple)** 中。

语法

def function_name(*args):
    # 函数体,args 是一个元组

示例

def add_all(*args):
    total = 0
    for num in args:
        total += num
    return total

# 可以传入任意数量的参数
sum1 = add_all(1, 2, 3)
sum2 = add_all(10, 20, 30, 40, 50)
sum3 = add_all() # 也可以不传入参数,args 为空元组

print(sum1)  # 输出: 6
print(sum2)  # 输出: 150
print(sum3)  # 输出: 0

*args 可以和普通参数一起使用,但必须放在普通参数后面。


3. 关键字参数 (Keyword Arguments)

定义:当调用函数时,你可以通过 关键字=值 的形式指定参数的名称,这样就不需要按照函数定义的顺序来传递参数了。

语法(调用时)

function_name(param1=value1, param2=value2)

示例

def describe_pet(animal_type, pet_name):
    print(f"I have a {animal_type} named {pet_name}.")

# 按照位置传递参数
describe_pet("dog", "Buddy")  # 输出: I have a dog named Buddy.

# 使用关键字传递参数,顺序可以随意调换
describe_pet(pet_name="Mittens", animal_type="cat")  # 输出: I have a cat named Mittens.
3.1 可变关键字参数 (Arbitrary Keyword Arguments)

定义:当你不确定函数会接收多少个关键字参数时,可以使用它。它会将所有多余的关键字参数收集到一个 ** 字典(dict)** 中。

语法

def function_name(**kwargs):
    # 函数体,kwargs 是一个字典

示例

def build_profile(first_name, last_name, **kwargs):
    profile = {"first": first_name, "last": last_name}
    profile.update(kwargs) # 将 kwargs 中的内容更新到 profile 字典中
    return profile

user_profile = build_profile(
    "Albert", 
    "Einstein", 
    location="Princeton", 
    field="Physics"
)

print(user_profile)
# 输出: {'first': 'Albert', 'last': 'Einstein', 'location': 'Princeton', 'field': 'Physics'}

总结对比

参数类型 定义时语法 调用时语法 内部接收类型 核心作用
默认参数 def f(a, b=5): f(10) 或 f(10, 20) 普通变量 为参数提供默认值,简化调用
可变位置参数 def f(*args): f(1, 2, 3, 4) 元组 (tuple) 接收任意数量的位置参数
可变关键字参数 def f(**kwargs): f(x=1, y=2, z=3) 字典 (dict) 接收任意数量的关键字参数

函数的变量作用范围

函数的变量作用范围(Scope)指的是变量在程序中可以被访问的区域。主要分为局部变量全局变量,某些语言还支持嵌套作用域(如 Python、JavaScript)。

在函数中使用全局变量且对全局变量赋值时,将会重新在函数内部创建一个新的局部变量,而不是直接使用全局变量,函数内部的变量和函数外部的变量只是名称相同,实际上并不是同一个变量

一、局部变量(Local Variable)

  • 定义:在函数内部声明的变量,仅在函数内部可见和访问。
  • 生命周期:从函数调用开始创建,函数执行结束后销毁。
  • 示例(Python):
    def func():
        x = 10  # 局部变量,仅在 func 内部可用
        print(x)  # 输出:10
    
    func()
    print(x)  # 报错:NameError: name \'x\' is not defined(外部无法访问)
    

二、全局变量(Global Variable)

  • 定义:在函数外部声明的变量,可在整个程序(包括多个函数)中访问。
  • 注意:函数内部若要修改全局变量,需用 global 关键字声明(否则会被当作局部变量重新定义)。
  • 示例(Python):
    x = 100  # 全局变量
    
    def func1():
        print(x)  # 函数内部可直接访问全局变量(读取),输出:100
    
    def func2():
        global x  # 声明要修改的是全局变量
        x = 200  # 修改全局变量的值
    
    func1()
    func2()
    print(x)  # 输出:200(全局变量已被修改)
    

三、嵌套作用域(Enclosing Scope)

  • 定义:在嵌套函数(函数内部再定义函数)中,内层函数可以访问外层函数的变量(非全局、非局部),外层变量称为 “自由变量”。
  • 注意:内层函数若要修改外层变量,需用 nonlocal 关键字声明(Python 特有)。
  • 示例(Python):
    def outer():
        x = 10  # 外层函数的变量(嵌套作用域变量)
        
        def inner():
            nonlocal x  # 声明要修改的是外层函数的变量
            x = 20  # 修改外层变量
            print(x)  # 输出:20
        
        inner()
        print(x)  # 输出:20(外层变量已被内层修改)
    
    outer()
    

核心规则(就近原则)

变量访问时,会优先在当前作用域查找,若找不到则向上一层作用域查找,直到全局作用域;若全局作用域仍找不到,则报错。

  • 局部作用域 → 嵌套作用域(若有) → 全局作用域

变量为可变数据

在python中根据是否会改变内存恐慌可将数据分为可变数据和不可变数据,其中可变数据是指数据变化后不会改变内存空间。

当可变数据为全局变量时,在函数中对可变数据进行修改回改变全局变量

id()函数可以获取变量数据值所在的内存空间编号

id() 函数用于获取对象的唯一标识符,这个标识符是一个整数,可以理解为该对象在计算机内存中的地址。

语法

id(object)
  • 参数object,可以是任何 Python 对象(整数、字符串、列表、字典等)。
  • 返回值:一个整数,表示对象的唯一 ID。

核心特点

  1. 唯一性:在同一个程序运行期间,每个对象的 ID 都是唯一的,不同对象的 ID 不会重复。
  2. 暂时性:对象被销毁后,其 ID 可能会被后续创建的对象复用(但在同一时间点不会重复)。
  3. 与内存地址的关系:ID 本质上是对象在内存中的地址(对于 CPython 解释器,id() 直接返回对象的内存地址)。

示例代码

1. 基本类型对象的 ID
# 整数对象
a = 10
b = 10
print(id(a))  # 输出:140707243256848(具体值因系统和运行时而异)
print(id(b))  # 输出:140707243256848(与 a 相同,因为小整数会被缓存)

# 字符串对象
s1 = "hello"
s2 = "hello"
print(id(s1))  # 输出:140707243182768
print(id(s2))  # 输出:140707243182768(字符串常量池优化,相同字符串复用)

# 列表对象(可变类型)
lst1 = [1, 2, 3]
lst2 = [1, 2, 3]
print(id(lst1))  # 输出:140707243054592
print(id(lst2))  # 输出:140707243054720(不同对象,ID 不同)
2. 变量赋值与 ID 变化
x = [1, 2, 3]
print(id(x))  # 输出:140707243054848

# 变量 x 重新赋值为新列表
x = [4, 5, 6]
print(id(x))  # 输出:140707243054976(ID 改变,指向新对象)

# 变量引用传递
y = x
print(id(y))  # 输出:140707243054976(与 x 相同,指向同一个对象)
3. 函数参数传递与 ID
def func(obj):
    print("函数内对象 ID:", id(obj))

lst = [1, 2, 3]
print("函数外对象 ID:", id(lst))  # 输出:140707243055104
func(lst)  # 输出:函数内对象 ID:140707243055104(传递的是对象引用,ID 相同)

导入其它模块中的函数

在 Python 中,模块导入主要有以下几种方式,以 module_name.py 文件为例,其内容如下:

# module_name.py
def func1():
    return "函数1"

def func2():
    return "函数2"

variable = "模块变量"

1. 导入整个模块

语法

import module_name

使用:通过 模块名.函数名/模块名.变量名 访问。

示例

import module_name

print(module_name.func1())   # 输出:函数1
print(module_name.variable)  # 输出:模块变量

2. 导入模块中的指定函数 / 变量

语法

from module_name import func1, func2, variable

使用:直接使用函数名 / 变量名,无需加模块前缀。

示例

from module_name import func1, variable

print(func1())        # 输出:函数1
print(variable)       # 输出:模块变量
# print(func2())     # 报错:未导入

3. 导入模块中的全部函数 / 变量(不推荐)

语法

from module_name import *

使用:直接使用所有函数和变量,但可能导致命名冲突。

示例

from module_name import *

print(func1())   # 输出:函数1
print(func2())   # 输出:函数2
print(variable)  # 输出:模块变量

缺点

  • 污染当前命名空间,可能覆盖已有变量 / 函数。
  • 可读性差,无法清晰区分来源。

4. 导入模块并指定别名(推荐)

语法

import module_name as mn
from module_name import func1 as f1

示例

import module_name as mn
print(mn.func1())  # 输出:函数1

from module_name import func2 as f2
print(f2())        # 输出:函数2

优点

  • 简化代码,避免长模块名重复输入。
  • 解决命名冲突。

__name__属性

在 Python 中,__name__ 是一个内置变量,用于表示当前模块的名称。它的核心作用是判断模块是 “被直接运行” 还是 “被导入到其他模块中运行”


1. __name__ 的两种取值

  • 当模块被直接运行时__name__ 的值为 "__main__"
  • 当模块被导入到其他模块时__name__ 的值为模块本身的名称(即文件名,不带 .py 后缀)。

2. 示例说明

假设有两个文件:

  • module_a.py
  • module_b.py
示例 1:模块被直接运行

module_a.py

print(f"模块 module_a 的 __name__ 值为: {__name__}")

if __name__ == "__main__":
    print("模块 module_a 被直接运行了!")
else:
    print("模块 module_a 被导入到其他模块中了。")

运行 module_a.py 的输出:

plaintext

模块 module_a 的 __name__ 值为: __main__
模块 module_a 被直接运行了!

示例 2:模块被导入

module_b.py

# 导入 module_a
import module_a

print(f"\n模块 module_b 的 __name__ 值为: {__name__}")

运行 module_b.py 的输出:

plaintext

模块 module_a 的 __name__ 值为: module_a
模块 module_a 被导入到其他模块中了。

模块 module_b 的 __name__ 值为: __main__

3. 核心作用

__name__ 的主要用途是让模块既可以独立运行(作为脚本),又可以被其他模块导入(作为工具模块)

典型场景

  • 在模块中编写测试代码,只有当模块被直接运行时才执行测试。
  • 避免模块中的代码在被导入时自动执行(只在直接运行时执行)。

4. 常见用法总结

# 模块中的主程序入口
if __name__ == "__main__":
    # 当模块被直接运行时,执行以下代码
    main()  # 例如调用主函数
    print("测试代码执行...")

优点

  • 使模块具有 “双重身份”,增强代码的复用性和灵活性。
  • 分离 “库代码” 和 “测试 / 演示代码”,保持模块的整洁。

函数的递归

函数递归是指函数在执行过程中调用自身的编程技巧,用于将复杂问题分解为规模更小的同类子问题,直到达到可直接求解的 “基线条件”(终止条件),再逐层返回结果,最终得到原问题的解。

一、递归的核心要素(必须满足)

  1. 基线条件(Base Case):递归终止的条件,当问题规模缩小到此时,直接返回结果,避免无限递归(导致栈溢出)。
  2. 递归步骤(Recursive Step):将原问题分解为规模更小的同类子问题,通过调用自身求解子问题,再组合子问题的结果得到原问题的解。

二、经典示例(简洁版)

示例 1:计算 n 的阶乘(n!)
  • 定义:n! = n × (n-1) × (n-2) × ... × 1,且 0! = 1(基线条件)。
  • 递归逻辑:n! = n × (n-1)!(将 n! 分解为 n 和 (n-1)! 的乘积,子问题规模更小)。
def factorial(n):
    # 基线条件:n=0 或 n=1 时,直接返回 1
    if n in (0, 1):
        return 1
    # 递归步骤:n! = n × (n-1)!
    return n * factorial(n - 1)

# 测试
print(factorial(5))  # 输出:120(5×4×3×2×1)
示例 2:斐波那契数列(第 n 项)
  • 定义:斐波那契数列前两项为 0、1,后续每项 = 前两项之和(F (n) = F (n-1) + F (n-2))。
  • 基线条件:F(0)=0,F(1)=1。
def fibonacci(n):
    # 基线条件:n=0 返回 0,n=1 返回 1
    if n == 0:
        return 0
    elif n == 1:
        return 1
    # 递归步骤:F(n) = F(n-1) + F(n-2)
    return fibonacci(n - 1) + fibonacci(n - 2)

# 测试
print(fibonacci(6))  # 输出:8(数列:0,1,1,2,3,5,8)
示例 3:计算列表元素之和(递归实现)
  • 基线条件:列表为空时,和为 0。
  • 递归步骤:列表和 = 第一个元素 + 剩余元素的和(子问题:规模减 1 的列表)。
def list_sum(lst):
    # 基线条件:空列表和为 0
    if not lst:
        return 0
    # 递归步骤:第一个元素 + 剩余列表的和
    return lst[0] + list_sum(lst[1:])

# 测试
print(list_sum([1, 2, 3, 4]))  # 输出:10(1+2+3+4)

三、递归的优缺点

优点:
  • 代码简洁直观,能自然表达分治思想(如斐波那契、阶乘等数学问题)。
  • 无需手动编写循环,减少代码冗余。
缺点:
  • 递归调用会创建新的函数栈帧,若递归深度过大(如 n=10000 的阶乘),会导致 栈溢出(RecursionError)
  • 部分场景存在重复计算(如斐波那契数列的递归实现,会多次计算 F (n-2)、F (n-3) 等),效率较低(可通过 memoization 优化)。

匿名函数lambda

函数名 = lambda 参数:函数内代码

等效为

def fun1(x,y):
   return y+x

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐