学习 Python 3 与 Linkbot/定义函数
为了开始本章节,我将给你一个示例,它展示了你可能做什么,但你不应该这样做(所以不要输入它)
a = 23
b = -23
if a < 0:
a = -a
if b < 0:
b = -b
if a == b:
print("The absolute values of", a, "and", b, "are equal.")
else:
print("The absolute values of", a, "and", b, "are different.")
输出为
The absolute values of 23 and 23 are equal.
程序看起来有点重复。程序员讨厌重复事物——毕竟,这就是计算机存在的意义!(还要注意,求绝对值改变了变量的值,这就是为什么输出中打印的是 23,而不是 -23。)幸运的是,Python 允许你创建函数来消除重复。以下是重写的示例
a = 23
b = -23
def absolute_value(n):
if n < 0:
n = -n
return n
if absolute_value(a) == absolute_value(b):
print("The absolute values of", a, "and", b, "are equal.")
else:
print("The absolute values of", a, "and", b, "are different.")
输出为
The absolute values of 23 and -23 are equal.
此程序的关键特征是 def
语句。def
(define 的缩写)开始一个函数定义。def
后面跟着函数名 absolute_value
。接下来是一个 '(',后面跟着参数 n
(n
在函数被调用时从程序传递到函数中)。冒号 ':' 后面的语句在函数被使用时执行。这些语句一直持续到缩进的语句结束或遇到 return
。return
语句将一个值返回到函数被调用的地方。我们已经在我们的第一个程序中遇到了一个函数,即 print
函数。现在我们可以创建新的函数。
注意 a
和 b
的值没有改变。函数可以用来重复不需要返回值的任务。以下是一些示例
def hello():
print("Hello")
def area(width, height):
return width * height
def print_welcome(name):
print("Welcome", name)
hello()
hello()
print_welcome("Fred")
w = 4
h = 5
print("width =", w, " height =", h, " area =", area(w, h))
输出为
Hello Hello Welcome Fred width = 4 height = 5 area = 20
该示例展示了你可以用函数做的一些事情。注意你可以使用零个参数或两个或多个参数。还要注意,当函数不需要返回一个值时,return 是可选的。
在消除重复代码时,你经常会在重复代码中使用变量。在 Python 中,这些变量以特殊的方式处理。到目前为止,我们看到的所有变量都是全局变量。函数具有称为局部变量的特殊类型变量。这些变量仅在函数运行期间存在。当一个局部变量与另一个变量(如全局变量)具有相同的名称时,局部变量会隐藏另一个变量。听起来很混乱?好吧,以下这些例子(有点牵强)应该有助于澄清。
a = 4
def print_func():
a = 17
print("in print_func a = ", a)
print_func()
print("a = ", a)
运行后,我们将收到以下输出
in print_func a = 17 a = 4
函数内部的变量赋值不会覆盖全局变量,它们只存在于函数内部。即使 a
在函数内部被赋予了一个新值,这个新赋予的值也只与 print_func
有关,当函数运行结束,a
的值再次被打印出来时,我们看到的是最初赋予的值。
以下是一个更复杂的示例。
a_var = 10
b_var = 15
e_var = 25
def a_func(a_var):
print("in a_func a_var = ", a_var)
b_var = 100 + a_var
d_var = 2 * a_var
print("in a_func b_var = ", b_var)
print("in a_func d_var = ", d_var)
print("in a_func e_var = ", e_var)
return b_var + 10
c_var = a_func(b_var)
print("a_var = ", a_var)
print("b_var = ", b_var)
print("c_var = ", c_var)
print("d_var = ", d_var)
in a_func a_var = 15 in a_func b_var = 115 in a_func d_var = 30 in a_func e_var = 25 a_var = 10 b_var = 15 c_var = 125 d_var = Traceback (most recent call last): File "C:\def2.py", line 19, in <module> print("d_var = ", d_var) NameError: name 'd_var' is not defined
在这个示例中,变量 a_var
、b_var
和 d_var
在它们位于函数 a_func
内部时都是局部变量。在语句 return b_var + 10
运行之后,它们都将不再存在。变量 a_var
自动成为局部变量,因为它是一个参数名。变量 b_var
和 d_var
是局部变量,因为它们出现在函数中语句 b_var = 100 + a_var
和 d_var = 2 * a_var
中等号的左侧。
在函数内部,a_var
没有被赋予任何值。当用 c_var = a_func(b_var)
调用函数时,15 被赋予 a_var
,因为此时 b_var
是 15,使对函数的调用变为 a_func(15)
。最终在 a_func
内部将 a_var
设置为 15。
如你所见,一旦函数运行结束,隐藏了同名全局变量的局部变量 a_var
和 b_var
就消失了。然后语句 print("a_var = ", a_var)
打印值 10
而不是值 15
,因为隐藏全局变量的局部变量已经消失。
另一件需要注意的是末尾出现的 NameError
。这是因为变量 d_var
不再存在,因为 a_func
已结束。所有局部变量在函数退出时都会被删除。如果你想从函数中获取一些东西,那么你必须使用 return something
。
最后要提醒的一点是,e_var
的值在 a_func
内部保持不变,因为它不是一个参数,而且它从未出现在函数 a_func
内部等号的左侧。当一个全局变量在函数内部被访问时,它是来自外部的全局变量。
函数允许局部变量只存在于函数内部,并且可以隐藏函数外部的其他变量。
我们现在已经了解了可以将数字和变量传递给函数参数。事实证明,你可以将几乎任何东西传递给函数,包括 Linkbot 对象。在“决策”这一章中,我们编写了一些可以使双轮 Linkbot 四处移动的代码。在代码中,我们指定了轮子的旋转角度,但如果我们能够告诉 Linkbot 在地面上移动一定的距离,那就酷多了。当你编写新函数时,在实际编写之前,通常需要对函数的使用方式进行原型设计,所以现在就让我们尝试一下。我们希望我们的函数可以用类似于以下方式使用
driveDistance(myLinkbot, 10) # Drive a wheeled Linkbot 10 inches forward
现在我们已经对如何使用我们的函数感到满意,现在我们要担心如何实际编写它,使它能完成我们想要它做的事情。首先,让我们列出我们知道的事情和我们拥有的东西。到目前为止,我们知道可以用两个函数来移动 Linkbot 上的电机:moveJoint()
和 move()
。在这两个函数中,我们发现 move()
可能更适合驱动双轮 Linkbot。但是,move()
函数采用角度作为参数。这留下了问题:如何将距离转换为角度?
事实证明,有一个公式可以用来计算车轮需要转多少度才能行驶一定距离。公式是:
如果你想看看这个公式的推导过程,请点击下面的“推导”链接。
为了解决这个问题,我们可以考虑车轮在表面上的滚动方式。让我们考虑一个在表面上不打滑的轮子,因为这将使我们的计算更容易。让我们考虑一下轮子的“周长”。如果你拿一根绳子,把它绕着圆圈缠绕一圈,绳子的长度就是“周长”。半径为“r”的圆的周长是
下图显示了一个蓝色车轮,上面缠绕着一条绿色绳子。当车轮滚动时,绳子从车轮上展开。
从图中我们可以看出,如果车轮滚动一圈,它就会行驶一个周长的距离。知道一圈是 360 度,我们可以写出比率
所以,如果我们想要行驶一段距离 "distance",我们可以做
使用这个公式,如果我们知道轮子的半径,也知道我们想要行驶的距离,我们就可以计算出轮子需要转动的角度!现在我们可以编写我们的函数了。
注意! 对于数学爱好者,你可能也知道圆的 "弧长" 是
其中 以弧度表示。解出 得到
将 转换为度数,我们得到 这与我们之前的结果完全相同! |
现在,我们可以将该方程式包含在我们的函数中。这使我们能够对任何距离重复使用该函数,而不必一遍又一遍地输入方程式。
import barobo
import math # So that we can use math.pi
dongle = barobo.Dongle()
dongle.connect()
myLinkbot = dongle.getLinkbot('abcd') # Change abcd to your Linkbot's serial ID
def driveDistance(linkbot, distance):
r = 3.5 / 2 # If you have a wheel that's not 3.5 inches in diameter, change "3.5" to the diameter of your wheel
degrees = (360) / (2 * math.pi * r) * distance
linkbot.move(degrees, 0, -degrees)
driveDistance(myLinkbot, 10) # Drives the Linkbot 10 inches forward
driveDistance(myLinkbot, -5) # Drives the Linkbot 5 inches backward
上面显示的程序使用 driveDistance()
函数将机器人向前移动 10 英寸,然后向后移动 5 英寸。你可能想知道为什么我们要费心定义一个函数(它占用 4 行代码),而我们可以不使用函数完成相同的任务。
- 想象一下,如果任务比仅仅两个动作复杂得多。如果你需要让机器人前后移动超过 4 次,那么使用函数实际上可以节省时间和代码。
- 通过复制/粘贴编写重复代码可能非常难以调试。想象一下,如果你为 20 个机器人动作复制粘贴了 20 次方程式,然后你在复制粘贴的代码中发现了一个错误。你需要在所有 20 个粘贴的代码块中纠正这个错误。如果你编写了一个有错误的函数,你只需要修复函数内部的方程式。
- 如果你正在为其他人编写代码,那么将代码封装在函数中是有意义的。想象一下,你正在与一个团队合作,你的工作是编写一个函数来使机器人前后移动,另一个人的工作是编写一个函数来使机器人转弯,而第三个人必须编写一个函数来更改 LED 颜色。然后,你可以将这三个函数放在同一个程序中,并拥有一个能够准确地行驶一定距离、转弯并更改 LED 颜色的机器人。
例子
[edit | edit source]temperature2.py
#! /usr/bin/python
#-*-coding: utf-8 -*-
# converts temperature to Fahrenheit or Celsius
def print_options():
print("Options:")
print(" 'p' print options")
print(" 'c' convert from Celsius")
print(" 'f' convert from Fahrenheit")
print(" 'q' quit the program")
def celsius_to_fahrenheit(c_temp):
return 9.0 / 5.0 * c_temp + 32
def fahrenheit_to_celsius(f_temp):
return (f_temp - 32.0) * 5.0 / 9.0
choice = "p"
while choice != "q":
if choice == "c":
c_temp = float(input("Celsius temperature: "))
print("Fahrenheit:", celsius_to_fahrenheit(c_temp))
choice = input("option: ")
elif choice == "f":
f_temp = float(input("Fahrenheit temperature: "))
print("Celsius:", fahrenheit_to_celsius(f_temp))
choice = input("option: ")
elif choice == "p": #Alternatively choice != "q": so that print when anything unexpected inputed
print_options()
choice = input("option: ")
示例运行
Options: 'p' print options 'c' convert from Celsius 'f' convert from Fahrenheit 'q' quit the program option: c Celsius temperature: 30 Fahrenheit: 86.0 option: f Fahrenheit temperature: 60 Celsius: 15.5555555556 option: q
area2.py
#! /usr/bin/python
#-*-coding: utf-8 -*-
# calculates a given rectangle area
def hello():
print('Hello!')
def area(width, height):
return width * height
def print_welcome(name):
print('Welcome,', name)
def positive_input(prompt):
number = float(input(prompt))
while number <= 0:
print('Must be a positive number')
number = float(input(prompt))
return number
name = input('Your Name: ')
hello()
print_welcome(name)
print()
print('To find the area of a rectangle,')
print('enter the width and height below.')
print()
w = positive_input('Width: ')
h = positive_input('Height: ')
print('Width =', w, ' Height =', h, ' so Area =', area(w, h))
示例运行
Your Name: Josh Hello! Welcome, Josh To find the area of a rectangle, enter the width and height below. Width: -4 Must be a positive number Width: 4 Height: 3 Width = 4 Height = 3 so Area = 12
练习
[edit | edit source]将上面示例中的 area2.py 程序改写为分别使用函数计算正方形面积、矩形面积和圆形面积(3.14 * radius**2
)。此程序应包含一个菜单界面。
def square(side):
return side * side
def rectangle(width , height):
return width * height
def circle(radius):
return 3.14159 * radius ** 2
def options():
print()
print("Options:")
print("s = calculate the area of a square.")
print("c = calculate the area of a circle.")
print("r = calculate the area of a rectangle.")
print("q = quit")
print()
print("This program will calculate the area of a square, circle or rectangle.")
choice = "x"
options()
while choice != "q":
choice = input("Please enter your choice: ")
if choice == "s":
side = float(input("Length of square side: "))
print("The area of this square is", square(side))
options()
elif choice == "c":
radius = float(input("Radius of the circle: "))
print("The area of the circle is", circle(radius))
options()
elif choice == "r":
width = float(input("Width of the rectangle: "))
height = float(input("Height of the rectangle: "))
print("The area of the rectangle is", rectangle(width, height))
options()
elif choice == "q":
print(" ",end="")
else:
print("Unrecognized option.")
options()