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

4.7 模块化程序设计.ipynb @masterview markup · raw · history · blame

Notebook

4.8 模块化程序设计

4.8.1 程序设计方法

Python支持__面向对象__的程序设计方法,也支持__面向过程__的程序设计思想。

__面向对象程序设计__的核心是__对象__,是把数据及数据的操作方法放在一起,作为一个相互依存的整体。对同类对象抽象出共性,形成__类__。类中大多数数据,只能用本类的方法进行处理。类通过__接口__与外界发生关系,对象与对象之间通过__消息__进行通信。

__面向对象程序设计__的优点是可扩展性高,适用于用户需求经常变化的场景,如互联网应用、游戏、企业内应用等。其缺点是编程复杂度高,不容易掌握。

__面向过程程序设计__分析出解决问题所需的步骤,然后再用函数把这些步骤一步一步实现,使用时一个一个依次调用即可。面向过程其实是最为实际的一种思考方式,从上往下逐步求精,所以面向过程最重要的思想是模块化设计方法。

当程序规模不是很大时,程序的流程很清楚,按照模块与函数的方法可以很好地组织。对于一般的计算问题和数据处理问题,面向过程的方法会体现出相当的优势。本书的后续内容都是按照面向过程的程序设计思想组织的。

面向过程的程序设计方法,需要合理地应用函数将程序划分为不同的功能单元,分别用不同的函数和模块实现,通过函数的调用和模块的导入实现整体功能。 函数的应用,可以让程序代码扁平化、逻辑更加简单清晰,简化代码的编写、增加代码的可读性和可维护性。

实例4.4 简单计算器

设计一个简单计算器的程序,命名为Calc.py,可以实现简单的加、减、乘、除、整除和幂运算。

In [ ]:
#Calc.py

def add(a,b):      #加法运算函数
    return a + b

def subtract(a,b):      #减法运算函数
    return a - b

def multiply(a,b):      #乘法运算函数
    return a * b

def divide(a,b):      #除法运算函数
    if b == 0:        #考虑0为除数的情况
        return 'Divided by zero'
    else:
        return a / b

def divide_no_remainder(a,b):      #整数除法运算函数
    if b == 0:        #考虑0为除数的情况
        return 'Divided by zero'
    else:
        return a // b

def power(a,b):      # 幂运算函数
    result = 1
    for i in range(1,b+1):
        result = result * a
    return result


if __name__ == '__main__':      #当本文件不作模块,被其它程序导入时,下面的代码会被执行
    m = eval(input())           #输入第一操作数,可以是整数或浮点数
    sign = input()              #输入操作符:"+"、"-" 、"*" 、"/" 、"//"、 "**"
    n = eval(input())           #输入第二操作数,可以是整数或浮点数
    if sign == '+':             #当运算符为*时,调用加法函数
        print(add(m,n))
    elif sign == '-':             #当运算符为-时,调用减法函数
        print(subtract(m,n))
    elif sign == '*':             #当运算符为*时,调用乘法函数
        print(multiply(m,n))
    elif sign == '/':             #当运算符为/时,调用除法函数
        print(divide(m,n))
    elif sign == '//':             #当运算符为//时,调用整除函数
        print(divide_no_remainder(m,n))
    elif sign == '**':             #当运算符为**时,调用幂函数
        print(power(m,n))

从代码量来看,行数有所增加,但从逻辑上看,程序的结构变得更加清晰。每个函数只实现简单的加、减、乘、除、整除和幂运算中的一种功能,主程序只实现输入、判断和输出,根据输入的不同运算符,调用不同的函数进行处理,程序更为扁平、逻辑也更清晰。

4.8.2 模块

通过定义函数的形式将功能封装,可以实现程序设计的模块化。__模块(module)__用来从逻辑上组织Python代码,本质就是扩展名为.py的文件,主文件名为对应的模块名。

Python本身就内置了很多非常有用的模块(__标准库__),这些模块__可以直接使用__。 模块包括标准库、开源模块(第三方库)和自定义模块。

下面的代码导入了__标准库__math模块,使用math模块的pow()进行幂运算。

In [4]:
import math               # 导入math库
print( math.pow( 2, 0.5)) # 使用math库的pow()函数计算2的0.5次幂

Python中除了内置大量的标准库外,还有大量的__第三方库__。这些库__安装后__可以直接使用import导入并使用其中的功能模块,极大地简化了编程难度。

如下假定系统已经安装了名为numpy的第三方库,下面的代码导入该库并使用numpy.linspace()函数生成指定区间内的等差数列。

In [7]:
import numpy as toch             # 导入第三方库numpy,取别名为np

print( np.linspace(0,100,21))  # 生成[0,100]内由21个数构成的等差数列,并输出

若自己定义的函数需要经常被调用,就可以定义一个模块(__自定义模块__),将函数定义写在模块里,下次使用这些函数时先导入这个模块,就可以调用模块中自定义的函数了。

导入模块的方法如下:

In [ ]:
import 模块名 as 模块别名

如果自定义模块与当前程序文件处于同一目录下,则可以使用下面的语句导入模块:

In [ ]:
from 模块名 import 类名或函数名

自定义模块与当前程序文件不在同一目录下时,可以在模块名前加上目录名。

__自定义模块__的方法是把需要反复调用的代码定义为函数,将输入、输出和调用函数的语句放到 if name == 'main': 分支下面。例如,将输出小于n的全部素数的程序定义为一个模块,可以将“例4.2素数函数”里的代码做如下修改后保存为__myPrime.py文件__

In [1]:
#文件 myPrime.py
def is_prime(n):
    """接收正整数n,判断是否为素数,返回布尔值"""
    if n < 2:
        return False       # 0和1不是素数
    for i in range(2, n):  # 遍历2 ~ n-1中的数
        if n % i == 0:     # 若存在因子则不是素数
            return False   # 不是素数时返回False
    else:   # for匹配,当i==2时也进入该子句
        return True        # 素数时返回True


if __name__ == '__main__':
    num = int(input())      # 读入一个正整数
    for i in range(num):    #输出 0 ~ num-1 范围内的素数
        if is_prime(i):   # 调用函数
            print(i,end=' ')
2 3 5 7 

__直接运行myPrime.py文件__ 时,它的 name 属性值为'main',此时执行if name == 'main': 分支里的语句,等待用户输入正整数num,输出小于num的所有素数。

__myPrime.py文件作为模块__ 时,需要导入模块名myPrime,此时它的 name 属性值为模块名,不执行if分支。

用这种方法编写的程序可以作为模块导入,程序中定义的函数可以很方便地被其它程序引用。

将myPrime.py文件放到当前文件夹下,导入myPrime模块,利用其中的is_prime()函数实现:输入n,输出不大于n的所有回文素数。

回文素数:指一个数既是素数又是回文数。例如131,既是回文数又是素数,因此131是一个回文素数。

In [6]:
# 鉴于educoder平台的特点,请先运行本行命令将myPrime.py放到当前文件夹下
!tar -xvf /data/bigfiles/44c570f4-2027-4e63-883c-695a90377873.tar
In [7]:
# 回文素数
# 用户输入一个正整数 n, 在一行内从小到大输出不大于n的回文素数,空格分隔。

import myPrime              #导入当前路径下的myPrime模块

def palindromic(num):
    """接收一个数字为参数,判定其是否为回文数,返回布尔值。"""
    if str(num) == str(num)[::-1]:
        return True
    else:
        return False


def palindromic_prime(number):
    """接收一个正整数参数number,遍历从0到number之间的所有整数,
 若某个数是素数,且转为字符串后是回文字符串,则称其是回文素数。
 找出并在同一行中从小到大输出不大于number的所有回文素数,每个输出后加一个空格,
 函数无返回值。
 """
    for i in range(number + 1 ):  # 遍历小于n的整数
        if palindromic(i) and myPrime.is_prime(i):
            print(i, end=' ')  # i为回文素数时输出i


if __name__ == '__main__':
    n = int(input())
    palindromic_prime(n)
    
    
# 运行时,输入:  200
# 输出:          2 3 5 7 11 101 131 151 181 191 

练一练

将myPrime.py文件放到当前文件夹下,模仿上面的代码,导入myPrime模块分别完成:1. 输出不大于n的所有反素数,2. 验证哥德巴赫猜想(读入偶数n,将其表示为 n = p + q 的形式,其中p、q均为素数)。

提示: 1.反素数:是指一个非回文数,它和它的逆序数同时是素数。例如13,它自身不是回文数,而13和31都是素数。

2. 哥德巴赫猜想:任何一个大于2的偶数,总能表示为两个素数之和

</font>

In [ ]: