第1关:函数的参数 - 搭建函数房子的砖
任务描述
当我们需要在程序中多次执行同一类型的任务时,不需要反复编写代码段来完成任务,而是可以利用函数工具来大大方便我们的编程工作。函数是可重复使用的,用来实现相关联功能的代码段。
本实训的目标是让读者了解并掌握函数结构的相关知识,本关的小目标则是让读者先了解并掌握函数参数的有关知识。
相关知识
我们在使用函数前,得先定义一个满足自己使用要求的函数。定义函数的基本结构是:
def functionname( parameters ):
"函数_文档字符串"
function_suite
return [expression]
- 定义函数以
def
关键词开头,后面跟着函数名、圆括号()
、括号中的参数、冒号; - 接着,在缩进块中编写函数体,函数的第一行语句一般是写文档字符串,用于存放函数说明,也可以选择不写;
Return[expression]
表示结束函数,并返回值。而不带表达式的return
相当于返回空值。
本关的重点就是研究函数的参数parameters
。定义函数的时候,参数的名字和位置定下来了,函数的接口定义也就完成了。我们在调用函数时,只用知道该传递什么样的参数,函数内部的运行情况已经被封装,使用者不必了解。
Python
的函数参数主要包含以下几种:
- 必选参数;
- 默认参数;
- 可变参数;
- 关键字参数。
必选参数
必选参数也叫位置参数,是函数中最常用的参数,必选参数就是在调用函数的时候必须指定参数值,例如:
#定义加法函数plus,参数a,b就是必选参数
def plus(a,b):
c=a+b
return(c)
#调用函数plus时,必须给参数a,b传递值
d=plus(1,2)
#输出结果d
print(d)
输出结果:
3
如果调用plus
函数时,传入的参数不符合要求,例如:
>>d = plus()
TypeError: plus() missing 2 required positional arguments: 'a' and 'b'
>>d = plus(1)
TypeError: plus() missing 1 required positional argument: 'b'
默认参数
默认参数是指给函数参数提供默认值,如果在调用函数的时候没有给该参数传递值,则该参数使用默认值。例如:
#定义加法函数plus,参数a是必选参数,参数b是默认值2的参数
def plus(a,b=2):
c=a+b
return(c)
#调用函数plus时,必须给参数a传递值,若不给b传递值,则b默认为2
d=plus(1)
#输出结果d
print(d)
从上面的例子可以看出,在函数调用过程中可以不用给默认参数传递参数值。但在使用默认参数时,有两点需要注意:
- 默认参数要放在所有必选参数的后面;
- 默认参数必须指向不变对象。
可变参数
在有些情况下,我们在定义函数的时候,还不能确定函数应该包含多少个参数,这时我们可以使用可变参数,可变参数就是传入的参数数量是可变的。例如:
#定义plus函数,完成的功能是返回输入的整数之和。
# 参数numbers是可变参数,表示输入的参数个数可以为任意值
def plus(*numbers):
add = 0
for i in numbers:
add += i
return(add)
#调用3次plus函数,每次的参数个数都不相同
d1 = plus(1,2,3)
d2 = plus(1,2,3,4)
d3 = plus(1,3,5,7,9)
#向函数中可以传递任意参数,包括0个参数
d4 = plus()
#输出结果
print(d1)
print(d2)
print(d3)
print(d4)
输出结果:
6
10
25
0
在上面的例子中,numbers
就是一个可变参数,可变参数前面加一个标识符*
,在函数内部,可变参数numbers
接收到的值是一个 tuple
。
我们在调用参数是可变参数的函数时,可以给该函数传递任意个数的参数,包括0
个参数。
关键字参数
可变参数允许我们在调用函数时传入任意个参数,这些可变参数在函数调用时自动组装为一个tuple
。
而关键字参数允许我们传入任意个含参数名的参数,这些关键字参数在函数调用时自动组装为一个dict
。也就是说,关键字参数将长度任意的键-值对, 作为参数传递给函数。
#定义一个包含关键字参数的函数,返回值为参数值
def plus(**kw):
return kw
#调用plus函数,参数值为空
d1 = plus()
#调用plus函数,参数值为x=1
d2 = plus(x=1)
#调用plus函数,参数值为x=1,y=2
d3 = plus(x=1, y=2)
#输出d1,d2,d3
print(d1)
print(d2)
print(d3)
输出结果:
{}
{'x': 1}
{'x': 1, 'y': 2}
在上面的例子中,kw
就是一个关键字参数,关键字参数前面加两个*
表示,关键字参数可以扩展函数功能,使传递参数过程更为简便,例如:
#定义一个plus函数,有3个参数,返回值是3个参数之和
def plus(x,y,z):
return x+y+z
#有一个dict列表,当中3个键的值分别为1,2,3
dict = {'x':1, 'y':2, 'z':3}
#将dict列表中的3个值传入plus函数中,得到返回值d
d = plus(dict['x'],dict['y'],dict['z'])
#输出d
print(d)
输出结果:
6
但在上述例子中,将字典中的值向plus
函数中传递参数的方法过于累赘,可以采取关键字参数的方法。例如:
#定义一个plus函数,有3个参数,返回值是3个参数之和
def plus(x,y,z):
return x+y+z
#有一个dict列表,当中3个键的值分别为1,2,3
dict = {'x':1, 'y':2, 'z':3}
#用关键字参数的方法将dict列表中的3个值传入plus函数中,得到返回值d
d = plus(**dict)
#输出d
print(d)
输出结果:
6
使用关键字参数**dict
的方法,可以大大提高参数传递的效率。
参数组合
我们在函数定义过程中,可以同时用到必选参数,默认参数,可变参数,关键字参数中的一种或几种。但是,需要特别注意的是,这四种参数在使用的过程中是有顺序的,顺序依次应该是必选参数、默认参数、可变参数和关键字参数。
例如:
#定义一个包含必选参数、默认参数、可变参数和关键字参数的函数plus
def plus(x, y, z=0, *args, **kw):
print('x=',x)
print('y=',y)
print('z=',z)
print('args=',args)
print('kw=',kw)
#调用函数plus,输入两个参数1,2
plus(1,2)
输出结果:
x= 1
y= 2
z= 0
args= ()
kw= {}
上面这个例子向plus
函数中传入了两个必选参数1
和2
,必选参数是必须得提供值,但是默认参数、可变参数和关键字参数可以不用提供值。
我们还可以给默认参数、可变参数和关键字参数传递值,例如:
定义一个包含必选参数、默认参数、可变参数和关键字参数的函数plus
def plus(x, y, z=0, *args, **kw):
print('x=',x)
print('y=',y)
print('z=',z)
print('args=',args)
print('kw=',kw)
#调用函数plus,输入参数x=1,y=2,z=3,args=(4,5,6),kw={}
plus(1,2,3,4,5,6)
print('\n')
#调用函数plus,输入参数x=1,y=2,z=3,args=(4,5,6),kw={'k':7, 'm':8}
plus(1,2,3,4,5,6,k=7,m=8)
输出结果:
x= 1
y= 2
z= 3
args= (4, 5, 6)
kw= {}
x= 1
y= 2
z= 3
args= (4, 5, 6)
kw= {'k': 7, 'm': 8}
小结
- 不同类型的参数是有顺序的,依次是必选参数、默认参数、可变参数和关键字参数;
- 默认参数一定要用不可变对象,用可变对象容易产生逻辑错误;
*args
表示的是可变参数,*args
接收的是一个元组;**kw
表示的是关键字参数,**kw
接收的是一个字典。
编程要求
本关的编程任务是补全src/Step1/plus.py
文件的代码,实现相应的功能。具体要求如下:
- 定义函数
plus
,功能是对参数(一个列表)中的数值元素进行累加,列表中的元素个数不确定; - 函数返回累加结果。
本关涉及的代码文件src/Step1/plus.py
的代码框架如下:
#coding=uft-8
#创建一个空列表numbers
numbers = []
#str用来存储输入的数字字符串,lst1是将输入的字符串用空格分割,存储为列表
str = input()
lst1 = str.split(' ')
#将输入的数字字符串转换为整型并赋值给numbers列表
for i in range(len(lst1)):
numbers.append(int(lst1.pop()))
# 请在此添加函数plus的代码,函数参数为一个列表
#********** Begin *********#
#********** End **********#
d = plus(numbers)
print(d)
测试说明
本关的测试文件是src/Step1/plus.py
,测试过程如下:
- 平台自动编译生成
plus.exe
; - 平台运行
plus.exe
,并以标准输入方式提供测试输入; - 平台获取
plus.exe
输出,并将其输出与预期输出对比。如果一致则测试通过,否则测试失败。
以下是平台对src/Step1/plus.py
的样例测试集:
测试输入: 1 2 3 4 5
预期输出: 15
测试输入: 1 3 5 7 9 11
预期输出: 36
测试输入: 2 4 6 8 10 12 14 16
预期输出: 72
开始你的任务吧,祝你成功!
明明每天都无所事事,却也感觉不到半点轻松。不如去运动吧
如果你觉得这一关的内容对你有帮助,请你在下面点赞。
代码:
#coding=utf-8
#创建一个空列表numbers
numbers = []
#str用来存储输入的数字字符串,lst1是将输入的字符串用空格分割,存储为列表
str = input()
lst1 = str.split(' ')
#将输入的数字字符串转换为整型并赋值给numbers列表
for i in range(len(lst1)):
numbers.append(int(lst1.pop()))
# 请在此添加函数plus的代码,函数参数为一个列表,对列表中的数值元素进行累加求和
#********** Begin *********#
def plus(numbers):
add=0
for i in numbers:
add+=i
return add
#********** End **********#
#调用plus函数,并将返回结果存储到变量d中
d = plus(numbers)
print(d)
第2关:函数的返回值 - 可有可无的return
任务描述
函数在进行运算处理后,返回的值被称为返回值。函数返回的值是通过return
语句执行。返回值能够让我们直接得到函数处理的结果,而不必关心函数内部复杂繁重的运算过程,大大提高了编程效率。
本关的主要目标是让读者了解并掌握函数返回值的相关知识。
相关知识
return
语句将值返回到调用函数的出口,函数中一定要有return
返回值才是完整的函数。如果我们没有在函数中定义函数返回值,那么程序会自动让函数返回一个结果,该结果是None
对象,而None
对象表示没有任何值。
将值作为返回值
函数的返回值只有一个,但有时我们会发现有的函数好像有多个返回值。其实这里的“多个”并不是多个返回值,比如函数返回一列表,里面包含很多个元素值。这就类似于:只能从超市带走一个箱子,但是允许我们把一些东西都装到箱子里面看做一个东西带走。例如:
def f():
return 1,'abc','1234'
print(f())
输出结果:
(1, 'abc', '1234')
调用f()
函数,程序输出为一个元组,所以函数返回值表面上是3
个值,其实是返回一个元组,元组里面有三个不同元素(元组语法上不需要一定要带上圆括号)。
将函数作为返回值
我们除了可以将各种类型的值作为返回值外,也可以将函数作为返回值。
例如,我们要定义一个函数来求列表中数值元素的和,一般情况下我们是这样定义的:
def plus(*args):
s = 0
for n in args:
s = s + n
return s
但是,如果我们不需要立刻求和,而是在后面的程序中,根据需求再计算怎么办?这时我们定义的函数可以不返回求和的结果,而是返回计算求和的函数!
所以我们还可以用如下方法定义函数:
def lazy_plus(*args):
def plus():
s = 0
for n in args:
s = s + n
return s
return plus
当我们调用lazy_plus()
时,返回的并不是求和结果,而是计算求和的函数:
#定义求和函数,返回的并不是求和结果,而是计算求和的函数
def lazy_plus(*args):
def plus():
s = 0
for n in args:
s = s + n
return s
return plus
#调用lazy_plus()时,返回的并不是求和结果,而是求和函数
f = lazy_plus(1,2,3,4,5)
print(f)
输出结果:
<function lazy_plus.<locals>.plus at 0x000001DAC97F9950>
调用函数f
时,才真正计算求和的结果:
#定义求和函数,返回的并不是求和结果,而是计算求和的函数
def lazy_plus(*args):
def plus():
s = 0
for n in args:
s = s + n
return s
return plus
#调用函数f时,得到真正求和的结果
f = lazy_plus(1,2,3,4,5)
print(f())
输出结果:
15
在上述例子中,我们在函数lazy_plus
中又定义了函数plus
,而且内部函数plus
是可以引用外部函数lazy_plus
的参数和局部变量的,当函数lazy_plus
返回函数plus
时,相关参数和变量也将会保存在返回的函数中,这种方式也称为“闭包(Closure)”
。
小结:我们除了可以将函数计算的值作为返回值外,也可以将函数作为返回值。
如果您想了解更多有关列表操作知识,请参考:
【美】Eric Matthes著《Python编程——从入门到实践》第八章
。
编程要求
本关的编程任务是补全src/step2/return.py
文件的代码,实现相应的功能。具体要求如下:
- 定义一个函数
gcd
,功能是求两个正整数的最大公约数;
本关涉及的代码文件src/step2/return.py
的代码框架如下:
#coding=utf-8
#输入两个正整数a,b
a = int(input())
b = int(input())
# 请在此添加函数gcd代码,求两个正整数的最大公约数
#********** Begin *********#
#********** End **********#
#调用函数,并输出最大公约数
print(gcd(a,b))
测试说明
本关的测试文件是src/step2/return.py
,测试过程如下:
- 平台自动编译生成
return.exe
; - 平台运行
return.exe
,并以标准输入方式提供测试输入; - 平台获取
return.exe
输出,并将其输出与预期输出对比。如果一致则测试通过,否则测试失败。
以下是平台对src/step2/return.py
的样例测试集:
测试输入: 1
8
预期输出: 1
测试输入: 9
3
预期输出: 3
测试输入: 9
21
预期输出: 3
测试输入: 126
36
预期输出: 18
开始你的任务吧,祝你成功!
总有人比自己更优秀、更帅、更春风得意。接受这个现实,但你还是要做自己心中的王。
如果你觉得这一关的内容对你有帮助,请你在下面点赞。
代码:
#coding=utf-8
#输入两个正整数a,b
a = int(input())
b = int(input())
# 请在此添加函数gcd代码,求两个正整数的最大公约数
#********** Begin *********#
def gcd(a,b):
if a<b:
t=a
a=b
b=t
while b:
maxs=a%b
a=b
b=maxs
return a
#********** End **********#
#调用函数,并输出最大公约数
print(gcd(a,b))
第3关:函数的使用范围:Python作用域
任务描述
函数是有使用范围的,在一个模块中,我们可以定义很多函数和变量,但我们希望有的函数和变量别人可以使用,有的函数和变量仅仅可以在模块内部使用。这就是Python
作用域的相关问题。
本关的目标就是让读者了解并掌握函数的使用范围,即Python
作用域的相关知识。
相关知识
在Python
中,正常的函数和变量名是公开的(public
),都是可以被直接引用的,比如:abs()
、abc
、dir()
等。
类似__xxx__
这种格式的变量是特殊变量,允许被直接引用,但是会被用作特殊用途,比如__author__
、__name__
就是属于特殊变量。hello
模块定义的文档注释也可以用特殊变量__doc__
访问,我们自己编程定义的变量一般不会用这种变量名。
类似_xxx
和__xxx
这种格式的函数和变量就是非公开的(private
),不应该被直接引用。
补充:_xxx
的函数和变量是protected
,我们直接从外部访问不会产生异常。__xxx
的函数和变量是private
,我们直接从外部访问会报异常,我们要注意前缀符号的区别。
我们要注意用词的区别,我们说的是private
函数和变量是“不应该”被直接引用,而不是“不能”被直接引用,这是因为在Python
种并没有一种方法可以真正完全限制访问private
函数或变量。但是我们为了养成良好的编程习惯,是不应该引用private
函数或变量的。
private
函数的作用是隐藏函数的内部逻辑,让函数有更好的封装性。
例如:
def _private_1(name):
return 'Hello, %s' % name
def _private_2(name):
return 'Hi, %s' % name
def greeting(name):
if len(name) > 3:
return _private_1(name)
else:
return _private_2(name)
我们在上述程序块里公开了greeting()
函数,greeting()
函数需要使用_private_1()
和_private_2()
函数,读者并不需要知道greeting()
函数中的内部实现细节。所以我们可以将内部逻辑用private
函数隐藏起来。这是一种十分常用的代码封装的方法。
小结:为了让程序的封装性更好,我们一般都限定函数的使用范围,一般我们把外部需要使用的函数定义为public
函数,而把只在内部使用,而外部不需要引用的函数定义成private
函数。
编程要求
本关的编程任务是补全src/step3/scope.py
文件的代码,实现相应的功能。具体要求如下:
- 编写程序,功能是求两个正整数的最小公倍数;
- 要求实现方法:先定义一个
private
函数_gcd()
求两个正整数的最大公约数,再定义public
函数lcm()
调用_gcd()
函数求两个正整数的最小公倍数。
本关涉及的代码文件src/step3/scope.py
的代码框架如下:
#coding=utf-8
#输入两个正整数a,b
a = int(input())
b = int(input())
# 请在此添加一个private函数_gcd()求两个正整数的最大公约数
#********** Begin *********#
#********** End **********#
# 请在此添加一个public函数lcm(),通过调用_gcd()求两个正整数的最小公倍数
#********** Begin *********#
#********** End **********#
#调用函数,并输出a,b的最小公倍数
print(lcm(a,b))
测试说明
本关的测试文件是src/step3/scope.py
,测试过程如下:
- 平台自动编译生成
scope.exe
; - 平台运行
scope.exe
,并以标准输入方式提供测试输入; - 平台获取
scope.exe
输出,并将其输出与预期输出对比。如果一致则测试通过,否则测试失败。
以下是平台对src/step3/scope.py
的样例测试集:
测试输入: 5
6
预期输出: 30
测试输入: 8
10
预期输出: 40
测试输入: 16
24
预期输出: 48
测试输入: 132
214
预期输出: 14124
开始你的任务吧,祝你成功!
路程中会遇到很多很多麻烦困难,我们需要承受,更要去解决,俞敏洪说过一句话:坚持下去,不是我们有足够的坚强,而是我们已经无法选择。
如果你觉得这一关的内容对你有帮助,请你在下面点赞。
代码:
#coding=utf-8
#输入两个正整数a,b
a = int(input())
b = int(input())
# 请在此添加一个private函数_gcd()求两个正整数的最大公约数
#********** Begin *********#
def gcd(a,b):
if a<b:
t=a
a=b
b=t
while b:
maxs=a%b
a=b
b=maxs
return a
#********** End **********#
#请在此添加一个public函数lcm(),在lcm()函数中调用_gcd()函数,求两个正整数的最小公倍数
#********** Begin *********#
def lcm(a,b):
return int(a*b/gcd(a,b))
#********** End **********#
#调用函数,并输出a,b的最小公倍数
print(lcm(a,b))
第4关:函数综合训练※
任务描述
本关任务:利用函数的知识完成如下习题。
相关知识(略)
编程要求
根据提示,在右侧编辑器Begin-End
处补充代码,完成如下要求:
第一题
若三角形的三边分别为a
,b
,c
,令p=(a+b+c)/2
,则该三角形的面积为:
S=p(p−a)(p−b)(p−c)
本题将利用triArea
函数计算如下图阴影部分的面积,并打印出结果。你的任务是编程实现函数triArea(a,b,c)
,利用上述公式计算三角形的面积。
第二题
本题通过编程验证哥德巴赫猜想,即:任何一个大于或等于6的偶数,可以表示成两个素数之和。例如:11111112 = 11 + 11111101
。你的任务:1)编程实现一个函数isPrime(x)
,判断整数x
是否为素数;2)程序将使用函数Goldbach(N)
将整数N
分解成两素数之和以验证哥德巴赫猜想,你需要补充完整该函数代码。
第三题
已知某型迫击炮发射初速度为300m/s
, 炮弹飞行过程中无动力,不考虑空气阻力,重力加速度取9.8m2/s
。在不同的角度下,炮弹落地的时间与飞行的位置都不一样。本题通过编程绘制角度分别为[30, 45, 60, 75]
度时的炸弹轨迹。其中函数calBombT\frace(theta)
计算炮弹飞行过程中n
个位置坐标,时间样本为均匀分配。你的任务是补充完整该程序代码。
计算逻辑示例如下(编程时不需要取整):
当角度为为30
度时,炸弹空中飞行时间约为30.6s
,
若取5
个均匀的时间样本,分别约为[ 0, 7.6, 15.3, 22.9, 30.6 ]
则对应的x
坐标则为[0,1988, 3976, 5964, 7953]
对应的y
坐标则为[ 0, 860,1147, 860, 0 ]
第四题
如图所示,一致函数的方程为
f(x)=exsin(x)
求函数曲线在[0,pi]
区间的长度。 你的任务:1)编写函数f(x)
计算上述函数的值;2)编写函数pt(a, b)
利用勾股定理计算直角三角形的斜边长。
提示:把区间分成n
个小区间,曲线可以近似看成线段。当小区间的区间数量足够多时,近似长度接近真实值。
测试说明
平台会对你编写的代码进行测试: 测试输入:
60
30
预期输出:
24.201994
60 = 7 + 53
[0.0, 158.339198, 316.678395, 475.017593, 633.356791, 791.695989, 950.035186, 1108.374384, 1266.713582, 1425.05278, 1583.391977, 1741.731175, 1900.070373, 2058.409571, 2216.748768, 2375.087966, 2533.427164, 2691.766362, 2850.105559, 3008.444757, 3166.783955, 3325.123153, 3483.46235, 3641.801548, 3800.140746, 3958.479944, 4116.819141, 4275.158339, 4433.497537, 4591.836735]
[0.0, 570.553037, 1100.352285, 1589.397745, 2037.689417, 2445.2273, 2812.011395, 3138.041702, 3423.31822, 3667.84095, 3871.609892, 4034.625045, 4156.88641, 4238.393987, 4279.147775, 4279.147775, 4238.393987, 4156.88641, 4034.625045, 3871.609892, 3667.84095, 3423.31822, 3138.041702, 2812.011395, 2445.2273, 2037.689417, 1589.397745, 1100.352285, 570.553037, 0.0]
l = 15.476558
开始你的任务吧,祝你成功!
代码:
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt #导入matplotlib.pyplot
# 第一题
######## begin ###########
# 请编写函数triArea(a ,b , c),返回三角形的面积
def triArea(a,b,c):
p=((a+b+c)/2)
S=pow(p*(p-a)*(p-b)*(p-c),1/2)
return(S)
######## end #########
S1 = triArea(9.8, 9.3, 6.4)
S2 = triArea(2.9, 4.1, 4.7)
S3 = triArea(2.0, 1.4, 2.3)
print('%.6f' %(S1-S2+S3))
# 第二题
######## begin ###########
# 请编写函数isPrime(x)。判断x是否是素数,返回True或者False
def isPrime(x):
n=0
for i in range(2,x//2):
if x%i==0:
n+=1
if n==0:
return("True")
else:
return("False")
####### end ############
def Goldbach(N): # 将N分解成两素数之和
if N < 6 or N % 2 == 1: # 若N小于6或N为奇数
print('N应该是大于等于6的偶数')
else:
# 循环判断,得到符合要求的小于N的两个素数,并打印
for x in range(2, N // 2): # 想想为什么是从2到N/2
# 调用isPrime函数,得到符合要求的小于N的两个素数
######## begin ###########
if isPrime(x)=="True" and isPrime(N-x)=="True":
######## end ###########
print(N, '=', x, '+', N - x)
break
N = int(input())
Goldbach(N)
# 第三题
# calBombTrace 函数
def calBombTrace(theta):
v0, g, n = 300, 9.8, 30
theta_d = np.radians(theta) #因numpy中cos、sin的输入为弧度值,故先将theta从度转换为弧度
v0_x = v0*np.cos(theta_d) #炮弹水平初速度
v0_y = v0*np.sin(theta_d) #炮弹垂直初速度
tmax = 2*v0_y/g #落地时间,即v0_y*t-0.5gtt=0的解
t = np.linspace(0, tmax, n) #n个时刻
xt = v0_x*t #n个时刻的横坐标
yt = v0_y*t-1/2*g*t**2 #n个时刻的纵坐标
return xt, yt
for theta in [30, 45, 60, 75]:
############ begin #########
# 调用函数,得到theta返回的值,并存储到xt与yt变量
xt,yt=calBombTrace(theta)
########### end #############
plt.plot(xt, yt)
plt.grid('on')
plt.axis([0, 10000, 0, 5000])
plt.savefig('./src/step4/res/轨迹.png')
plt.close()
print([round(x,6) for x in xt])
print([round(x,6) for x in yt])
# 第四题
# 在此添加代码,编写函数f(x),计算f(x)的值
from math import *
########### begin #############
def f(x):
a=((np.e)**x)*(np.sin(x))
return(a)
########### end #############
# 在此添加代码,编写函数pt(a, b),利用勾股定理计算直角三角形的斜边长
########### begin #############
def pt(a, b):
c=pow(a**2+b**2,1/2)
return(c)
########### end ############
n = 1000 # 细分成n个子区间
x = np.linspace(0, np.pi, n + 1) # n个子区间的n+1个端点
l, h = 0, np.pi / n # l为曲线长度、h为子区间宽度
for i in range(n): # 对每个子区间
li = pt(f(x[i + 1]) - f(x[i]), h) # 曲线在第i个子区间的近似长度
l += li # 将航渡累加到l中
print('l = %.6f' %l)