11. 变量

11.1 目标

  • 学习编程中使用变量的目的
  • 学习使用数字,逻辑变量和字符串
  • 学习定义和使用函数并返回值
  • 了解全局变量与局部变量的不同

11.2 Karel的成长

Karel长大了,它离开父母的家开始实验自己的生活.因此,机器人的家方块不再出现在迷宫中. 另外还有一些其他变化反映Karel的成长 — 它装备了一个GPS定位器可以确定它在迷宫中的位置, 它可以打印消息,使用变量和列表,利用可以返回值的函数,使用复杂逻辑,使用随机决定等等. 功能函数的完整介绍可以参见 第十六部分 .

11.3 变量的目的

在编程中,变量用来储存之后可能使用的有用信息. 这些信息有可能是一个数字,一个单词,一句话或者一个逻辑值(TrueFalse). 变量也会很复杂 — 我们会遇到列表(list),它可以储存多个值,比如机器人的路径,宝石的位置等.

11.4 变量的类型

我们每个人都使用变量.一例例子就是我们的名字.

字符串

假设你的名字叫”Melissa”.当你两岁的时候,你将它存在你的记忆中.

用计算机语言,你定义了一个变量 my_name :

my_name = "Melissa"

变量 my_name 储存了这个字符串.

数值

之后我们了解到有很多重要的数字,比如

seconds_per_minute = 60

而变量 hours_per_day 的值是24等等.

但我们同样会使用值不断变化的变量,如 days_per_year , number_of_my_pets 等.

在Karel中,我们只使用整数(不是一般的实数),因为这个语言的目的不在于解决数学问题.

逻辑变量

逻辑变量只能储存两个值, TrueFalse.我们在生活中也经常使用它:

I_have_a_dog = True
I_own_a_car = False

当然,对于不同的人这个变量的值是不同的.逻辑变量和操作将在 第十三部分 详细讨论.

11.5 使用GPS装备和print命令

Karel可以在任意时刻通过 gpsxgpsy 获得自己的坐标. 它还掌握了一项新本领: 通过 print 命令输出文本消息. 这几个命令的使用方法可以通过下面这个简单例子说明: Karel获取在迷宫中的位置并打印出来

_images/11_01.png

图1.Karel站在迷宫西南角,坐标为(0,0)

程序如下:

print"Horizontal position:", gpsx
print"Vertical position:", gpsy

输出为

Horizontal position: 0
Vertical position: 0

迷宫的宽度为15(东西方向),高度为12(南北方向). 如果Karel站在东北角

_images/11_02.png

图2.Karel站在迷宫东北角,坐标为(14,11)

那么程序输出为

Horizontal position: 14
Vertical position: 11

将Karel移动到迷宫的其他位置并且重新运行程序,熟悉GPS设备的用法!

print 命令可以用来输出更复杂的语句,其中变量和文本用逗号分割:

print "My GPS coordinates are", gpsx,"and", gpsy

对于上一个迷宫,程序输出:

My GPS coordinates are 14 and 11

11.6 自定义函数

我们可以在命令体中用 return 关键字返回一个值.这种命令被称为函数(function).函数同样用关键字 def 定义.例如,如下函数 countsteps 使机器人走到最近的墙并且返回需要的步数:

def countsteps
  n = 0
  while not wall
    go
    inc(n)
  return n

要注意一些事情:

  • 变量 n 被语句 n = 0 创建并初始化. 在Karel中,我们不需要事先声明变量类型,解释器会根据它首次被赋予的值自动判断其类型.
  • inc() 函数为整数变量的值加1. 同样还有一个函数 dec(),为整数变量的值减1.更多解释参考11.10节.

函数可以被如下使用:

num = countsteps
print "I reached wall in", num,"steps!"

我们首先创建了新的变量 num ,并且用函数 countsteps 返回的整数初始化它.之后打印出结果.

如图2所示情形,将输出:

I reached wall in 11 steps!

11.7 度量墙的长度

这里Karel的任务是度量和打印输出任意墙的长度.

墙有开头和结尾,但不包含闭循环; 机器人面朝墙的第一块砖,墙总是在它的左边,如图所示:

_images/11_03.png

图3.度量任意形状墙的长度

这个问题可以用只有13行的自定义函数 measurewall 完成:

# Function to measure the length
# of an arbitrary wall:
def measurewall
  l = 0
  while wall
    inc(l)
    left
    if not wall
      go
      right
      if not wall
        go
        right
        if not wall
          return l

# Call the function:
print "Length of wall is", measurewall

运行程序后得到输出:

Length of wall is: 53

你不妨试着改变墙的形状,看看此程序是否工作正常.

11.8 创建和实例化数值变量

在Karel中,可以通过多种方式创建和初始化数值变量:

  1. 通过赋予它们整数. 新变量 a 被创建, 给它设为0:
a = 0
  1. 通过函数 gpsx . 新变量 posx 被创建, 赋予它 gpsx 的值:
posx = gpsx
  1. 通过函数 gpsy . 新变量 posy 被创建, 赋予它 gpsy 的值:
posy = gpsy
  1. 通过已存在的变量实例化新变量. 已存在整数变量 var1, 那么新变量 var2 可以用如下方式创建:
var2 = var1
  1. 通过已知函数的返回值实例化新变量. 使用我们之前定义的函数 countsteps 定义新变量:
num = countsteps

11.9 改变数值变量的值

数值变量的值可以被随时更新, 用上述方法之一.

11.10 使用inc()和dec()函数

Karel根本不懂数学符号 +- .但为了计数的需要,它可以分别用函数 inc()dec() 来增加或减少整数一个单位. 也可以一次性增加或减少更多的单位, 通过 inc(n,num)dec(n,num) 方法. 这里 n 是变量名称, num 是一个整数.

11.11 比较运算

数字变量可以通过标准算符 > , < , >= , <= , == , != , <> 进行比较. 分别读作”大于”,”小于”,”大于等于”,”小于等于”,”等于”,”不等于”(后两个符号含义相同). 每次比较的结果是一个逻辑值 TrueFalse ,可以被用在条件判断,条件循环,或赋予一个变量.如下:

a = 1
b = 5
printa < b

输出:

True

代码:

a = 1
b = 5
c = a > b
print c

输出:

False

代码:

a = 0
while a <= 5
  print a
  inc(a)

输出:

0
1
2
3
4
5

11.12 文本字符串

字符串变量的创建和实例化类似于数值变量:

robots_name ="Karel"

它们可以被打印:

print"Robot’s name is", robots_name

输出:

Robot’s name is Karel

一个字符串变量可以用来实例化另一个新变量.比如有人想将机器人命名为”Carlos”(西班牙版本的”Karel”), 并在变量 robots_name_orig 中储存它的的原始名字. 可通过如下方法:

robots_name_orig = robots_name
robots_name = "Carlos"

11.13 局部和全局变量

定义在函数中的变量叫作局部变量,它只能在这个函数内使用. 如果我们试图在函数外使用它,就会抛处错误. 以下代码, 变量 a 定义在函数 myfunction 中, 是局部变量:

def myfunction
  a = 1
  retur

nmyfunction
print a

当运行时,代码抛出如下错误信息:

Unknown variable/procedure "a"

另一方面,在主程序(main)中定义的变量是全局变量.它可以在函数中使用.如下所示:

def myfunction
  print "b =", b
  return

b = 5
myfunction

输出为:

b = 5
总之我们应该尽可能多的使用局部变量,这样可使代码更安全和更好的组织.使用全局变量要更加谨慎或避免.