声明式编程
许多初学者期望 Python 能够以这种方式工作,但事实并非如此。更糟糕的是,他们可能不一致地期望它能这样工作。仔细考虑示例中的这一行:
x = x * 2
如果作业就像数学公式,我们必须解决x
这里。唯一可能的(数字)值x
将为零,因为任何其他数字都不等于该数字的两倍。我们应该如何解释代码前面所说的事实x = 1
?这不是矛盾吗?我们是否应该在尝试定义时收到错误消息x
两种不同的方式?或者期待x
爆炸到无穷大,因为程序不断尝试将旧值加倍x
当然,这些事情都不会发生。与大多数常用的编程语言一样,Python 是陈述性的语言,意味着代码行描述actions以定义的顺序发生。存在循环的地方,重复循环内的代码;哪里有类似的东西if
/else
,某些代码可能会被跳过;但一般来说,同一“块”中的代码只是按照编写的顺序发生。
在示例中,首先x = 1
发生,所以x
等于1
. Then y = x + 2
发生,这使得y
等于3
暂且。这发生过因为任务,而不是因为x
有一个价值。因此,当x
稍后在代码中进行更改,即does not cause y
改变。
顺应(控制)流程
那么,我们如何制作y
改变?最简单的答案是:与我们最初赋予它这个值的方式相同 - 通过任务, using =
。事实上,思考x = x * 2
再次编码,我们已经看过了这个怎么做。
在示例代码中,我们想要y
多次更改 - 每次循环一次,因为那是print(y)
发生。应该赋予什么值?这取决于x
- the current的价值x
在这个过程中的那个时刻,这是通过使用...确定的x
。就像怎样x = x * 2
检查现有值x
,将其加倍,并且changes x
达到翻倍的结果,所以我们可以写y = x + 2
检查现有值x
,添加两个,然后更改y
成为新的价值。
Thus:
x = 1
for _ in range(5):
x = x * 2
y = x + 2
print(y)
唯一改变的是这条线y = x + 2
现在在循环内。我们希望每次更新都会发生x = x * 2
发生后,立即发生(即,以便及时进行更改print(y)
)。所以,这直接告诉我们代码需要去哪里。
def
建立关系
假设程序中有多个地方x
变化:
x = x * 2
y = x + 2
print(y)
x = 24
y = x + 2
print(y)
最终,记住更新会变得很烦人y
在每行代码发生变化之后x
。它也是潜在的错误来源,随着程序的增长,这种情况会变得更糟。
在原始代码中,编写背后的想法y = x + 2
was to 表达一种关系之间x
and y
:我们希望代码能够处理y
就好像它的意思是一样的x + 2
,它出现的任何地方。用数学术语来说,我们想要处理y
as a 的函数 x
.
在 Python 中,像大多数其他编程语言一样,我们使用称为“函数”的东西来表达函数的数学概念。具体来说,在 Python 中,我们使用def
函数来编写函数。看起来像:
def y(z):
return z + 2
我们可以在函数中编写我们喜欢的任何代码,并且当函数被“调用”时,该代码将运行,就像我们现有的“顶级”代码运行一样。当Python第一次遇到以def
不过,它仅从该代码创建一个函数 - 它尚未运行该代码。
所以,现在我们有一个名为y
,这是一个函数,它接受一些z
价值并回馈(即return
是)计算的结果z + 2
。我们可以通过写类似的方式来调用它y(x)
,这将给我们现有的x
值和评估为该值加 2 的结果。
请注意,z
这是函数自己的值的名称已传入,并且它不必匹配我们为该值命名。事实上,我们根本不必为该值指定自己的名称:例如,我们可以编写y(1)
,该函数将计算3
.
我们所说的“评估”、“回馈”或“return
ing”?简单来说,调用该函数的代码就是一个表达, 就像1 + 2
,并且当计算该值时,它会以相同的方式就地使用。所以,举例来说,a = y(1)
将使a
等于3
:
- 该函数接收一个值
1
,称之为z
内部。
- 该函数计算
z + 2
, i.e. 1 + 2
,得到结果 3。
- 功能
return
是的结果3
.
- 这意味着
y(1)
评估为 3
;因此,代码的执行就好像我们已经输入了3
哪里的y(1)
is.
- 现在我们有相当于
a = 3
.
有关使用函数的更多信息,请参阅如何从函数中获取结果(输出)?以后如何使用结果?.
回到本节的开头,因此我们可以使用以下调用y
直接为我们的print
s:
x = x * 2
print(y(x))
x = 24
print(y(x))
我们不需要“更新”y
when x
变化;相反,我们确定值使用时间和地点。当然,从技术上来说我们无论如何都可以做到这一点:重要的是y
在实际用于某事的地方是“正确的”。但是通过使用该函数,逻辑x + 2
计算被打包、命名并放在一个地方。我们不需要写x + 2
每次。在这个例子中看起来微不足道,但是y(x)
无论计算多么复杂,只要x
是唯一需要的输入。计算只需要写一次:在函数定义中,其他一切都只是说y(x)
.
也可以使y
函数使用x
值直接来自我们的“顶级”代码,而不是显式传递它。这可能很有用,但在一般情况下它会变得复杂,并且会使代码更难理解并且容易出现错误。为了正确理解,请阅读在函数中使用全局变量 and 范围规则的简短描述?.