Py之模块
Posted 美好生活我心往之
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Py之模块相关的知识,希望对你有一定的参考价值。
模块&包(* * * * *)
模块(modue)的概念:
在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。
为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。在Python中,一个.py文件就称之为一个模块(Module)。
使用模块有什么好处?
最大的好处是大大提高了代码的可维护性。
其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。我们在编写程序的时候,也经常引用其他模块,包括Python内置的模块和来自第三方的模块。
所以,模块一共三种:
- python标准库
- 第三方模块
- 应用程序自定义模块
另外,使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。但是也要注意,尽量不要与内置函数名字冲突。
模块导入方法
1 import 语句
1
|
import module1[, module2[,... moduleN] |
当我们使用import语句的时候,Python解释器是怎样找到对应的文件的呢?答案就是解释器有自己的搜索路径,存在sys.path里。
1
2
|
[\' \', \' / usr / lib / python3. 4 \', \' / usr / lib / python3. 4 / plat - x86_64 - linux - gnu\', \'/usr/lib/python3.4/lib-dynload\' , \'/usr/local/lib/python3.4/dist-packages\' , \'/usr/lib/python3/dist-packages\' ] |
因此若像我一样在当前目录下存在与要引入模块同名的文件,就会把要引入的模块屏蔽掉。
2 from…import 语句
1
|
from modname import name1[, name2[, ... nameN]] |
这个声明不会把整个modulename模块导入到当前的命名空间中,只会将它里面的name1或name2单个引入到执行这个声明的模块的全局符号表。
3 From…import* 语句
1
|
from modname import * |
这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。大多数情况, Python程序员不使用这种方法,因为引入的其它来源的命名,很可能覆盖了已有的定义。
4 运行本质
1
2
|
#1 import test #2 from test import add |
无论1还是2,首先通过sys.path找到test.py,然后执行test脚本(全部执行),区别是1会将test这个变量名加载到名字空间,而2只会将add这个变量名加载进来。
包(package)
如果不同的人编写的模块名相同怎么办?为了避免模块名冲突,Python又引入了按目录来组织模块的方法,称为包(Package)。
举个例子,一个abc.py
的文件就是一个名字叫abc
的模块,一个xyz.py
的文件就是一个名字叫xyz
的模块。
现在,假设我们的abc
和xyz
这两个模块名字与其他模块冲突了,于是我们可以通过包来组织模块,避免冲突。方法是选择一个顶层包名:
引入了包以后,只要顶层的包名不与别人冲突,那所有模块都不会与别人冲突。现在,view.py
模块的名字就变成了hello_django.app01.views
,类似的,manage.py
的模块名则是hello_django.manage。
请注意,每一个包目录下面都会有一个__init__.py
的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录(文件夹),而不是一个包。__init__.py
可以是空文件,也可以有Python代码,因为__init__.py
本身就是一个模块,而它的模块名就是对应包的名字。
调用包就是执行包下的__init__.py文件
注意点(important)
1--------------
在nod1里import hello是找不到的,有同学说可以找到呀,那是因为你的pycharm为你把myapp这一层路径加入到了sys.path里面,所以可以找到,然而程序一旦在命令行运行,则报错。有同学问那怎么办?简单啊,自己把这个路径加进去不就OK啦:
1
2
3
4
5
|
import sys,os BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) import hello hello.hello1() |
2 --------------
1
2
|
if __name__ = = \'__main__\' : print ( \'ok\' ) |
“Make a .py both importable and executable”
如果我们是直接执行某个.py文件的时候,该文件中那么”__name__ == \'__main__\'“是True,但是我们如果从另外一个.py文件通过import导入该文件的时候,这时__name__的值就是我们这个py文件的名字而不是__main__。
这个功能还有一个用处:调试代码的时候,在”if __name__ == \'__main__\'“中加入一些我们的调试代码,我们可以让外部模块调用的时候不执行我们的调试代码,但是如果我们想排查问题的时候,直接执行该模块文件,调试代码能够正常运行!s
3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
##-------------cal.py def add(x,y): return x + y ##-------------main.py import cal #from module import cal def main(): cal.add( 1 , 2 ) ##--------------bin.py from module import main main.main() |
# from module import cal 改成 from . import cal同样可以,这是因为bin.py是我们的执行脚本, # sys.path里有bin.py的当前环境。即/Users/yuanhao/Desktop/whaterver/project/web这层路径, # 无论import what , 解释器都会按这个路径找。所以当执行到main.py时,import cal会找不到,因为 # sys.path里没有/Users/yuanhao/Desktop/whaterver/project/web/module这个路径,而 # from module/. import cal 时,解释器就可以找到了。
time模块(* * * *)
三种时间表示
在Python中,通常有这几种方式来表示时间:
- 时间戳(timestamp) : 通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。
- 格式化的时间字符串
- 元组(struct_time) : struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
import time # 1 time() :返回当前时间的时间戳 time.time() #1473525444.037215 #---------------------------------------------------------- # 2 localtime([secs]) # 将一个时间戳转换为当前时区的struct_time。secs参数未提供,则以当前时间为准。 time.localtime() #time.struct_time(tm_year=2016, tm_mon=9, tm_mday=11, tm_hour=0, # tm_min=38, tm_sec=39, tm_wday=6, tm_yday=255, tm_isdst=0) time.localtime( 1473525444.037215 ) #---------------------------------------------------------- # 3 gmtime([secs]) 和localtime()方法类似,gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。 #---------------------------------------------------------- # 4 mktime(t) : 将一个struct_time转化为时间戳。 print (time.mktime(time.localtime())) #1473525749.0 #---------------------------------------------------------- # 5 asctime([t]) : 把一个表示时间的元组或者struct_time表示为这种形式:\'Sun Jun 20 23:21:05 1993\'。 # 如果没有参数,将会将time.localtime()作为参数传入。 print (time.asctime()) #Sun Sep 11 00:43:43 2016 #---------------------------------------------------------- # 6 ctime([secs]) : 把一个时间戳(按秒计算的浮点数)转化为time.asctime()的形式。如果参数未给或者为 # None的时候,将会默认time.time()为参数。它的作用相当于time.asctime(time.localtime(secs))。 print (time.ctime()) # Sun Sep 11 00:46:38 2016 print (time.ctime(time.time())) # Sun Sep 11 00:46:38 2016 # 7 strftime(format[, t]) : 把一个代表时间的元组或者struct_time(如由time.localtime()和 # time.gmtime()返回)转化为格式化的时间字符串。如果t未指定,将传入time.localtime()。如果元组中任何一个 # 元素越界,ValueError的错误将会被抛出。 print (time.strftime( "%Y-%m-%d %X" , time.localtime())) #2016-09-11 00:49:56 # 8 time.strptime(string[, format]) # 把一个格式化时间字符串转化为struct_time。实际上它和strftime()是逆操作。 print (time.strptime( \'2011-05-05 16:37:06\' , \'%Y-%m-%d %X\' )) #time.struct_time(tm_year=2011, tm_mon=5, tm_mday=5, tm_hour=16, tm_min=37, tm_sec=6, # tm_wday=3, tm_yday=125, tm_isdst=-1) #在这个函数中,format默认为:"%a %b %d %H:%M:%S %Y"。 # 9 sleep(secs) # 线程推迟指定的时间运行,单位为秒。 # 10 clock() # 这个需要注意,在不同的系统上含义不同。在UNIX系统上,它返回的是“进程时间”,它是用秒表示的浮点数(时间戳)。 # 而在WINDOWS中,第一次调用,返回的是进程运行的实际时间。而第二次之后的调用是自第一次调用以后到现在的运行 # 时间,即两次时间差。 |
1
2
|
help (time) help (time.asctime) |
random模块(* *)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import random print (random.random()) #(0,1)----float print (random.randint( 1 , 3 )) #[1,3] print (random.randrange( 1 , 3 )) #[1,3) print (random.choice([ 1 , \'23\' ,[ 4 , 5 ]])) #23 print (random.sample([ 1 , \'23\' ,[ 4 , 5 ]], 2 )) #[[4, 5], \'23\'] print (random.uniform( 1 , 3 )) #1.927109612082716 item = [ 1 , 3 , 5 , 7 , 9 ] random.shuffle(item) print (item) |
import random def v_code(): code = \'\' for i in range(5): num=random.randint(0,9) alf=chr(random.randint(65,90)) add=random.choice([num,alf]) code += str(add) return code print(v_code())
os模块(* * * *)
os模块是与操作系统交互的一个接口
os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd os.curdir 返回当前目录: (\'.\') os.pardir 获取当前目录的父目录字符串名:(\'..\') os.makedirs(\'dirname1/dirname2\') 可生成多层递归目录 os.removedirs(\'dirname1\') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推 os.mkdir(\'dirname\') 生成单级目录;相当于shell中mkdir dirname os.rmdir(\'dirname\') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname os.listdir(\'dirname\') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印 os.remove() 删除一个文件 os.rename("oldname","newname") 重命名文件/目录 os.stat(\'path/filename\') 获取文件/目录信息 os.sep 输出操作系统特定的路径分隔符,win下为"\\\\",Linux下为"/" os.linesep 输出当前平台使用的行终止符,win下为"\\t\\n",Linux下为"\\n" os.pathsep 输出用于分割文件路径的字符串 win下为;,Linux下为: os.name 输出字符串指示当前使用平台。win->\'nt\'; Linux->\'posix\' os.system("bash command") 运行shell命令,直接显示 os.environ 获取系统环境变量 os.path.abspath(path) 返回path规范化的绝对路径 os.path.split(path) 将path分割成目录和文件名二元组返回 os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素 os.path.basename(path) 返回path最后的文件名。如何path以/或\\结尾,那么就会返回空值。即os.path.split(path)的第二个元素 os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False os.path.isabs(path) 如果path是绝对路径,返回True os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略 os.path.getatime(path) 返回path所指向的文件或者目录的最后存取时间 os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间
sys模块(* * *)
1
2
3
4
5
6
|
sys.argv 命令行参数 List ,第一个元素是程序本身路径 sys.exit(n) 退出程序,正常退出时exit( 0 ) sys.version 获取Python解释程序的版本信息 sys.maxint 最大的 Int 值 sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值 sys.platform 返回操作系统平台名称 |
进度条:
import sys,time for i in range(10): sys.stdout.write(\'#\') time.sleep(1) sys.stdout.flush()
json & pickle(* * * *)
之前我们学习过用eval内置方法可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特殊类型的时候,eval就不管用了,所以eval的重点还是通常用来执行一个字符串表达式,并返回表达式的值。
1
2
3
4
|
import json x = "[null,true,false,1]" print ( eval (x)) print (json.loads(x)) |
什么是序列化?
我们把对象(变量)从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。
序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。
反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。
json
如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。
JSON表示的对象就是标准的javascript语言的对象,JSON和Python内置的数据类型对应如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#----------------------------序列化 import json dic = { \'name\' : \'alvin\' , \'age\' : 23 , \'sex\' : \'male\' } print ( type (dic)) #<class \'dict\'> j = json.dumps(dic) print ( type (j)) #<class \'str\'> f = open ( \'序列化对象\' , \'w\' ) f.write(j) #-------------------等价于json.dump(dic,f) f.close() #-----------------------------反序列化<br> import json f = open ( \'序列化对象\' ) data = json.loads(f.read()) # 等价于data=json.load(f) |
import json #dct="{\'1\':111}"#json 不认单引号 #dct=str({"1":111})#报错,因为生成的数据还是单引号:{\'one\': 1} dct=\'{"1":"111"}\' print(json.loads(dct)) #conclusion: # 无论数据是怎样创建的,只要满足json格式,就可以json.loads出来,不一定非要dumps的数据才能loads
pickle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
##----------------------------序列化 import pickle dic = { \'name\' : \'alvin\' , \'age\' : 23 , \'sex\' : \'male\' } print ( type (dic)) #<class \'dict\'> j = pickle.dumps(dic) print ( type (j)) #<class \'bytes\'> f = open ( \'序列化对象_pickle\' , \'wb\' ) #注意是w是写入str,wb是写入bytes,j是\'bytes\' f.write(j) #-------------------等价于pickle.dump(dic,f) f.close() #-------------------------反序列化 import pickle f = open ( \'序列化对象_pickle\' , \'rb\' ) data = pickle.loads(f.read()) # 等价于data=pickle.load(f) print (data[ \'age\' ]) |
Pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据,不能成功地反序列化也没关系。
shelve模块(* * *)
shelve模块比pickle模块简单,只有一个open函数,返回类似字典的对象,可读可写;key必须为字符串,而值可以是python所支持的数据类型
1
2
3
4
5
6
7
8
9
10
11
12
|
import shelve f = shelve. open (r \'shelve.txt\' ) # f[\'stu1_info\']={\'name\':\'alex\',\'age\':\'18\'} # f[\'stu2_info\']={\'name\':\'alvin\',\'age\':\'20\'} # f[\'school_info\']={\'website\':\'oldboyedu.com\',\'city\':\'beijing\'} # # # f.close() print (f.get( \'stu_info\' )[ \'age\' ]) |
xml模块(* *)
xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,不过,古时候,在json还没诞生的黑暗年代,大家只能选择用xml呀,至今很多传统公司如金融行业的很多系统的接口还主要是xml。
xml的格式如下,就是通过<>节点来区别数据结构的:
<?xml version="1.0"?> <data> <country name="Liechtenstein"> <rank updated="yes">2</rank> <year>2008</year> <gdppc>141100</gdppc> <neighbor name="Austria" direction="E"/> <neighbor name="Switzerland" direction="W"/> </country> <country name="Singapore"> <rank updated="yes">5</rank> <year>2011</year> <gdppc>59900</gdppc> <neighbor name="Malaysia" direction="N"/> </country> <country name="Panama"> <rank updated="yes">69</rank> <year>2011</year> <gdppc>13600</gdppc> <neighbor name="Costa Rica" direction="W"/> <neighbor name="Colombia" direction="E"/> </country> </data>
xml协议在各个语言里的都 是支持的,在python中可以用以下模块操作xml:
import xml.etree.ElementTree as ET tree = ET.parse("xmltest.xml") root = tree.getroot() print(root.tag) #遍历xml文档 for child in root: print(child.tag, child.attrib) for i in child: print(i.tag,i.text) #只遍历year 节点 for node in root.iter(\'year\'): print(node.tag,node.text) #--------------------------------------- import xml.etree.ElementTree as ET tree = ET.parse("xmltest.xml") root = tree.getroot() #修改 for node in root.iter(\'year\'): new_year = int(node.text) + 1 node.text = str(new_year) node.set("updated","yes") tree.write("xmltest.xml") #删除node for country in root.findall(\'country\'): rank = int(country.find(\'rank\').text) if rank > 50: root.remove(country) tree.write(\'output.xml\')
自己创建xml文档:
import xml.etree.ElementTree as ET new_xml = ET.Element("namelist") name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"}) age = ET.SubElement(name,"age",attrib={"checked":"no"}) sex = ET.SubElement(name,"sex") sex.text = \'33\' name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"}) age = ET.SubElement(name2,"age") age.text = \'19\' et = ET.ElementTree(new_xml) #生成文档对象 et.write("test.xml", encoding="utf-8",xml_declaration=True) ET.dump(new_xml) #打印生成的格式
configparser模块(* *)
来看一个好多软件的常见文档格式如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
[DEFAULT] ServerAliveInterval = 45 Compression = yes CompressionLevel = 9 ForwardX11 = yes [bitbucket.org] User = hg [topsecret.server.com] Port = 50022 ForwardX11 = no |
如果想用python生成一个这样的文档怎么做呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
import configparser config = configparser.ConfigParser() config[ "DEFAULT" ] = { \'ServerAliveInterval\' : \'45\' , \'Compression\' : \'yes\' , \'CompressionLevel\' : \'9\' } c |