模块

模块(Module)

在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。

为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。在Python中,一个.py文件就称之为一个模块(Module)。

即:

  • 包含我们定义的函数以及变量的文件,以“.py”为后缀名。
  • 模块可以被其他的程序引用,以使用该模块中的函数或者数据。

模块的优点:

  • 1.提高了代码可维护性
  • 2.提高了代码的复用性
  • 3.可以导入很多功能模块 ( 标准库模块,自定义模块,第三方模块)
  • 4.避免了变量名重复

Python中导入模块的方法的简单形式主要有以下三种:

import 模块名
import模块名 as 新名称
from 模块名 import 函数名

区别 :

  • import 模块名 和import 模块名 as 新名称

    • 会导入整个模块;
    • 如果需要使用其中的某一个函数,必须以"模块名.函数名()"的形式调用函数。(通常这种方法,更有利于增强代码的可读性,优先推荐使用该种方法)
    • import 模块名 as 新名称 用来重新命名导入的模块,已使名称简便,方便使用。
  • from 模块名 import 函数名

    • 只是导入模块中的某一函数,也不是导入整个模块。

    • 可以直接使用函数名称调用函数,无数再在其前加上"模块名"。

    • 可以直接使用函数名称调用函数,无须再在其前加上"模块名"。

      如果程序语句非常多,我们不建议采用"from模块名import函数名"这种方式,因为采用这种方式调用函数时,我们直接使用函数名称调用函数,当程序语句非常多,我们调用了很多模块后,可能造成函数名重名,引发错误,而"模块名.函数名"的方式则会避免这样情况的发生。

例子:

以Python内建的calendar模块为例,其名称为calendar.py,里面定义了一些日历格式。只要使用import指令导入此模块,就可以使用calendar模块了。

  • import…
>>> import calendar#导入calendar模块
>>> print(calendar.month(2019,4))#调用模块中的month()函数
     April 2019
Mo Tu We Th Fr Sa Su
 1  2  3  4  5  6  7
 8  9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30

>>> calendar.isleap(2019)
False
>>>
  • import … as …
>>> import calendar as cal
>>> print(cal.month(2019,4))
     April 2019
Mo Tu We Th Fr Sa Su
 1  2  3  4  5  6  7
 8  9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30

>>> cal.isleap(2019)#判断是否是闰年
False
>>>
  • from … import…
>>> from calendar import month
>>> print(month(2019,4))
     April 2019
Mo Tu We Th Fr Sa Su
 1  2  3  4  5  6  7
 8  9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30

>>> isleap(2019)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'isleap' is not defined
>>>

注意,

  • import 语句的模块顺序:

我们推荐所有的模块在 Python 模块的开头部分导入。 而且最好按照这样的顺序:

  • Python 标准库模块
  • Python 第三方模块
  • 应用程序自定义模块

然后使用一个空行分割这三类模块的导入语句。 这将确保模块使用固定的习惯导入, 有助于减少每个模块需要的 import 语句数目。 其他的提示请参考《 Python 风格指南》(Python’s Style Guide), PEP8 。

  • 限制使用 “from module import *”

在实践中, 我们认为 “from module import *” 不是良好的编程风格, 因为它"污染"当前名称空间, 而且很可能覆盖当前名称空间中现有的名字; 但如果某个模块有很多要经常访问的变量或者模块的名字很长, 这也不失为一个方便的好办法。

我们只在两种场合下建议使用这样的方法, 一个场合是:目标模块中的属性非常多, 反复键入模块名很不方便, 例如 Tkinter (Python/Tk) 和 NumPy (Numeric Python) 模块, 可能还有socket 模块。另一个场合是在交互解释器下, 因为这样可以减少输入次数。

自定义模块

所谓自定义模块就是我们自己动手写的模块(.py文件),既可以是一个解决某个问题的独立程序也可以包含多个函数。

自定义模块的名称就是我们编写的Python程序的名称。

下面给大家举个例子:

在前面的课程中,我们已经接触过斐波那契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

1, 1, 2, 3, 5, 8,13, 21, 34, …

现在我们创建一个名为fibo.py的文件,内容如下:

#程序名称为fibo.py
#斐波拉契数列模块
def fib_01(n):#输出最大数小于n的斐波拉契数列
	i,j=0,1
	while j<n:
		print(j,end=' ')
		i,j =j,i+j
	print()

	
def fib_02(n):#以列表的形式输出最大数小于n的斐波拉契数列
	result=[]
	i,j=0,1
	while j<n:
		result.append(j)
		i,j=j,i+j
	return result



#程序名称为fibo.py
#斐波拉契数列模块
def fib_01(n):#输出最大数小于n的斐波拉契数列
	i,j=0,1
	while j<n:
		print(j,end=' ')
		i,j =j,i+j
	print()

	
def fib_02(n):#以列表的形式输出最大数小于n的斐波拉契数列
	result=[]
	i,j=0,1
	while j<n:
		result.append(j)
		i,j=j,i+j
	return result

#后面加入的话会报错需要导入import importlib
def sumOf2nums(x,y):
	print(x+y)

在当前目录下打开cmd命令窗口。进入Python解释器环境,然后:

>>> import fibo

回车,如果没有报错,恭喜你,已经成功导入这个模块了。但这并不导入fibo中定义的函数的名称,它只进入模块名称fibo。使用模块名称,我们可以访问其中的函数:

>>> import fibo        # 导入模块
>>> fibo.fib_01(100)    # 调用导入模块的函数
1 1 2 3 5 8 13 21 34 55 89
>>> fibo.fib_02(100)    # 调用导入模块的函数
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>>

如果接下来,我们会多次使用fib_01函数,我们可以这样做:

>>> fib = fibo.fib_01
>>> fib(100)
1 1 2 3 5 8 13 21 34 55 89
>>> fib(200)
1 1 2 3 5 8 13 21 34 55 89 144
>>> fib(1000)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>>

reload()

reload() 内建函数可以重新导入一个已经导入的模块。 它的语法如下:

import importlib
importlib.reload(module)

module 是你想要重新导入的模块。使用 reload() 的时候有一些标准。 首先模块必须是全部导入(不是使用 from-import), 而且它必须被成功导入。另外 reload() 函数的参数必须是模块自身而不是包含模块名的字符串。 也就是说必须类似 reload(sys) 而不是 reload(‘sys’)。
模块中的代码在导入时被执行, 但只执行一次,以后执行 import 语句不会再次执行这些代码,只是绑定模块名称。 而 reload() 函数不同。

模块搜索路径

前面我们在导入模块时要求在fibo.py所在路径下打开命令窗口,为什么呢?

一般情况下,Python解释器在运行程序时,在这之前会自动将程序所在的当前目录添加到sys.path路径列表下,然后,优先搜索当前路径下的模块。在Windows系统中,其默认模块搜索路径为Python安装目录及安装目录下的几个子文件夹,我们可以在python解释器环境下,通过以下方式查看:

import sys  #导入sys模块
print(sys.path)#输出当前的模块搜索路径,以列表形式
结果:
['D:\\课程所需软件环境指引\\pythondemo\\py', 'C:\\Users\\acer\\AppData\\Local\\Programs\\Python\\Python36\\python36.zip', 'C:\\Users\\acer\\AppData\\Local\\Programs\\Python\\Python36\\DLLs', 'C:\\Users\\acer\\AppData\\Local\\Programs\\Python\\Python36\\lib', 'C:\\Users\\acer\\AppData\\Local\\Programs\\Python\\Python36', 'C:\\Users\\acer\\AppData\\Local\\Programs\\Python\\Python36\\lib\\site-packages']
[Finished in 0.2s]

如果我们希望不在fibo.py文件所在目录路径下启动cmd命令窗口就可以导入fibo.py模块,我们可以用:

sys.path.append(AddPath)

临时添加fibo.py文件所在目录路径。

现在,打开cmd:

Microsoft Windows [版本 10.0.17134.706]
(c) 2018 Microsoft Corporation。保留所有权利。

C:\Users\acer>python
Python 3.6.6 (v3.6.6:4cf1f54eb7, Jun 27 2018, 03:37:03) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path.append('D:\课程所需软件环境指引\pythondemo\py')
>>> import fibo
>>> fibo.fib_01(100)
1 1 2 3 5 8 13 21 34 55 89
>>>


如果不同的人编写的模块名相同怎么办?为了避免模块名冲突,Python又引入了按目录来组织模块的方法,称为包(Package)

举个例子,一个name1.py的文件就是一个名字叫name1的模块,一个name2.py的文件就是一个名字叫`name12的模块。

现在,假设我们的name1name12这两个模块名字与其他模块冲突了,于是我们可以通过包来组织模块,避免冲突。方法是选择一个顶层包名,比如mycode`,按照如下目录存放:

mycode
├─ __init__.py
├─ name1.py
└─ name2.py

引入了包以后,只要顶层的包名不与别人冲突,那所有模块都不会与别人冲突。现在,name1.py模块的名字就变成了mycode.name1,类似的,name2.py的模块名变成了mycode.name2

请注意,每一个包目录下面都会有一个_init_.py的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录,而不是一个包。__init__.py可以是空文件,也可以有Python代码,因为__init__.py本身就是一个模块,而它的模块名就是mycode。

类似的,可以有多级目录,组成多级层次的包结构。比如如下的目录结构:

mycode
 ├─ web
 │  ├─ __init__.py
 │  ├─ utils.py
 │  └─ www.py
 ├─ __init__.py
 ├─ name1.py
 └─ name2.py

文件www.py的模块名就是mycode.web.www

Notes: 自己创建模块时要注意命名,不能和Python自带的模块名称冲突。例如,系统自带了sys模块,自己的模块就不可命名为sys.py,否则将无法导入系统自带的sys模块。

Python常用内置模块之time、datetime

(1) time模块

在Python中,表示时间通常有以下几种方式:

  • 时间戳(timetamp):通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。如果运行“type(time.time())”,返回的是float类型。
  • 格式化时间字符串(Format String)
  • 结构化的时间(struct_time):struct_time元组中共有9个元素(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)

为方便理解,现在举例说明:

i.时间戳的理解

import time
print(time.time())#1555481671.6814406
time.sleep(1)#程序挂起进程1秒钟
print(time.time())#1555481672.6824892

ii.格式化时间字符串

打印当前电脑系统时间
print(time.strftime("%Y-%m-%d %x"))#2019-04-17 04/17/19
print(time.strftime("%Y-%m-%d %H:%M:%S"))#2019-04-17 14:20:50

iii.结构化的时间

print(time.localtime())#本地时区
time.struct_time(tm_year=2019, tm_mon=4, tm_mday=17, tm_hour=14, tm_min=23, tm_sec=9, tm_wday=2, tm_yday=107, tm_isdst=0)
[Finished in 0.1s]

这里我们可以看出struct_time有9个元素,我们可以通过索引值引用某个值:

print(time.localtime()[3]) # 11

通过以上例子,我们可以看出,时间戳是计算机能够识别的时间;时间字符串是我们人能够看懂的时间;而元组则是用来操作时间的。

几种时间格式的转换:

时间戳和结构化时间的转化

time.gmtime(时间戳) 
# UTC时间,与英国伦敦当地时间一致
time.localtime(时间戳) 
# 当地时间。例如我们现在在北京执行这个方法:与UTC时间相差8小时,UTC时间+8小时 = 北京时间


例子:

print(time.localtime(1500000000))
#time.struct_time(tm_year=2017, tm_mon=7, tm_mday=14, tm_hour=10, tm_min=40, tm_sec=0, tm_wday=4, tm_yday=195, tm_isdst=0)
print(time.gmtime(1500000000))
#time.struct_time(tm_year=2017, tm_mon=7, tm_mday=14, tm_hour=2, tm_min=40, tm_sec=0, tm_wday=4, tm_yday=195, tm_isdst=0)

结构化时间和时间戳的转化

time.mktime(时间戳时间)

demo:

print(time.mktime(time.localtime()))

字符串时间和结构化时间的转化

time.strptime(时间字符串,字符串对应格式)

demo:

print(time.strptime("2018-10-23","%Y-%m-%d"))
#time.struct_time(tm_year=2018, tm_mon=10, tm_mday=23, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=1, tm_yday=296, tm_isdst=-1)
print(time.strptime("10/23/2018","%m/%d/%Y"))
#time.struct_time(tm_year=2018, tm_mon=10, tm_mday=23, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=1, tm_yday=296, tm_isdst=-1)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值