30.3.1. 函数的返回值不要超过3个

在返回多个值的时候,可以用带星号的表达式接收那些没有被普通变量捕获到的值

#!/usr/bin/env python
# -*- coding:utf8 -*-
# auther: 18793
# Date:2021/10/26 17:31
# filename: sample01.py

lengths = [63, 73, 83, 33, 43, 53, 72, 82, 19, 70]


def get_avg_ratio(num):
    average = sum(num) / len(num)
    scaled = [x / average for x in num]
    scaled.sort(reverse=True)
    return scaled


longest, *middle, shortest = get_avg_ratio(lengths)

print(f"Longest: {longest:>4.0%}")
print(f"Shortest: {shortest:>4.0%}")

"""
Longest: 140%
Shortest:  32%
"""

假设现在需求又变了,我们这次还想知道平均长度、中位长度(长度的中位数)以及样本的总数。我们可以扩展原有的get_stats函数,让它把这些指标也计算出来,然后一并通过元组返回给调用方,让调用方自己去拆分。

lengths = [63, 73, 83, 33, 43, 53, 72, 82, 19, 70]

def get_stats(num):
    minimum = min(num)
    maximum = max(num)
    count = len(num)
    average = sum(num) / count
    sorted_numbers = sorted(num)
    middle = count // 2
    if count % 2 == 0:
        lower = sorted_numbers[middle - 1]
        upper = sorted_numbers[middle]
        median = (lower + upper) / 2
    else:
        median = sorted_numbers[middle]
    return minimum, maximum, average, median, count


minimum, maximum, average, median, count = get_stats(lengths)
print(f"Min: {minimum},Max:{maximum}")
print(f"Average:{average},Median:{median},Count {count}")

"""
Min: 19,Max:83
Average:59.1,Median:66.5,Count 10
"""

第二个问题是,调用函数并拆分返回值的那行代码会写得比较长,所以按照PEP8风格指南,可能需要折行

(minimum, maximum, average, median, count) = \
    get_stats(lengths)

为避免这些问题,我们不应该把函数返回的多个值拆分到三个以上的变量里。一个三元组最多只拆成三个普通变量,或两个普通变量与一个万能变量(带星号的变量)。当然用于接收的变量个数也可以比这更少。假如要拆分的值确实很多,那最好还是定义一个轻便的类或namedtuple.并让函数返回这样的实例。

要点:

函数可以把多个值合起来通过一个元组返回给调用者,以便利用Python的unpacking机制去拆分。

对于函数返回的多个值,可以把普通变量没有捕获到的那些值全都捕获到一个带星号的变量里。

把返回的值拆分到四个或四个以上的变量是很容易出错的,所以最好不要那么写,而是应该通过小类或namedtuple实例完成。