自定义模块
自定义模块
什么是模块:
模块是一系列常用功能的集合体,一个py文件就是一个模块
一个函数封装一个功能,比如现在有一个软件,不可能将所有程序都写入一个文件,所以咱们应该分文件,组织结构要好,代码不冗余,所以要分文件,但是分文件,分了5个文件,每个文件里面可能都有相同的功能(函数),怎么办?所以将这些相同的功能封装到一个文件中.
模块就是文件,存放一堆函数,谁用谁拿。怎么拿?
为什么要使用模块?
1.从文件级别组织程序,更方便管理
随着程序的发展,功能越来越多,为了方便管理,我们通常将程序分成一个个的文件,这样做程序的结构更清晰,方便管理。这时我们不仅仅可以把这些文件当做脚本去执行,还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用
2.拿来主义,提升开发效率
同样的原理,我们也可以下载别人写好的模块然后导入到自己的项目中使用,这种拿来主义,可以极大地提升我们的开发效率,避免重复造轮子。
ps:
如果你退出python解释器然后重新进入,那么你之前定义的函数或者变量都将丢失,因此我们通常将程序写到文件中以便永久保存下来,需要时就通过python meet.py方式去执行,此时meet.py被称为脚本script.
导入
import翻译过来是一个导入的意思
模块可以包含可执行的语句和函数的定义,这些语句的目的是初始化模块,它们只在模块名第一次遇到导入import语句时才执行 (import语句是可以在程序中的任意位置使用的,且针对同一个模块很import多次,为了防止你重复导入,python的优化手段是: 第一次导入后就将模块名加载到内存了,后续的import语句仅是对已经加载到内存中的模块对象增加了一次引用,不会重新执行模块内的语句), 如下 import spam #只在第一次导入时才执行meet.py内代码,此处的显式效果是只打印一次'from the meet.py',当然其他的顶级代码也都被执行了, 只不过没有显示效果.
多个引入模块
import meet
import meet
import meet
执行结果:只打印一次
from the meet.py
每个模块都是一个独立的名称空间,定义在这个模块中的函数,把这个名称空间
为模块起别名
别名其实就是一个绰号,好处可以将很长的模块名改成很短,方便使用
import meet.py as t t.read1()
别名有利于代码的扩展和优化
#mysql.py def sqlparse(): print('from mysql sqlparse') #oracle.py def sqlparse(): print('from oracle sqlparse') #test.py db_type=input('>>: ') if db_type == 'mysql': import mysql as db elif db_type == 'oracle': import oracle as db db.sqlparse()
导入多个模块
import os,sys,json 这样写可以但是不推荐
推荐写法
import os
import sys
import json
多行导入:易于阅读,易于编辑,易于搜索,易于维护
from..import
from mm002 import read1 read1()
from..import..与import对比
唯一的区别就是,使用from...import..则是将spam中的名字直接导入到当前的名称空间中,所以在当前名称空间中直接使用名字可以了,无需加前缀:meet
from..import..的方式有好处也有坏处
好处:使用起来方便了
坏处:容易与当前执行文件中的名字冲突
执行文件有与模块同名的变量或者函数名,会有覆盖效果
from导入的模式也支持as
from meet import read1 as read read()
from导入的时侯,一行导入多个内容
from meet import read1,read2,name
全部导入
from meet import*
#from spam import * 把spam中所有的不是以下划线(_)开头的名字都导入到当前位置 #大部分情况下我们的python程序不应该使用这种导入方式,因为*你不知道你导入什么名字,很有可能会覆盖掉你之前已经定义的名字。而且可读性极其的差,在交互式环境中导入时没有问题。
可以用__all__来控制*(用来发布新版本),在背调用的文件中新增一行
__all__=['money','read1'] #这样在另外一个文件中用from spam import *就这能导入列表中规定的两个名字
模块循环导入问题
模块循环/嵌套导入抛出异常的根本原因是由于在python中模块被导入一次之后们就不会重新调导入,值是会在第一次导入时执行模块内代码
在我们的项目中应该尽量避免出现循环/嵌套导入,如果出现多个模块都需要共享的数据,可以将共享的数据集中存放到某一个地方
在程序出现了循环/嵌套导入后的异常分析、解决方法如下(了解,以后尽量避免)
模块的重载(了解)
考虑到性能的原因,每个模块只被导入一次,放入字典sys.module中,如果你改变了模块的内容,你必须重启程序,python不支持重新加载或卸载之前导入的模块,
有的同学可能会想到直接从sys.module中删除一个模块不就可以卸载了吗,注意了,你删了sys.module中的模块对象仍然可能被其他程序的组件所引用,因而不会被清楚。
特别的对于我们引用了这个模块中的一个类,用这个类产生了很多对象,因而这些对象都有关于这个模块的引用。
py文件的两种功能
编写好的一个python文件可以两种用途:
一:脚本,一个文件就是整个程序,用来被执行
二:模块,文件中存放着一堆功能,用来被导入使用
python位我们内置全局变量__name__
当文件被当做脚本执行时:__name__等于'__main__'
当文件被当做模块导入时:__name__等于模块名
作用:用来控制.py文件在不同的应用场景下执行不同的逻辑(或者是在模块文件中测试代码)
if __name__=='__main__':
x.py from run import run run() run def run(): print("run") if __name__=='__main__': run()
在模块文件中测试run()函数
此函数被导入时__name__就变成了文件名,if条件成立
所以run执行,若不成立则不执行
模块的搜索路径
模块的查找顺序是:内存中已经加载的模块-->内置模块-->sys.apth路径中包含的模块
模块的查找顺序
1、在第一次导入某个模块时(比如spam),会先检查该模块是否已经被加载到内存中(当前执行文件的名称空间对应的内存),如果有则直接引用 ps:python解释器在启动时会自动加载一些模块到内存中,可以使用sys.modules查看
2、如果没有,解释器则会查找同名的内建模块
3、如果还没有找到就从sys.path给出的目录列表中依次寻找spam.py文件。
需要特别注意的是:我们自定义的模块名不应该与系统内置模块重名。虽然每次都说,但是仍然会有人不停的犯错。
修改加载顺序sys.path.insert()
在初始化后,python程序可以修改sys.path,路径放到前面的优先于标准库被加载。
>>> import sys >>> sys.path.append('/a/b/c/d') >>> sys.path.insert(0,'/x/y/z') #排在前的目录,优先被搜索
注意:搜索时按照sys.path中从左到右的顺序查找,位于前的优先被查找.
#windows下的路径不加r开头,会语法错误 sys.path.insert(0,r'C:\Users\Administrator\PycharmProjects\a')
编译Python文件(了解)
为了提高加载模块的速度,强调强调强调:提高的是加载速度而绝非运行速度。python解释器会在__pycache__目录中下缓存每个模块编译后的版本,格式为:module.version.pyc。通常会包含python的版本号。例如,在CPython3.3版本下,spam.py模块会被缓存成__pycache__/spam.cpython-33.pyc。这种命名规范保证了编译后的结果多版本共存。
Python检查源文件的修改时间与编译的版本进行对比,如果过期就需要重新编译。这是完全自动的过程。并且编译的模块是平台独立的,所以相同的库可以在不同的架构的系统之间共享,即pyc使一种跨平台的字节码,类似于JAVA火.NET,是由python虚拟机来执行的,但是pyc的内容跟python的版本相关,不同的版本编译后的pyc文件不同,2.5编译的pyc文件不能到3.5上执行,并且pyc文件是可以反编译的,因而它的出现仅仅是用来提升模块的加载速度的,不是用来加密的。
#提示: 1.模块名区分大小写,foo.py与FOO.py代表的是两个模块 2.在速度上从.pyc文件中读指令来执行不会比从.py文件中读指令执行更快,只有在模块被加载时,.pyc文件才是更快的 3.只有使用import语句是才将文件自动编译为.pyc文件,在命令行或标准输入中指定运行脚本则不会生成这类文件.
time模块
time翻译过来就是时间,
常用方法 1.time.sleep(secs) (线程)推迟指定的时间运行。单位为秒。 2.time.time() 获取当前时间戳
在计算中时间共有三种方式:
1.时间戳:通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的便宜量.我们运行"type(time.time())",返回的是float类型
2.格式化字符串时间:格式化的时间字符串(Format String):'1992-02-06'
python中时间日期格式化符号: %y 两位数的年份表示(00-99) %Y 四位数的年份表示(000-9999) %m 月份(01-12) %d 月内中的一天(0-31) %H 24小时制小时数(0-23) %I 12小时制小时数(01-12) %M 分钟数(00=59) %S 秒(00-59) %a 本地简化星期名称 %A 本地完整星期名称 %b 本地简化的月份名称 %B 本地完整的月份名称 %c 本地相应的日期表示和时间表示 %j 年内的一天(001-366) %p 本地A.M.或P.M.的等价符 %U 一年中的星期数(00-53)星期天为星期的开始 %w 星期(0-6),星期天为星期的开始 %W 一年中的星期数(00-53)星期一为星期的开始 %x 本地相应的日期表示 %X 本地相应的时间表示 %Z 当前时区的名称 %% %号本身
3.结构化时间:元祖(struct_time)struct_time元组共有9个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天等)
导入time模块
导入时间模块 import time 时间戳 print(time.time()) 1547554922.2864077
时间字符串
print(time.strftime("%Y-%m-%d %X")) 2019-01-15 20:23:42
print(time.strftime("%Y-%m-%d %H-%M-%S"))
2019-01-15 20-26-29
时间元祖:localtime将一个时间戳转换为当前时区的struct_time
print(time.localtime()) time.struct_time(tm_year=2019, tm_mon=1, tm_mday=15, tm_hour=20, tm_min=26, tm_sec=29, tm_wday=1, tm_yday=15, tm_isdst=0)
小结:时间戳是计算机能够识别的时间;时间字符串是人能够懂的时间;元祖则是用来操作时间的
时间格式的转换:
时间戳-->结构化时间
time.gmtime(时间戳) #UTC时间,与英国伦敦当地时间一直
time.localtime(时间戳) #当地时间.例如我们现在在北京之行这个方法:与UTC时间相差8小时,UTC时间+8小时=北京时间
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.localtime(时间戳)
结构化时间-->时间戳
time.mktime(结构化时间)
time_li=time.localtime()
print(time.mktime(time_li))
结构化时间-->字符串时间
#time.strftime("格式定义","结构化时间") 结构化时间参数若不传,则显示当前时间 print(time.strftime("%Y-%m-%d %X")) 2019-01-15 21:06:44 print(time.strftime("%Y-%m-%d",time.localtime(1500000000))) 2017-07-14
字符串时间-->结构化时间
time.strptime(时间字符串,字符串对应格式)
print(time.strptime("2017-03-16","%Y-%m-%d")) time.struct_time(tm_year=2017, tm_mon=3, tm_mday=16, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=75, tm_isdst=-1) print(time.strptime("07/24/2017","%m/%d/%Y")) time.struct_time(tm_year=2017, tm_mon=7, tm_mday=24, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=0, tm_yday=205, tm_isdst=-1)
#结构化时间 --> %a %b %d %H:%M:%S %Y串 #time.asctime(结构化时间) 如果不传参数,直接返回当前时间的格式化串 >>>time.asctime(time.localtime(1500000000)) 'Fri Jul 14 10:40:00 2017' >>>time.asctime() 'Mon Jul 24 15:18:33 2017' #时间戳 --> %a %b %d %H:%M:%S %Y串 #time.ctime(时间戳) 如果不传参数,直接返回当前时间的格式化串 >>>time.ctime() 'Mon Jul 24 15:19:07 2017' >>>time.ctime(1500000000) 'Fri Jul 14 10:40:00 2017'
Python处理日期和时间的标准库
datetime
获取当前日期和时间
from datetime import datetime print(datetime.now())
结果: 2019-01-15 21:12:16.688821
注意:datetime
是模块,datetime
模块还包含一个datetime的
类,通过from datetime import datetime
导入的才是datetime
这个类。
如果仅导入import datetime
,则必须引用全名datetime.datetime
。
datetime.now()
返回当前日期和时间,其类型是datetime
。
获取指定日期和时间
要指定某个日期和时间,我们直接用参数构造一个datetime
:
from datetime import datetime dt = datetime(2018,5,20,13,14) print(dt) ''' 结果:2018-05-20 13:14:00 '''
datetime转换为timestamp(时间戳)
from datetime import datetime dt = datetime.now() new_timestamp = dt.timestamp() print(new_timestamp) ''' 结果:1543931750.415896 '''
timestamp转换为datetime
import time from datetime import datetime new_timestamp = time.time() print(datetime.fromtimestamp(new_timestamp))
str转换为datetime
很多时候,用户输入的日期和时间是字符串,要处理日期和时间,首先必须把str转换为datetime。转换方法是通过datetime.strptime()
实现,需要一个日期和时间的格式化字符串:
from datetime import datetime t = datetime.strptime('2018-4-1 00:00','%Y-%m-%d %H:%M') print(t) ''' 结果: 2018-04-01 00:00:00 '''
datetime转换为str
如果已经有了datetime对象,要把它格式化为字符串显示给用户,就需要转换为str,转换方法是通过strftime()
实现的,同样需要一个日期和时间的格式化字符串:
from datetime import datetime now = datetime.now() print(now.strftime('%a, %b %d %H:%M')) Mon, May 05 16:28
datetime加减
对日期和时间进行加减实际上就是把datetime往后或往前计算,得到新的datetime。加减可以直接用+
和-
运算符,不过需要导入timedelta
这个类:
from datetime import datetime, timedelta now = datetime.now() print(now) now1 = now + timedelta(hours=10) print(now1) now2 = now - timedelta(days=1) print(now2) now3 = now + timedelta(days=2, hours=12) print(now3)
可见,使用timedelta
你可以很容易地算出前几天和后几天的时刻。
datetime
表示的时间需要时区信息才能确定一个特定的时间,否则只能视为本地时间
posted on 2019-01-15 13:52 🐳️南栀倾寒🐳️ 阅读(195) 评论(0) 编辑 收藏 举报