Programmer-defined功能

我们已经看到Python编程的一个重要部分是调用函数来执行计算或执行其他有用的任务。我们使用过的函数示例包括print()和input()。函数对于编程非常有用,因此Python很自然地为我们提供了一种创建自己的函数的方法。

Python中函数定义的基本形式是

Def <name>(<parameter list>): <optional doc string> <statements> <return statement>

下面是一个简单的示例,演示了用户定义函数的赢博体育关键特性。

def square(x): ““”计算参数的平方”“” " result = x*x返回结果

这个示例函数计算并返回一个整数的平方。让我们仔细看看这个函数的组成部分。

函数定义的第一行设置函数的接口,包括它的名称和它接受的参数。

def广场(x):

接口声明告诉我们这个函数的名字是‘square’,它接受一个名为‘x’的参数。函数可以接受任意数量的参数。要设置多个参数,我们只需创建一个以逗号分隔的参数列表。

函数体是缩进部分。代码体包含执行计算并最终返回结果的语句。

函数体的第一行可以是一个可选的doc字符串,它是一些记录函数功能的文本。许多开发环境,如PyCharm,会查找这些文档字符串,并在您将鼠标悬停在函数名称上时显示该文档。对于doc字符串,我们总是使用特殊的Python三引号字符串格式,因为这种格式允许我们构造跨越多行的字符串。

defsquare (x): """square(x)计算它的参数x的平方。它实际上没有什么比这更多的了。当你调用这个函数时,请不要试图传递数字以外的东西。结果将难以预测。”“” result = x*x返回结果

接下来,我们将有一个或多个语句来执行一些计算。通过参数进入函数的输入在这些计算中起作用。

结果= x*x

最后一个语句是return语句,它负责返回计算的结果。

返回结果

函数的附加规则

除了我上面描述的用于定义函数的结构规则之外,在Python程序中使用函数还必须遵循一些额外的规则。

  1. 函数必须在使用之前定义。如果一个函数中的代码想要使用另一个函数,则其他函数定义必须出现在using函数的定义之前。
  2. 您可以在其他函数体中定义函数,但是这些嵌套函数只能在定义它们的其他函数中使用。
  3. 当你调用一个函数时,你必须确保你传递了该函数所需的参数数量。
  4. 一个函数只能返回一个值,尽管在一个函数中可以有多个返回语句。一旦击中return语句之一,就会退出函数体。
  5. 函数名必须是唯一的。不能用相同的名称定义两个函数。

牛顿法

牛顿法是求函数根的一种方法。给定一个可微函数f(x)我们想找到f的一个根,也就是x的一个值使得f(x) = 0。

该方法包括以下步骤:

  1. 选一个点x0接近词根。找到对应的点(x0 , fx0在曲线上。
  2. 在该点上画出曲线的切线,看它与x轴的交点。
  3. 过境点,x1,是你的下一个猜测。从该点开始重复该过程,直到您满意地接近根为止。

数学细节

我们选一个点

(x0, f (x0))

求出该点处的切线方程。切线在这一点的斜率是

切线有一般形式

这条线在y = 0时与x轴相交。

为了重复这个过程,我们只需要将点x1输入到上一个公式中来生成根的下一个近似值

每次我们生成另一个近似值时,我们都可以通过简单地将其代回函数f来轻松地测试该近似值与根的接近程度。一旦|f(xn)|低于预设容差,我们就可以停止迭代。

程序

下面是一个Python程序的代码,该程序使用牛顿方法查找函数的根

F (x) = x4 + 2x3 - 14x2 + 2x + 1

这个函数在0.4附近有一个正的实根。为了找到这个根,我们将写一个函数,它使用函数f(x)及其导数的牛顿迭代

来计算多项式fx),fx)更有效率,我们将使用一个特殊的技巧叫做霍纳氏法则求多项式的值。你知道霍纳法则是怎么运作的吗?

#程序的根f (x) = x ^ 4 + 2 x ^ 3 - 14 x ^ 2 + 2 + 1 #通过牛顿法#定义函数及其导数def f (x):返回(((x + 2) * x-14) * x + 2) * x + 1 def fp (x):返回((4 * x + 6) * x-28) * x + 2 =输入(“输入一个起始猜根:“)x =浮动(x) y = f (x)公差= 10 e-6 y <)或y >公差:#计算f (x) yp = fp (x) #做一个轮牛顿法x = x - y / yp y = f (x)打印(根估计是,x)

从模块导入函数

大多数编程系统都包含有用的函数库,Python也不例外。例如,为了使用标准的数学函数,如exp(x)或sin(x),我们在程序的顶部放置一个import语句来导入数学模块。

导入数学

我们可以使用该模块中的任何函数,如exp()、sin()或sqrt(),只需在其名称前加上我们从其导入的模块的名称。

Print ('exp(3.3) = ',math.exp(3.3))

或者,您可以使用import语句的变体,仅从模块导入特定函数。如果使用这种方法,可以使用这些函数名,而不需要在它们前面加上模块名。

从math导入sin, cos print('sin(1.43) = ',sin(1.43))

编程练习

牛顿法有广泛的赢博体育。在本练习中,我们将最新体育赛事资讯、实时赔率分析及在线投注平台探索其中一个赢博体育程序。

许多数学函数可以在其他函数的基础上计算。一个例子是函数f(x) = ln x。定义自然对数函数的一种方法是将自然对数表示为方程的解。考虑这个等式

X = et

数学上,这个方程的解是t = lnx。

构建一个程序,使用这个方程和牛顿法来计算lnx。下面是你的程序应该做的。

  1. 提示用户输入x的值。
  2. 使用上面的牛顿方法代码来构造一些计算方程x = et的根的代码。
  3. 的值。t牛顿的方法收敛到math.log (x)看看你得到的值有多接近实际值。

构造一个有用的函数:计算exp(x)

作为编写函数的练习,让我们看看是否可以构造自己的函数来计算exp(x)。这样做的关键是exp(x)的幂级数表达式:

这是一个可以计算这个幂级数的函数的初稿。

Def exp1(x): sum = 1对于n在范围(1,16):sum += x**n/math.factorial(n)返回sum

由于幂级数的和是一个无限的和,我们将不得不满足于一个有限的近似。我通过试错法确定了n = 15的截止值,因为这样可以用最少的求和项产生最好的结果。下面是一个简单测试程序的一些输出,它证实了这一点。

Math.exp (0.5)= 2.0137527074704766 exp1(0.5)= 2.0137527074704766 . (0.3)= 1.3498588075760032

接下来,我们介绍一个简单的优化。由于x**n和math.factorial(n)的计算成本都很高,因此我们利用了求和中连续项之间的简单关系。

这意味着我们可以很容易地从它之前的项计算和中的每一个新项。

下面是使用这种优化的exp函数的一个版本。

defexp2 (x): ““”指数函数的更精细的版本。”“” sum = 1 + x term = x,对于range(2,16)中的n: term = term*x/n sum += term返回sum

下面是一个快速的测试运行,以确认这当然产生相同的数值结果与早期的,效率较低的版本。

Math.exp (0.3)= 1.3498588075760032 exp1(0.3)= 1.349858807576003 exp2(0.3)= 1.349858807576003 exp2(0.3)= 2.0137527074704766 exp1(0.5)= 2.0137527074704766 exp2(0.5)= 2.0137527074704766

我们的指数计算函数似乎工作得很好,但它还有最后一个严重的弱点。幂级数近似的问题在于,它们对赢博体育x值的收敛性都不一样。这里有另一个测试表明,当我们代入一个更大的x时,近似会变得更差。

Math.exp (3.3)= 27.112638920657883

当输入x变大时,我们可以通过增加和中的项数来解决这个问题。相反,我要采取另一种策略。由于exp2对于输入x在0到1的范围内似乎做得很好,所以技巧是将给定的任何x映射到该范围内。我们可以通过以下策略做到这一点:

  1. 计算使x/2n < 1的最小幂n。
  2. 计算exp (x / 2 n)。
  3. 请注意,
  4. Exp (x) = Exp (x/2n))2n

  5. 我们可以通过重复平方计算后一个表达式:
  6. (exp(x/2n))2n = (exp(x/2n))2)2n-1

现在是指数计算函数的最终版本它利用了这个策略。

def exp3(x): "“ exp的最终版本-适用于更大范围的x。”“#最初我们使用x的绝对值z = math.fabs(x) #计算最小的n,使z/2**n <= 1 n = 1而z > 1: n += 1 z/ = 2.0 #因为z现在在0 <= z <= 1的范围内,exp2将#做得很好结果= exp2(z) #因为现在结果= exp(z/2**n),为了计算exp(z) #我们现在需要计算结果**(2**n)。我们通过重复平方结果来实现这一点,因为# (result**2)**(2**(n-1)) = result**(2**n)而n > 1: result = result*result n- = 1 #最后,我们处理负x的情况。if(x < 0):返回1/result else:返回结果

一个测试运行证实了这比exp2要好得多:

Math.exp (3.3)= 27.112638920657883 exp2(3.3)= 27.11262722548732 exp3(3.3)= 27.112638920657805

创建和使用模块

当程序变得更大、更复杂时,我们会想要开始将有用的函数组织到模块中,以便导入到程序中。在下一个例子中,我将编写一组处理素数的有用函数,然后将这些函数导入到一个简单的测试程序中。

首先,这是包含有用函数定义的模块:

defisprime (n,known_primes): "“”测试n是否为质数。第二个参数必须是一个质数列表,其中包括赢博体育小于根号n的质数。“”“对于known_primes中的p:如果p*p > n:返回True如果n % p == 0:返回False返回True def primeFactors(n,primes): ”“”计算并返回n的素数因子列表。"“” factors = [] x = n对于素数中的p:而x % p == 0: factors.append(p) x = x//p如果x >: 1: factors.append(x)返回factors deffindprimes (m,n,素数):“”"构造并返回一个小于n的赢博体育素数的列表。素数必须是小于或等于m的素数的种子列表。myprime = prime .copy()对于范围(m,n)中的num:如果isPrime(num, myprime)而不是myprime中的num: myprime .append(num)返回myprime

下面是使用该模块中函数的测试程序。

from prime_stuff import * p = [2,3,5,7] allPrimes = findPrimes(10,100,p) x = int(输入(‘输入2到10000之间的整数:’))如果isPrime(x,allPrimes): print(str(x) + ‘是素数。’)否则:factors = primeFactors(x,allPrimes) print(str(x) + ‘不是素数。’)print(“它的因子是”+ str(factors))