python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python函数返回值return与多返回值

Python函数的返回值return与多返回值示例详解

作者:星河耀银海

这篇文章主要介绍了Python函数的返回值return与多返回值的相关资料,从基础用法到多返回值、生成器特性,再到实战案例,文中通过代码介绍的非常详细,需要的朋友可以参考下

一、开篇:return——函数的"出口"

每个函数都有入口(参数)和出口(返回值)。如果说参数让函数接收输入,那么return就让函数给出结果。在Python中,return语句还有几个不那么明显的特性——多返回值、隐式返回None、以及它在生成器中的特殊用法。

⌨️ 先来看几个问题:

# 问题1:没有return的函数返回什么?
def no_return():
    print("我没有return语句")

result = no_return()
print(result)    # 输出什么?

# 问题2:Python函数能返回多个值吗?
def get_user():
    return "张三", 25, "zhangsan@test.com"

name, age, email = get_user()
print(name, age, email)  # 这到底返回了一个值还是三个值?

# 问题3:return和print有什么区别?
def add_and_print(a, b):
    print(a + b)  # 这不叫"返回"!

def add_and_return(a, b):
    return a + b  # 这才叫返回

result = add_and_print(3, 4)
print(f"add_and_print的结果: {result}")     # None!

result = add_and_return(3, 4)
print(f"add_and_return的结果: {result}")    # 7

💡 今天这篇文章,我们就来彻底搞懂return语句的一切。

二、return的基本用法

2.1 return的作用

# return有两个作用:
# 1. 终止函数执行(函数遇到return立刻结束)
# 2. 将一个值(或多个值)返回给调用者

# 基本使用
def add(a, b):
    return a + b

result = add(3, 5)
print(result)    # 8

# return后面的代码不会执行
def demonstrate_early_return(x):
    if x < 0:
        return "负数"  # 函数在这里结束
    if x == 0:
        return "零"    # 函数在这里结束
    # x > 0 才执行到这里
    result = x ** 2
    return f"正数,平方={result}"

print(demonstrate_early_return(-5))   # 负数
print(demonstrate_early_return(0))    # 零
print(demonstrate_early_return(5))    # 正数,平方=25

2.2 没有return的函数

# 没有return语句的函数,隐式返回None
def no_return():
    pass

def just_print():
    print("我只打印,不返回")

def return_none():
    return  # 只有return,没有值

# 三者的返回结果相同
print(no_return())      # None
print(just_print())     # None(先打印"我只打印,不返回")
print(return_none())    # None

# ⚠️ 常见错误:混淆print和return
def calculate_bad(a, b):
    print(a + b)  # 打印到屏幕,但不返回值

def calculate_good(a, b):
    return a + b  # 返回值,可以赋值给变量

# calculate_bad的结果无法被后续计算使用
result_bad = calculate_bad(3, 4)    # 屏幕输出: 7
print(f"result_bad + 10 = {result_bad + 10}")  # TypeError! None + 10

# calculate_good的结果可以被使用
result_good = calculate_good(3, 4)  # 屏幕无输出
print(f"result_good + 10 = {result_good + 10}")  # 17

2.3 return 与循环的结合

# return可以在循环中使用,立即终止整个函数

def find_first_negative(numbers):
    """找到第一个负数并返回"""
    for i, n in enumerate(numbers):
        if n < 0:
            return i, n  # 找到就返回,函数结束
    return -1, None  # 没找到

# return在嵌套循环中——直接终止整个函数
def find_in_matrix(matrix, target):
    """在矩阵中搜索目标值"""
    for i, row in enumerate(matrix):
        for j, value in enumerate(row):
            if value == target:
                return (i, j)  # 终止整个函数,不只是内层循环!
    return None

matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
]
print(find_in_matrix(matrix, 5))   # (1, 1)
print(find_in_matrix(matrix, 10))  # None

# ⚠️ 注意:return不能直接在函数外的循环中使用
# for i in range(10):
#     return i  # SyntaxError! return只能在函数内部

三、多返回值:Python的独门绝技

3.1 多返回值的本质

# Python的"多返回值"实际上返回的是一个元组
def get_user():
    return "张三", 25, "zhangsan@test.com"

# 上面等价于:
def get_user_explicit():
    return ("张三", 25, "zhangsan@test.com")

# 验证:返回值的类型
result = get_user()
print(result)           # ('张三', 25, 'zhangsan@test.com')
print(type(result))    # <class 'tuple'>

# 利用元组解包分别接收
name, age, email = get_user()
print(name)    # 张三
print(age)     # 25
print(email)   # zhangsan@test.com

# 也可以只接收元组
data = get_user()
print(data[0])  # 张三
print(data[1])  # 25

3.2 多返回值的各种用法

# 1. 返回两个值:常用于"结果+状态"
def safe_divide(a, b):
    """安全除法,返回 (结果, 是否成功)"""
    if b == 0:
        return None, False
    return a / b, True

result, ok = safe_divide(10, 2)
if ok:
    print(f"结果: {result}")
else:
    print("除数不能为零")

# 2. 返回三个值:常用于统计
def statistics(numbers):
    """返回 (最小值, 最大值, 平均值)"""
    if not numbers:
        return None, None, None
    return min(numbers), max(numbers), sum(numbers) / len(numbers)

scores = [85, 92, 78, 95, 88]
min_score, max_score, avg_score = statistics(scores)
print(f"最低: {min_score}, 最高: {max_score}, 平均: {avg_score:.1f}")

# 3. 返回多个值:按需接收
def get_file_info(filepath):
    """返回文件的多种信息"""
    import os
    exists = os.path.exists(filepath)
    if not exists:
        return exists, None, None, None
    
    size = os.path.getsize(filepath)
    modified = os.path.getmtime(filepath)
    ext = os.path.splitext(filepath)[1]
    return exists, size, modified, ext

# 可以只接收需要的部分(使用 _ 忽略不需要的)
exists, size, _, ext = get_file_info("test.py")
print(f"存在: {exists}, 大小: {size}字节, 扩展名: {ext}")

# 或者用 * 收集多余返回值
exists, *details = get_file_info("test.py")
print(f"存在: {exists}, 详情: {details}")

3.3 命名元组 —— 让多返回值更可读

from collections import namedtuple

# 普通多返回值:需要记住位置
def get_user_basic():
    return "张三", 25, "zhangsan@test.com", "北京"

# 调用者需要记住位置:name=0, age=1, email=2, city=3
user = get_user_basic()
print(user[2])  # 这是email还是city?需要查看函数定义才知道

# ✅ 使用命名元组:自带"文档"
UserInfo = namedtuple('UserInfo', ['name', 'age', 'email', 'city'])

def get_user_named():
    return UserInfo("张三", 25, "zhangsan@test.com", "北京")

user = get_user_named()
print(user.name)    # 张三 —— 自文档化!
print(user.email)   # zhangsan@test.com
print(user.age)     # 25

# 仍然支持元组解包
name, age, email, city = get_user_named()
print(name, age, email, city)

四、return的高级特性

4.1 return在生成器中的特殊含义

# 在生成器函数中,return的值会成为StopIteration异常的值

def my_generator():
    yield 1
    yield 2
    yield 3
    return "完成"  # 在生成器中,return的值被"隐藏"了

# 正常迭代看不到return的值
gen = my_generator()
for item in gen:
    print(item, end=' ')  # 1 2 3

# 但是可以通过捕获StopIteration来获取
gen = my_generator()
while True:
    try:
        print(next(gen))
    except StopIteration as e:
        print(f"生成器返回: {e.value}")  # 完成
        break

# 使用yield from时,return的值可以被传递
def outer_generator():
    result = yield from inner_generator()
    print(f"内层生成器返回: {result}")

def inner_generator():
    yield 1
    yield 2
    return "内层完成"

4.2 return None vs 不写return

# 以下三种写法在返回None的意义上等价
# 但语义上有细微差别

# 1. 不写return —— 意味着"返回值不重要"
def set_name(obj, name):
    obj.name = name
    # 不返回任何值(隐式None)

# 2. 写return —— 意味着"在这里显式结束"
def process_if_valid(data):
    if not data:
        return  # 显式提前结束,不返回有用的值
    return process(data)

# 3. 写return None —— 意味着"返回值就是None,注意这一点"
def try_get_value(d, key):
    return d.get(key, None)  # 显式说明可能返回None

# 对于"返回值可能是None"的函数,调用者需要注意
def find_user(user_id):
    # 可能找不到,返回None
    if user_id in database:
        return database[user_id]
    return None  # 显式的None,提示调用者需要处理

# 调用者应该检查
user = find_user(123)
if user is not None:
    print(f"找到: {user['name']}")
else:
    print("用户不存在")

4.3 在finally中谨慎使用return

# ⚠️ finally中的return会覆盖try中的return!

def tricky_return():
    try:
        return "try中的return"
    finally:
        return "finally中的return"  # 这会覆盖上面的return!

print(tricky_return())  # "finally中的return" —— 不是"try中的return"!

# 更清晰的例子
def even_trickier():
    try:
        return 1
    except:
        return 2
    finally:
        return 3  # 无论是try还是except,最终都返回3

print(even_trickier())  # 3

# 📝 建议:finally块中不要使用return
# finally应该用于清理操作,不应该改变函数返回值

五、实战案例

5.1 配置解析器

import json
import os
from typing import Optional, Dict, Any, Tuple

class ConfigParser:
    """配置解析器 —— return的多场景应用"""
    
    @staticmethod
    def parse_json_file(filepath: str) -> Tuple[bool, Optional[Dict], Optional[str]]:
        """解析JSON配置文件
        
        Returns:
            (成功标志, 配置字典, 错误信息)
        """
        if not os.path.exists(filepath):
            return False, None, f"文件不存在: {filepath}"
        
        try:
            with open(filepath, 'r', encoding='utf-8') as f:
                config = json.load(f)
        except json.JSONDecodeError as e:
            return False, None, f"JSON格式错误: {e}"
        except Exception as e:
            return False, None, f"读取文件失败: {e}"
        
        if not isinstance(config, dict):
            return False, None, "配置文件必须是JSON对象"
        
        return True, config, None
    
    @staticmethod
    def get_nested(config: Dict, *keys, default=None):
        """安全获取嵌套配置值
        
        例: get_nested(config, 'database', 'mysql', 'host')
        """
        current = config
        for key in keys:
            if not isinstance(current, dict):
                return default
            if key not in current:
                return default
            current = current[key]
        return current

# 使用
parser = ConfigParser()
success, config, error = parser.parse_json_file("config.json")

if not success:
    print(f"❌ 加载配置失败: {error}")
    config = {}  # 使用空配置

db_host = parser.get_nested(config, "database", "host", default="localhost")
print(f"数据库主机: {db_host}")

5.2 数据验证工具

from dataclasses import dataclass
from typing import List

@dataclass
class ValidationResult:
    """验证结果 —— 替代简单的多返回值"""
    is_valid: bool
    errors: List[str]
    warnings: List[str]

class InputValidator:
    """输入验证器 —— 使用命名返回值"""
    
    @staticmethod
    def validate_email(email: str) -> ValidationResult:
        """验证邮箱地址"""
        errors = []
        warnings = []
        
        if not email:
            errors.append("邮箱不能为空")
            return ValidationResult(False, errors, warnings)
        
        if " " in email:
            errors.append("邮箱不能包含空格")
        
        if "@" not in email:
            errors.append("邮箱必须包含@符号")
        else:
            parts = email.split("@")
            if len(parts) != 2:
                errors.append("邮箱只能包含一个@符号")
            else:
                local, domain = parts
                if not local:
                    errors.append("@前面不能为空")
                if not domain:
                    errors.append("@后面不能为空")
                elif "." not in domain:
                    errors.append("域名必须包含点号")
        
        if len(email) > 254:
            errors.append("邮箱地址过长(超过254个字符)")
        
        if email.lower() != email:
            warnings.append("邮箱包含大写字母(将转为小写处理)")
        
        return ValidationResult(
            is_valid=len(errors) == 0,
            errors=errors,
            warnings=warnings,
        )
    
    @staticmethod
    def validate_password(password: str) -> ValidationResult:
        """验证密码强度"""
        errors = []
        warnings = []
        
        if not password:
            errors.append("密码不能为空")
            return ValidationResult(False, errors, warnings)
        
        if len(password) < 8:
            errors.append("密码长度至少8个字符")
        
        checks = {
            "大写字母": any(c.isupper() for c in password),
            "小写字母": any(c.islower() for c in password),
            "数字": any(c.isdigit() for c in password),
            "特殊字符": any(not c.isalnum() for c in password),
        }
        
        missing = [name for name, ok in checks.items() if not ok]
        if missing:
            errors.append(f"密码缺少: {', '.join(missing)}")
        
        if len(password) > 128:
            warnings.append("密码过长(建议不超过128个字符)")
        
        if errors:
            return ValidationResult(False, errors, warnings)
        
        # 密码强度评分
        score = sum(1 for ok in checks.values() if ok)
        if score >= 4 and len(password) >= 12:
            pass  # 强密码
        elif score >= 3:
            warnings.append("密码强度中等,建议添加更多字符类型")
        else:
            warnings.append("密码强度弱")
        
        return ValidationResult(True, errors, warnings)

# 使用
validator = InputValidator()

email_result = validator.validate_email("Test@Example.com")
print(f"邮箱验证: {'✅' if email_result.is_valid else '❌'}")
for err in email_result.errors:
    print(f"  ❌ {err}")
for warn in email_result.warnings:
    print(f"  ⚠️ {warn}")

pwd_result = validator.validate_password("abc123")
print(f"\n密码验证: {'✅' if pwd_result.is_valid else '❌'}")
for err in pwd_result.errors:
    print(f"  ❌ {err}")

六、本章小结

✅ 本文我们全面掌握了Python函数的return语句:

  1. return的两大作用:终止函数执行 + 返回值给调用者。函数没有return时隐式返回None。

  2. 多返回值:Python的"多返回值"实质是返回一个元组。利用元组解包可以优雅地接收多个值。这是Python相比其他语言的一大便利。

  3. return vs print:print输出到屏幕,不影响返回值。return让值可以被赋值、传递和计算——这是初学者最容易混淆的点。

  4. 高级用法

    • 生成器中的return值通过StopIteration异常传递
    • finally中的return会覆盖try中的return(避免这样做)
    • return可跳出多层嵌套循环(比break更彻底)
  5. 最佳实践

    • 用命名元组或dataclass代替"裸"多返回值,提高可读性
    • 显式return None表示"注意,可能返回None"
    • 函数应该一致地返回相同类型(不要有时返回字符串、有时返回None)

return是函数的"嘴巴"——它决定了函数如何向外部世界"说话"。掌握好return,你的函数才能真正成为可组合、可复用的构建块。⌨️ 从下一篇文章开始,我们将深入学习函数的参数系统——位置参数、关键字参数、默认参数、可变参数等。

到此这篇关于Python函数的返回值return与多返回值的文章就介绍到这了,更多相关Python函数返回值return与多返回值内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文