11. 变量 ========= 11.1 目标 ---------- - 学习编程中使用变量的目的 - 学习使用数字,逻辑变量和字符串 - 学习定义和使用函数并返回值 - 了解全局变量与局部变量的不同 11.2 Karel的成长 ----------------- Karel长大了,它离开父母的家开始实验自己的生活.因此,机器人的家方块不再出现在迷宫中. 另外还有一些其他变化反映Karel的成长 --- 它装备了一个GPS定位器可以确定它在迷宫中的位置, 它可以打印消息,使用变量和列表,利用可以返回值的函数,使用复杂逻辑,使用随机决定等等. 功能函数的完整介绍可以参见 :doc:`第十六部分 ` . 11.3 变量的目的 ---------------- 在编程中,变量用来储存之后可能使用的有用信息. 这些信息有可能是一个数字,一个单词,一句话或者一个逻辑值(`True` 或 `False`). 变量也会很复杂 --- 我们会遇到列表(*list*),它可以储存多个值,比如机器人的路径,宝石的位置等. 11.4 变量的类型 ---------------- 我们每个人都使用变量.一例例子就是我们的名字. :ref:`字符串` 假设你的名字叫"Melissa".当你两岁的时候,你将它存在你的记忆中. 用计算机语言,你定义了一个变量 *my_name* : :: my_name = "Melissa" 变量 *my_name* 储存了这个字符串. :ref:`数值` 之后我们了解到有很多重要的数字,比如 :: seconds_per_minute = 60 而变量 *hours_per_day* 的值是24等等. 但我们同样会使用值不断变化的变量,如 *days_per_year* , *number_of_my_pets* 等. 在Karel中,我们只使用整数(不是一般的实数),因为这个语言的目的不在于解决数学问题. :ref:`逻辑变量` 逻辑变量只能储存两个值, ``True`` 或 ``False``.我们在生活中也经常使用它: :: I_have_a_dog = True I_own_a_car = False 当然,对于不同的人这个变量的值是不同的.逻辑变量和操作将在 :doc:`第十三部分` 详细讨论. 11.5 使用GPS装备和print命令 ---------------------------- Karel可以在任意时刻通过 ``gpsx`` 和 ``gpsy`` 获得自己的坐标. 它还掌握了一项新本领: 通过 ``print`` 命令输出文本消息. 这几个命令的使用方法可以通过下面这个简单例子说明: Karel获取在迷宫中的位置并打印出来 .. figure:: _static/11_01.png :align: center :width: 60% 图1.Karel站在迷宫西南角,坐标为(0,0) 程序如下: :: print"Horizontal position:", gpsx print"Vertical position:", gpsy 输出为 :: Horizontal position: 0 Vertical position: 0 迷宫的宽度为15(东西方向),高度为12(南北方向). 如果Karel站在东北角 .. figure:: _static/11_02.png :align: center :width: 60% 图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的任务是度量和打印输出任意墙的长度. 墙有开头和结尾,但不包含闭循环; 机器人面朝墙的第一块砖,墙总是在它的左边,如图所示: .. figure:: _static/11_03.png :align: center :width: 60% 图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 2. 通过函数 ``gpsx`` . 新变量 *posx* 被创建, 赋予它 ``gpsx`` 的值: :: posx = gpsx 3. 通过函数 ``gpsy`` . 新变量 *posy* 被创建, 赋予它 ``gpsy`` 的值: :: posy = gpsy 4. 通过已存在的变量实例化新变量. 已存在整数变量 *var1*, 那么新变量 *var2* 可以用如下方式创建: :: var2 = var1 5. 通过已知函数的返回值实例化新变量. 使用我们之前定义的函数 ``countsteps`` 定义新变量: :: num = countsteps 11.9 改变数值变量的值 ---------------------- 数值变量的值可以被随时更新, 用上述方法之一. 11.10 使用inc()和dec()函数 --------------------------- Karel根本不懂数学符号 ``+`` 和 ``-`` .但为了计数的需要,它可以分别用函数 ``inc()`` 或 ``dec()`` 来增加或减少整数一个单位. 也可以一次性增加或减少更多的单位, 通过 ``inc(n,num)`` 或 ``dec(n,num)`` 方法. 这里 ``n`` 是变量名称, ``num`` 是一个整数. 11.11 比较运算 --------------- 数字变量可以通过标准算符 ``>`` , ``<`` , ``>=`` , ``<=`` , ``==`` , ``!=`` , ``<>`` 进行比较. 分别读作"大于","小于","大于等于","小于等于","等于","不等于"(后两个符号含义相同). 每次比较的结果是一个逻辑值 ``True`` 或 ``False`` ,可以被用在条件判断,条件循环,或赋予一个变量.如下: :: 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 :: 总之我们应该尽可能多的使用局部变量,这样可使代码更安全和更好的组织.使用全局变量要更加谨慎或避免.