跳转到内容

学习 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。接下来是一个 '(',后面跟着参数 nn 在函数被调用时从程序传递到函数中)。冒号 ':' 后面的语句在函数被使用时执行。这些语句一直持续到缩进的语句结束或遇到 returnreturn 语句将一个值返回到函数被调用的地方。我们已经在我们的第一个程序中遇到了一个函数,即 print 函数。现在我们可以创建新的函数。

注意 ab 的值没有改变。函数可以用来重复不需要返回值的任务。以下是一些示例

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_varb_vard_var 在它们位于函数 a_func 内部时都是局部变量。在语句 return b_var + 10 运行之后,它们都将不再存在。变量 a_var 自动成为局部变量,因为它是一个参数名。变量 b_vard_var 是局部变量,因为它们出现在函数中语句 b_var = 100 + a_vard_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_varb_var 就消失了。然后语句 print("a_var = ", a_var) 打印值 10 而不是值 15,因为隐藏全局变量的局部变量已经消失。

另一件需要注意的是末尾出现的 NameError。这是因为变量 d_var 不再存在,因为 a_func 已结束。所有局部变量在函数退出时都会被删除。如果你想从函数中获取一些东西,那么你必须使用 return something

最后要提醒的一点是,e_var 的值在 a_func 内部保持不变,因为它不是一个参数,而且它从未出现在函数 a_func 内部等号的左侧。当一个全局变量在函数内部被访问时,它是来自外部的全局变量。

函数允许局部变量只存在于函数内部,并且可以隐藏函数外部的其他变量。

函数中的 Linkbot : 使 Linkbot 移动特定距离

[编辑 | 编辑源代码]

我们现在已经了解了可以将数字和变量传递给函数参数。事实证明,你可以将几乎任何东西传递给函数,包括 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()


使用 Linkbot 学习 Python 3
 ← 调试 定义函数 高级函数示例 → 
华夏公益教科书