{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 程序的基本结构(三):逻辑判断与分支" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "如果源代码是我们写出来的故事,那么“逻辑判断与分支”就是故事中的情节编排,是场景之间的关联、排列和衔接——这一点程序和小说、影视剧不那么相近,倒是更像电子游戏。游戏是互动性最强的艺术形式,可以根据玩家的行为走向不同的情节,发生不同的事件和冲突,这种分支多样性极大地增加了表现力和趣味性。\n", "\n", "程序也一样,如果一个程序只能顺序一条一条指令执行,能表达的东西就太少了。我们需要根据输入的不同执行不同的指令,最终给出不一样的结果,这样程序才有价值。所以所有的编程语言都会提供逻辑判断和分支执行的能力。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## if...else 语句" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "所谓分支,其实也很简单,就是“如果这样就 A 否则就 B”,通过这个句式的组合可以实现无穷无尽的变化,这个句式翻译成 Python 的语法就是:\n", "\n", "```python\n", "if X:\n", " A\n", "else:\n", " B\n", "```\n", "\n", "X 是一个“逻辑判断”,其结果要么是真(*True*)要么是假(*False*);A 和 B 是两个代码段(*code block*),分别缩进以表示从属于 `if` 和 `else`。上面的代码意思是:如果 X 是真就执行代码段 A,否则就执行代码段 B。\n", "\n", "Python 还可以连着写好几个 `if`,比如:\n", "\n", "```python\n", "if X:\n", " A\n", "elif Y:\n", " B\n", "else:\n", " C\n", "```\n", "\n", "这里的 `elif` 是 *else if* 的简化写法,整个意思是:如果 X 是真就执行 A(不管 Y 如何),否则继续判断 Y——如果 Y 是真就执行 B,否则就执行 C。\n", "\n", "下面我们重点看看 X、Y 这些所谓“逻辑判断”可以是什么东西。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 逻辑表达式" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "只要最终给出一个逻辑真值或假值的东西都可以算作“逻辑判断”,我们大致分分类可以有这么些:\n", "* 布尔类型的变量或者值,要么是 `True` 要么是 `False`;\n", "* 上一章介绍的**大小比较操作符**的运算结果,例如 `a <= 6` `a + b == c` 这类;\n", "* 返回布尔值的函数,例如我们上一章介绍的 `isinstance()`;\n", "* 上面这些东西通过上一章介绍的**逻辑运算操作符**组合起来,例如 `(a > 1) and (a <= 6)` `isinstance(x, int) or isinstance(x, float)`。\n", "\n", "这些东西通称“逻辑表达式”,因为其结果最终都是一个逻辑真值或者假值,根据其真假 `if...else` 语句就知道到底应该执行哪一个分支。我们来看例子。" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "94 是偶数\n" ] } ], "source": [ "from random import randrange\n", "n = randrange(1, 100)\n", "if n % 2 == 0:\n", " print(n, '是偶数')\n", "else:\n", " print(n, '是奇数')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "上面的代码首先引入 `random` 模块里的一个函数 `randrange()`,然后调用这个函数来生成一个 1~100 之间的随机数并赋给 n——我们先不去细究这里面的东西,知道这个结果就好,关键是下面的 `if...else` 语句:如果 n 除以 2 的余数是 0(还记得上一章我们介绍的整除操作符 `//` 和 `%` 吧),就打印 ‘n 是偶数’,否则打印 ‘n 是奇数’。由于 n 是随机生成的一个数,所以你可以反复多次运行上面这段代码(运行的方法是选择上面这个 *cell*,按 ⌃+回车),看看不同的结果。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "有了逻辑判断和条件分支,我们可以做好多事情了,比如我们可以实现一个算绝对值的函数:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "def abs(x):\n", " if x >= 0:\n", " return x\n", " else:\n", " return -x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "这个函数非常简单,如果是大于等于零的数就直接返回这个数,否则返回它的相反数,我们可以测试下:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "42" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "abs(42)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.14" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "abs(-3.14)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "我们还可以实现一个我们自己的 `type()` 函数,和官方的 `type()` 功能也差不多,即返回一个变量或者值的数据类型:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "def type_0(x):\n", " if isinstance(x, bool):\n", " return 'bool'\n", " elif isinstance(x, int):\n", " return 'int'\n", " elif isinstance(x, float):\n", " return 'float'\n", " elif isinstance(x, str):\n", " return 'str'\n", " else:\n", " return 'unknown'" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'int'" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type_0(42)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'str'" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type_0('abracadabra')" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'bool'" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type_0(False)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'unknown'" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type_0([1, 2, 3])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "最后一个例子显示出我们的 `type_0` 实现和系统的 `type` 还是有点差距,不过没关系,我们才刚开始嘛。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 万物皆为布尔值" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "我们上一节列出了几类逻辑表达式,它们都可以放在 `if` 后面做逻辑判断,但可以放在 `if` 后面的远不止这些,事实上**几乎任何东西**都可以。因为 Python 提供了一组规则来判断一个值“相当于”逻辑真还是假,这种定义是在所谓“合理类比”和方便性的基础上做出的,比如:\n", "* 数字 0 “相当于”假,而其他数字都相当于真;\n", "* 空字符串“相当于”假,非空的字符串“相当于”真。\n", "\n", "其他很多情形也类似,一般来说 0 啊、空啊之类的都“相当于”假,其他就算真了。如果我们搞不清楚某个东西相当于真还是假,可以借助于内置函数 `bool()`,这个函数可以把任何东西变成布尔值(`True` 或者 `False`),下面是一些例子:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "bool(42)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "bool(0)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "bool(0.0)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "bool('')" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "bool('abracadabra')" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "bool('0') # 这是一个非空字符串,不要和 bool(0) 搞混哦~" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "bool([1, 2, 3]) # 和字符串类似,非空列表相当于真,空列表相当于假" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "bool([])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "这种“相当于”的逻辑,可以帮助我们写出更简洁的代码,比如下面两段代码是完全等价的:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "a = 42\n", "if n != 0:\n", " a = a / n" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "a = 42\n", "if n:\n", " a = a / n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "下面两段也完全等价:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdin", "output_type": "stream", "text": [ "请输入您的姓名 \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "姓名不可为空,请重新输入\n" ] } ], "source": [ "s = input('请输入您的姓名')\n", "if s == '':\n", " print('姓名不可为空,请重新输入')" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdin", "output_type": "stream", "text": [ "请输入您的姓名 Neo\n" ] } ], "source": [ "s = input('请输入您的姓名')\n", "if not s:\n", " print('姓名不可为空,请重新输入')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "最后这个例子里的 `input()` 也是 Python 内置函数,它的作用是提示用户输入点什么,并把用户输入的东西作为函数值返回,我们会经常在例子中用到这个东西。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 小结" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 根据一个逻辑判断做分支执行的能力使得计算机程序真正开始变得“智能”,程序中的角色(变量与值)和交互(操作符与函数)通过它才最终编排成有用的东西;\n", "* `if...else` 的语法简单直观,但通过各种逻辑表达式组合可以实现丰富的逻辑选择;\n", "* Python 中的几乎任何值都能转换为布尔值 `True` 或 `False`,`bool()` 函数可以告诉我们特定值对应的是逻辑真还是假。" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.4" } }, "nbformat": 4, "nbformat_minor": 4 }