python_DAY10

本文详细介绍了Python的模块化编程理念,包括模块、包的使用,以及导入模块的不同方式。强调了模块化编程的优势,如代码复用、可维护性,并通过实例展示了如何设计和使用API。此外,还探讨了导入模块的动态方式和包的导入本质,特别是__init__.py文件的作用。最后,讨论了包内引用和避免使用from...import*的导入方式。
摘要由CSDN通过智能技术生成

一、模块化程序设计理念

1. 语句、函数、模块、包

语句,函数,类 – 文件中的内容 (函数和变量组成了类)
模块 – 文件
包 – 文件夹

2.模块化编程

(1). 为什么需要模块化编程

  • 模块化编程(Modular Programming)将一个任务分解成多个模块。每个模块就像一个积木一样,便于后期的反复使用、反复搭建。
  • 模块化编程有如下几个重要优势:
    (1). 便于将一个任务分解成多个模块,实现团队协同开发,完成大规模程序
    (2). 实现代码复用。一个模块实现后,可以被反复调用。
    (3). 可维护性增强。

(2). 模块化编程的一般流程:

  1. 设计 APII(Application Programming Interface 应用程序编程接口),进行功能描述。
  2. 编码实现 API 中描述的功能。
  3. 在模块中编写测试代码,并消除全局代码。
  4. 使用私有函数实现不被外部客户端调用的模块函数。

(3). 模块的 API 和功能描述要点

  • API(Application Programming Interface 应用程序编程接口)是用于描述模 块中提供的函数和类的功能描述和使用方式描述。
  • 模块化编程中,首先设计的就是模块的 API(即要实现的功能描述),然后开始编 码实现 API 中描述的功能。最后,在其他模块中导入本模块进行调用。
  • 我们可以通过help(模块名)查看模块的API。一般使用时先导入模块 然后通过help函数查看。
#导入 math 模块,并通过 help()查看 math 模块的 API:
import math
help(math)

运行结果:
出现math函数的API(应用程序编程接口),就是math里头有啥就出来啥

(4).设计计算薪水模块的API

#模块名是Salary
'''
本模块用于计算薪水
'''

company = '拜师教育'

def yearSalary(monthSalary):
    '''计算年薪:monthSalary*12'''
    return monthSalary*12

def daySalary(monthSalary):
    '''计算日薪:monthSalary/22.5'''
    return monthSalary/22.5

if __name__=='__main__':  #如果名字就是main 代表着这里是模块本身,不是其他
    print(yearSalary(22500))
    print(daySalary(22500))

运行结果:
270000
1000.0
import Salary

print(Salary.__name__)
print(Salary.__doc__)  #通过 __doc__可以获得文档字符串的内容
print(Salary.yearSalary.__doc__)

运行结果:
Salary    运行结果是Salary说明这是调用的不是模块本省
本模块用于计算薪水
计算年薪:monthSalary*12

二、导入模块

  • 模块化设计的好处之一就是“代码复用性高”。写好的模块可以被反复调用,重复使用。 模块的导入就是“在本模块中使用其他模块”。

1. import语句导入

  • import语句的基本语法格式如下:
    (1)import   模块名       #导入一个模块
    (2)import   模块 1,模块 2…   #导入多个模块
    (3)import   模块名  as 模块别名    #导入模块并使用新名字

  • import 加载的模块分为四个通用类别:
    a.使用 python 编写的代码(.py 文件);
    b.已被编译为共享库或 DLL 的 C 或 C++扩展;
    c.包好一组模块的包
    d.使用 C 编写并链接到 python 解释器的内置模块;

  • 我们一般通过 import 语句实现模块的导入和使用,import 本质上是使用了内置函数 import()。

  • 当我们通过 import 导入一个模块时,python 解释器进行执行,最终会生成一个对象, 这个对象就代表了被加载的模块。

import math

print(id(math))
print(type(math))
print(math.pi)  #通过math.成员名   来访问模块中的成员

运行结果:
2293437643328
<class 'module'>
3.141592653589793
  • 由上,我们可以看到 math 模块被加载后,实际会生成一个 module 类的对象,该对象被 math 变量引用。
  • 我们可以通过 math 变量引用模块中所有的内容。 我们通过 import 导入多个模块,本质上也是生成多个 module 类的对象而已。
  • 有时候,我们也需要给模块起个别名,本质上,这个别名仅仅是新创建一个变量引用加 载的模块对象而已。
#import math as m   #与
import math
m=math              #一样
print(m.sqrt(9))

运行结果:
3.0

2.from…import导入

  • python 中可以使用 from…import 导入模块中的成员。基本语法格式如下:
      from  模块名  import  成员1,成员2,…
  • 如果希望导入一个模块中的所有成员,则可以采用如下方式:
      from  模块名  import  *
    【注】尽量避免“from 模块名 import ”这种写法。 它表示导入模块中所有的不 是以下划线(_)开头的名字都导入到当前位置。 但你不知道你导入什么名字,很有可能 会覆盖掉你之前已经定义的名字。而且可读性极其的差。一般生产环境中尽量避免使用。
#使用 from…import 导入模块指定的成员
from math import pi,sin

print(sin(pi/2))

运行结果:
1.0

3. import 语句和 from…import 语句的区别

  • import 导入的是模块。from…import 导入的是模块中的一个函数/一个类。

我们自定义一个模块 calculator.py:

'''
一个实现四则运算的计算器
'''
def add(a,b):
    return a+b

def minus(a,b):
    return a-b

我们在另一个模块 test.py 测试:

import calculator
a=calculator.add(30,40)  #不加模块名无法识别
print(a)

from calculator import *
a=add(30,40)   #无需模块名,可以直接引用里面的函数/类
print(a)

运行结果:
70

4. import()动态导入

  • import 语句本质上就是调用内置函数__import__(),我们可以通过它实现动态导入。给 import()动态传递不同的的参数值,就能导入不同的模块。
#使用__import__()动态导入指定的模块
t='math'
m=__import__(t)
print(m.pi)

运行结果:
3.141592653589793
  • 一般不建议我们自行使用__import__()导入,其行为在 python2 和 python3 中 有差异,会导致意外错误。如果需要动态导入可以使用 importlib 模块。
import importlib
a=importlib.import_module('math')
print(a.pi)

运行结果:
3.141592653589793

5. 模块的加载问题

  • 当导入一个模块时, 模块中的代码都会被执行。不过,如果再次导入这个模块, 则不会再次执行。
  • 一个模块无论导入多少次,这个模块在整个解释器进程内有且仅有一个实例对象。
    o1.py的源代码
print('o1被加载了')

o2.py的源代码

import o1 #会执行 test02 模块中的语句 #
import o1 #不会再执行 test02 模块中的语句

重新加载
  有时候我们确实需要重新加载一个模块,这时候可以使用:importlib.reload() 方法

import o1
import o1

print('***********')
import importlib
importlib.reload(o1)

运行结果:
o1被加载了
***********
o1被加载了

三、包package的使用

1. 导入包操作和本质

  • 以module_AA.py为例,导入代码如下:
  1. import  a.aa.module_AA  在使用时,必须加完整名称来引用,比如:a.aa.module_AA.fun_AA()
  2. from  a.aa  import  module_AA  在使用时,直接可以使用模块名。 比如:module_AA.fun_AA()
  3. from  a.aa.module_AA  import  fun_AA 直接导入函数 在使用时,直接可以使用函数名。 比如:fun_AA()
  • 【注】
    (1). from package import item 这种语法中,item 可以是包、模块,也可以是函数、 类、变量。
    (2). import item1.item2 这种语法中,item 必须是包或模块,不能是其他。

  • 导入包的本质其实是“导入了包的__init__.py”文件。也就是说,”import pack1”意味 着执行了包 pack1 下面的__init__.py 文件。 这样,可以在__init__.py 中批量导入我们需要 的模块,而不再需要一个个导入。

  • init.py 的三个核心作用:
    (1). 作为包的标识,不能删除。
    (2). 用来实现模糊导入
    (3). 导入包实质是执行__init__.py 文件,可以在__init__.py 文件中做这个包的初始化、以及 需要统一执行代码、批量导入。

  • [示例]测试包的__init__.py 文件本质用法
    a 包下的__init__.py 文件内容:

import turtle
import math

print('导入a包')

b 包下的 module_B1.py 文件中导入 a 包,代码如下:

import a
print(a.math.pi)

运行结果:
导入a包
3.141592653589793

【注】如上测试我们可以看出 python 的设计者非常巧妙的通过__init__.py 文件将包转成了 模块的操作。因此,可以说“包的本质还是模块”。

2. 用 * 导入包

  • import * 这样的语句理论上是希望文件系统找出包中所有的子模块,然后导入它们。 这可能会花长时间等。Python 解决方案是提供一个明确的包索引。
  • 这个索引由 _ init _.py 定义 _ all _ 变量,该变量为一列表,如上例 a 包下的 _ init _.py 中,可定义 _ all _ = [“module_A”,“module_A2”]
  • 这意味着, from sound.effects import * 会从对应的包中导入以上两个子模块;
    【注】尽管提供 import * 的方法,仍不建议在生产代码中使用这种写法。

3. 包内引用

  • 如果是子包内的引用,可以按相对位置引入子模块 以 aa 包下的 module_AA 中导入 a 包下内容为例:
    from … import module_A  #…表示上级目录 .表示同级目录
    from . import module_A2  #.表示同级目录
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值