Python多变量同时赋值——以斐波那契数列为例

1 引入——斐波那契数列

笔者在尝试编写斐波那契数列程序时,看到一个版本的Python实现,代码如下:

n = int(input("需要计算的项数: "))
a = 0
b = 1
for i in range(0,n):
    a, b = b, a + b
    print(a,end=' ')

在这里给不知道斐波那契数列(Fibonacci sequence)的小伙伴科普一下:

斐波那契数列(Fibonacci sequence),因数学家斐波那契以兔子繁殖为例子而引入,指的是这样的数列:

F 0 = 0 F_0=0 F0=0, F 1 = 1 F_1=1 F1=1, F n = F n − 1 + F n − 2   ( n > 1 ) F_n=F_{n-1}+F_{n-2}\ (n>1) Fn=Fn1+Fn2 (n>1)

0 ,   1 ,   1 ,   2 ,   3 ,   5 ,   8 ,   13   , 21 ,   34 ,   55 ⋯ 0,\ 1,\ 1,\ 2,\ 3,\ 5,\ 8,\ 13\ ,21,\ 34,\ 55\cdots 0, 1, 1, 2, 3, 5, 8, 13 ,21, 34, 55

每一个数是前两个数的总和。

这里的赋值语句a, b = b, a + b实现了同时将a+b赋给b,又将原来的b赋给a的功能。

如果将其拆开的直接写成如下代码的话,结果是错误的

b = a + b
a = b

因为通过第一步b = a + b,b的值已经发生了改变,而我需要将原来的b赋值给a,所以发生错误,修改:

b = a + b
a = b - a

但是这样修改不如示例代码简洁,所以我决定研究一下Python对于这种赋值语句的原理。

2 表达式列表

经过查阅Python语言参考文档,我找到了这种表示方法,叫做表达式列表 (Expression list)

文档原文:

6.15. Expression lists

expression_list    ::=  expression ("," expression)* [","]
starred_list       ::=  starred_item ("," starred_item)* [","]
starred_expression ::=  expression | (starred_item ",")* [starred_item]
starred_item       ::=  assignment_expression | "*" or_expr

Except when part of a list or set display, an expression list containing at least one comma yields a tuple. The length of the tuple is the number of expressions in the list. The expressions are evaluated from left to right.

原文代码块使用的是一种BNF范式(Backus-Naur form / Backus normal form),是一种描述计算机语法规则的元语言。Python文档使用的是一种修改的BNF范式,在这里简单介绍一下Python使用的BNF范式语法,帮助大家更好的理解Expression List及相关概念。

BNF范式语法:

  1. 每个规则的开头是规则定义的名称加上 ::= 表示:“被定义为”

  2. 竖线|用来分隔可选项

  3. 星号*用来表示前一项的零次或多次重复

  4. 加号+用来表示前一项的一次或多次重复

  5. 方括号括起[]表示可以出现零次或一次

  6. 圆括号用于分组

  7. 双引号“”括起来的表示括起来的字符本身

介绍完BNF范式语法,看一下expression_list

expression_list    ::=  expression ("," expression)* [","]

可以证明expression_list就是我们想要的形如a, b的形式。

文档中提到:除了作为列表或者集合显示的一部分(例:[2, 3]),包含至少一个逗号的表达式列表会生成一个元组,元组长度为列表中表达式的数量,表达式将从左至右进行求值。

通过代码进行验证:

>>> a = 1
>>> b = 2
>>> a , b
(1, 2)

3 赋值语句

看完了表达式列表,接下来看一下赋值语句 (assignment statements).

文档原文:

An assignment statement evaluates the expression list (remember that this can be a single expression or a comma-separated list, the latter yielding a tuple) and assigns the single resulting object to each of the target lists, from left to right.

表达式列表可以是单一表达式,也可以是逗号分隔的列表(我们着重研究的对象),后者会生成一个元组(这和我们在上文中得到的结论相同),将结果从左到右赋值给目标列表。

对这种赋值方式的详细解释:

Although the definition of assignment implies that overlaps between the left-hand side and the right-hand side are ‘simultaneous’ (for example a, b = b, a swaps two variables), overlaps within the collection of assigned-to variables occur left-to-right, sometimes resulting in confusion.

赋值语句看起来像是右边所有元素同时赋给左边,但实际上赋值是从左至右的。

文档中给出的例子:

x = [0, 1]
i = 0
i, x[i] = 1, 2         # i is updated, then x[i] is updated
print(x)

右侧是一个表达式列表1, 2,赋值给左侧,按照从左至右的顺序进行赋值,

首先将1赋给i,其次将2赋给x[i],因为此时i=1,所以x[1]等于2,所以最终结果为[0, 2]

解释斐波那契数列的例子:

n = int(input("需要计算的项数: "))
a = 0
b = 1
for i in range(0,n):
    a, b = b, a + b
    print(a,end=' ')

以第一次循环为例,a = 0, b = 1,右侧的b, a + b是一个表达式列表,从左到右进行求值并生成一个元组(1, 1),此时右侧的元组中储存的是两个数值,与变量名无关。

按顺序将元组第一个值赋给a,第二个值赋给b,完成赋值语句。

通过这样的赋值语句,成功将原来的b赋给a,将a + b赋给b,而没有发生冲突。


本文是本人通过查找阅读Python文档得出的结论,如有不正之处,欢迎大家批评指正。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值