编写高质量Python (第19条) 不要把函数返回的多个数值拆分到三个以上的变量

第 19 条 不要把函数返回的多个数值拆分到三个以上的变量

​ unpacking 机制允许 Python 函数返回一个以上的值(参见 第 6 条)。假设现在要统计一群鳄鱼的各项指标,把每条鳄鱼的体型都保存在列表里面,需要查询列表中最短和最长的鳄鱼。这可以用下面这种写法实现,它可以同时把两个值返回。

def get_status(numbers):
    minimum = min(numbers)
    maximum = max(numbers)
    return minimum, maximum


lengths = [63, 73, 72, 60, 67, 66, 71, 61, 72, 70]

minimum, maximum = get_status(lengths)

print(f'Min: {minimum}, Max: {maximum}')

>>>
Min: 60, Max: 73

​ 函数返回的其实是个元组(tuple),同时返回的那两个值就是元组的两个元素。程序通过把函数返回的元组赋给 minumum 与 maximum 这两个变量来拆解元组,相当于用这两个变量分别接受元组的两个元素。下面举一个更简单的例子,来演示 unpacking 语句和返回多个值的函数是怎样调用的。

first, second = 1, 2
assert first == 1
assert second == 2

def my_function():
	return 1, 2

first, second = my_function()
assert first == 1
assert second == 2

在返回多个值的时候,可以用带星号的表达式接受那些没有被普通变量捕获到的值(参见 第 13 条 )。例如,我们需要写一个函数,用来计算每条鳄鱼的长度与这些鳄鱼的平均长度之比。该函数会把比值放在列表中返回,但我们在接收的时候,可以只接收最长与最短的那两条鳄鱼的比值,而把中间那些鳄鱼的比值用带星号的写法总括。

def get_avg_ratio(numbers):
    average = sum(numbers) / len(numbers)
    scaled = [x / average for x in numbers]
    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: 108%
Shortest: 89%

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

def get_status(numbers):
    minimum = min(numbers)
    maximum = max(numbers)
    count = len(numbers)
    average = sum(numbers) / count

    sorted_numbers = sorted(numbers)
    middle = count // 2
    if count % 2 == 0:
        lower = sorted_numbers[middle - 1]
        higher = sorted_numbers[middle]
        median = (lower + higher) / 2
    else:
        median = sorted_numbers[middle]
    return minimum, maximum, average, median, count

minimum, maximum, average, median, count = get_status(lengths)
print(f'Min: {minimum}, Max: {maximum}')
print(f'Average: {average}, Medain: {median}, Count: {count}')

>>>
Min: 60, Max: 73
Average: 67.5, Medain: 68.5, Count: 10

这样写有两个问题。首先,函数返回的五个值都是数字,所以很容易就会搞错顺序,这样很容易让程序出现 bug。

第二个问题就是,调用函数并拆分返回值的那行代码会写的特别长,所以按照 PEP 8 风格指南,需要折行(参见 第 2 条),这样让代码看着别扭。

minimum, maximum, average, median, count = get_status(
			lengths)

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

(minimum, maximum, average,
median, count) = get_status(lengths)

(minimum, maximum, average, median, count
			)= get_status(lengths)

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

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值