master
/ 4.7 模块化程序设计.ipynb

4.7 模块化程序设计.ipynb @master

d487d71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4.8 模块化程序设计"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.8.1 程序设计方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python支持<font color=Red>__面向对象__</font>的程序设计方法,也支持<font color=Red>__面向过程__</font>的程序设计思想。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color=Red>__面向对象程序设计__</font>的核心是<font color=Red>__对象__</font>,是把数据及数据的操作方法放在一起,作为一个相互依存的整体。对同类对象抽象出共性,形成<font color=Red>__类__</font>。类中大多数数据,只能用本类的方法进行处理。类通过<font color=Red>__接口__</font>与外界发生关系,对象与对象之间通过<font color=Red>__消息__</font>进行通信。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color=Red>__面向对象程序设计__</font>的优点是可扩展性高,适用于用户需求经常变化的场景,如互联网应用、游戏、企业内应用等。其缺点是编程复杂度高,不容易掌握。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color=Red>__面向过程程序设计__</font>分析出解决问题所需的步骤,然后再用函数把这些步骤一步一步实现,使用时一个一个依次调用即可。面向过程其实是最为实际的一种思考方式,从上往下逐步求精,所以面向过程最重要的思想是模块化设计方法。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当程序规模不是很大时,程序的流程很清楚,按照模块与函数的方法可以很好地组织。对于一般的计算问题和数据处理问题,面向过程的方法会体现出相当的优势。本书的后续内容都是按照面向过程的程序设计思想组织的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "面向过程的程序设计方法,需要合理地应用函数将程序划分为不同的功能单元,分别用不同的函数和模块实现,通过函数的调用和模块的导入实现整体功能。\n",
    "函数的应用,可以让程序代码扁平化、逻辑更加简单清晰,简化代码的编写、增加代码的可读性和可维护性。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font face='楷体' color='red' size=5> 实例4.4 简单计算器 </font>\n",
    "\n",
    "设计一个简单计算器的程序,命名为Calc.py,可以实现简单的加、减、乘、除、整除和幂运算。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Calc.py\n",
    "\n",
    "def add(a,b):      #加法运算函数\n",
    "    return a + b\n",
    "\n",
    "def subtract(a,b):      #减法运算函数\n",
    "    return a - b\n",
    "\n",
    "def multiply(a,b):      #乘法运算函数\n",
    "    return a * b\n",
    "\n",
    "def divide(a,b):      #除法运算函数\n",
    "    if b == 0:        #考虑0为除数的情况\n",
    "        return 'Divided by zero'\n",
    "    else:\n",
    "        return a / b\n",
    "\n",
    "def divide_no_remainder(a,b):      #整数除法运算函数\n",
    "    if b == 0:        #考虑0为除数的情况\n",
    "        return 'Divided by zero'\n",
    "    else:\n",
    "        return a // b\n",
    "\n",
    "def power(a,b):      # 幂运算函数\n",
    "    result = 1\n",
    "    for i in range(1,b+1):\n",
    "        result = result * a\n",
    "    return result\n",
    "\n",
    "\n",
    "if __name__ == '__main__':      #当本文件不作模块,被其它程序导入时,下面的代码会被执行\n",
    "    m = eval(input())           #输入第一操作数,可以是整数或浮点数\n",
    "    sign = input()              #输入操作符:\"+\"、\"-\" 、\"*\" 、\"/\" 、\"//\"、 \"**\"\n",
    "    n = eval(input())           #输入第二操作数,可以是整数或浮点数\n",
    "    if sign == '+':             #当运算符为*时,调用加法函数\n",
    "        print(add(m,n))\n",
    "    elif sign == '-':             #当运算符为-时,调用减法函数\n",
    "        print(subtract(m,n))\n",
    "    elif sign == '*':             #当运算符为*时,调用乘法函数\n",
    "        print(multiply(m,n))\n",
    "    elif sign == '/':             #当运算符为/时,调用除法函数\n",
    "        print(divide(m,n))\n",
    "    elif sign == '//':             #当运算符为//时,调用整除函数\n",
    "        print(divide_no_remainder(m,n))\n",
    "    elif sign == '**':             #当运算符为**时,调用幂函数\n",
    "        print(power(m,n))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "从代码量来看,行数有所增加,但从逻辑上看,程序的结构变得更加清晰。每个函数只实现简单的加、减、乘、除、整除和幂运算中的一种功能,主程序只实现输入、判断和输出,根据输入的不同运算符,调用不同的函数进行处理,程序更为扁平、逻辑也更清晰。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.8.2 模块"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "通过定义函数的形式将功能封装,可以实现程序设计的模块化。<font color=Red>__模块(module)__</font>用来从逻辑上组织Python代码,本质就是扩展名为.py的文件,主文件名为对应的模块名。\n",
    "\n",
    "Python本身就内置了很多非常有用的模块(<font color=Red>__标准库__</font>),这些模块<font color=Red>__可以直接使用__</font>。\n",
    "模块包括标准库、开源模块(第三方库)和自定义模块。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下面的代码导入了<font color=Red>__标准库__</font>math模块,使用math模块的pow()进行幂运算。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import math               # 导入math库\n",
    "print( math.pow( 2, 0.5)) # 使用math库的pow()函数计算2的0.5次幂"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python中除了内置大量的标准库外,还有大量的<font color=Red>__第三方库__</font>。这些库<font color=Red>__安装后__</font>可以直接使用import导入并使用其中的功能模块,极大地简化了编程难度。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如下假定系统已经安装了名为numpy的第三方库,下面的代码导入该库并使用numpy.linspace()函数生成指定区间内的等差数列。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as toch             # 导入第三方库numpy,取别名为np\n",
    "\n",
    "print( np.linspace(0,100,21))  # 生成[0,100]内由21个数构成的等差数列,并输出"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "若自己定义的函数需要经常被调用,就可以定义一个模块(<font color=Red>__自定义模块__</font>),将函数定义写在模块里,下次使用这些函数时先导入这个模块,就可以调用模块中自定义的函数了。\n",
    "\n",
    "导入模块的方法如下:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import 模块名 as 模块别名"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果自定义模块与当前程序文件处于同一目录下,则可以使用下面的语句导入模块:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from 模块名 import 类名或函数名"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "自定义模块与当前程序文件不在同一目录下时,可以在模块名前加上目录名。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color=Red>__自定义模块__</font>的方法是把需要反复调用的代码定义为函数,将输入、输出和调用函数的语句放到 if __name__ == '__main__': 分支下面。例如,将输出小于n的全部素数的程序定义为一个模块,可以将“例4.2素数函数”里的代码做如下修改后保存为<font color=Red>__myPrime.py文件__</font>。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      " 9\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2 3 5 7 "
     ]
    }
   ],
   "source": [
    "#文件 myPrime.py\n",
    "def is_prime(n):\n",
    "    \"\"\"接收正整数n,判断是否为素数,返回布尔值\"\"\"\n",
    "    if n < 2:\n",
    "        return False       # 0和1不是素数\n",
    "    for i in range(2, n):  # 遍历2 ~ n-1中的数\n",
    "        if n % i == 0:     # 若存在因子则不是素数\n",
    "            return False   # 不是素数时返回False\n",
    "    else:   # for匹配,当i==2时也进入该子句\n",
    "        return True        # 素数时返回True\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    num = int(input())      # 读入一个正整数\n",
    "    for i in range(num):    #输出 0 ~ num-1 范围内的素数\n",
    "        if is_prime(i):   # 调用函数\n",
    "            print(i,end=' ')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color=Red>__直接运行myPrime.py文件__</font> 时,它的 __name__ 属性值为'__main__',此时执行if __name__ == '__main__': 分支里的语句,等待用户输入正整数num,输出小于num的所有素数。\n",
    "\n",
    "将<font color=Red>__myPrime.py文件作为模块__</font> 时,需要导入模块名myPrime,此时它的 __name__ 属性值为模块名,不执行if分支。\n",
    "\n",
    "用这种方法编写的程序可以作为模块导入,程序中定义的函数可以很方便地被其它程序引用。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "将myPrime.py文件放到当前文件夹下,导入myPrime模块,利用其中的is_prime()函数实现:输入n,输出不大于n的所有回文素数。\n",
    "\n",
    "<font face='楷体' color='red' size=3> 回文素数:指一个数既是素数又是回文数。例如131,既是回文数又是素数,因此131是一个回文素数。 </font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 鉴于educoder平台的特点,请先运行本行命令将myPrime.py放到当前文件夹下\n",
    "!tar -xvf /data/bigfiles/44c570f4-2027-4e63-883c-695a90377873.tar"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 回文素数\n",
    "# 用户输入一个正整数 n, 在一行内从小到大输出不大于n的回文素数,空格分隔。\n",
    "\n",
    "import myPrime              #导入当前路径下的myPrime模块\n",
    "\n",
    "def palindromic(num):\n",
    "    \"\"\"接收一个数字为参数,判定其是否为回文数,返回布尔值。\"\"\"\n",
    "    if str(num) == str(num)[::-1]:\n",
    "        return True\n",
    "    else:\n",
    "        return False\n",
    "\n",
    "\n",
    "def palindromic_prime(number):\n",
    "    \"\"\"接收一个正整数参数number,遍历从0到number之间的所有整数,\n",
    " 若某个数是素数,且转为字符串后是回文字符串,则称其是回文素数。\n",
    " 找出并在同一行中从小到大输出不大于number的所有回文素数,每个输出后加一个空格,\n",
    " 函数无返回值。\n",
    " \"\"\"\n",
    "    for i in range(number + 1 ):  # 遍历小于n的整数\n",
    "        if palindromic(i) and myPrime.is_prime(i):\n",
    "            print(i, end=' ')  # i为回文素数时输出i\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    n = int(input())\n",
    "    palindromic_prime(n)\n",
    "    \n",
    "    \n",
    "# 运行时,输入:  200\n",
    "# 输出:          2 3 5 7 11 101 131 151 181 191 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font face='楷体' color='red' size=5> 练一练 </font>\n",
    "\n",
    "将myPrime.py文件放到当前文件夹下,模仿上面的代码,导入myPrime模块分别完成:1. 输出不大于n的所有反素数,2. 验证哥德巴赫猜想(读入偶数n,将其表示为 n = p + q 的形式,其中p、q均为素数)。\n",
    "\n",
    "<font face='楷体'> <font color='red' size=3> 提示: </font>\n",
    "    1.反素数:是指一个非回文数,它和它的逆序数同时是素数。例如13,它自身不是回文数,而13和31都是素数。\n",
    "    2. 哥德巴赫猜想:任何一个大于2的偶数,总能表示为两个素数之和\n",
    "</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "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.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}