{
"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
}