python 模块、包

模块

模块导入:

import导入模块干的事

1.产生新的名称空间
2.以新建的名称空间为全局名称空间,执行文件的代码
3.拿到一个模块名spam,指向spam.py产生的名称空间

from .. import ..

1.产生新的名称空间
2.以新建的名称空间为全局名称空间,执行文件的代码
3.直接拿到就是spam.py产生的名称空间中名字

优点:方便,不用加前缀
缺点:容易跟当前文件的名称空间冲突

__all__=['money']  #加入spam文件内[ ]内必须是字符串 
from spam import * #*代表all

模块搜索顺序

内存---->内置------->sys.path

若倒入的模块跟执行的py不在一个路径下,则用sys.path:

方法1.
#sys.path.insert更精准
import sys
#sys.path.append(r'/Users/boxfish-edu/PycharmProjects/untitled/d/a')
sys.path.insert(0,r'/Users/boxfish-edu/PycharmProjects/untitled/d/a')
import aaa
print(aaa.name)

方法2.
#a.b表示两层目录
from a.b import bbb
print(bbb.name)

正则表达式re模块

常用正则表达式符号

'.'     默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
'^'     匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)
'$'     匹配字符结尾,或e.search("foo$","bfoo\nsdfsf",flags=re.MULTILINE).group()也可以
'*'     匹配*号前的字符0次或多次,re.findall("ab*","cabb3abcbbac")  结果为['abb', 'ab', 'a']
'+'     匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb']
'?'     匹配前一个字符1次或0次
'{m}'   匹配前一个字符m次
'{n,m}' 匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb']
'|'     匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC'
'(...)' 分组匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 结果 abcabca456c
 
 
'\A'    只从字符开头匹配,re.search("\Aabc","alexabc") 是匹配不到的
'\Z'    匹配字符结尾,同$
'\d'    匹配数字0-9
'\D'    匹配非数字
'\w'    匹配[A-Za-z0-9]
'\W'    匹配非[A-Za-z0-9]
's'     匹配空白字符、\t、\n、\r , re.search("\s+","ab\tc1\n3").group() 结果 '\t'
 
'(?P<name>...)' 分组匹配 re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","371481199306143242").groupdict("city") 结果{'province': '3714', 'city': '81', 'birthday': '1993'}

常用的匹配语法

re.match 从头开始匹配
re.search 匹配包含
re.findall 把所有匹配到的字符放到以列表中的元素返回
re.splitall 以匹配到的字符当做列表分隔符
re.sub      匹配字符并替换
print(re.findall('a.c','abc1\nn2a\nc3\tad_efa * | - =',re.S)) #加上re.s可以使.匹配\n

print(re.findall('al(?:e)x\smak(?:e)','alex make love'))   #固定语法 不单单匹配括号里的

正则表达式概念

  1. 使用单个字符串来描述匹配一系列符合某个句法规则的字符串
  2. 是对字符串操作的一种逻辑公式
  3. 应用场景:处理文本和数据
  4. 正则表示是过程:依次拿出表达式和文本中的字符比较,如果每一个字符都能匹配,则匹配成功;否则匹配失败

字符匹配

字符描述
.匹配任意一个字符(除了\n)
\d \D数字/非数字
\s \S空白/非空白字符
\w \W单词字符[a-zA-Z0-9]/非单词字符
\b \B单词边界,一个\w与\W之间的范围,顺序可逆/非单词边界
  • 匹配任意一个字符
 # 匹配字符串abc,.代表b
 >>> re.match('a.c','abc').group()
'abc'
  • 数字与非数字
 # 匹配任意一数字
 >>> re.match('\d','1').group()
'1'
 # 匹配任意一个非数字
 >>> re.match('\D','a').group()
'a'
  • 空白与非空白字符
 # 匹配任意一个空白字符
 >>> re.match("\s"," ").group()
' '
 # 匹配任意一个非空白字符
 >>> re.match("\S","1").group()
'1'
 >>> re.match("\S","a").group()
'a'
  • 单词字符与非单词字符

单词字符即代表[a-zA-Z0-9]

 # 匹配任意一个单词字符
 >>> re.match("\w","a").group()
'a'
 >>> re.match("\w","1").group()
'1'
 # 匹配任意一个非单词字符
 >>> re.match("\W"," ").group()
' '

次数匹配

字符匹配
*匹配前一个字符0次或者无限次
+匹配前一个字符1次或者无限次
?匹配前一个字符0次或者1次
{m}/{m,n}匹配前一个字符m次或者N次
*?/+?/??匹配模式变为贪婪模式(尽可能少匹配字符)
  • 介绍
字符匹配
prev?0个或1个prev
prev*0个或多个prev,尽可能多地匹配
prev*?0个或多个prev,尽可能少地匹配
prev+1个或多个prev,尽可能多地匹配
prev+?1个或多个prev,尽可能少地匹配
prev{m}m个连续的prev
prev{m,n}m到n个连续的prev,尽可能多地匹配
prev{m,n}?m到n个连续的prev,尽可能少地匹配
[abc]a或b或c
[^abc]非(a或b或c)
  • 匹配前一个字符0次或者无限次
 >>> re.match('[A-Z][a-z]*','Aaa').group()
'Aaa'
 >>> re.match('[A-Z][a-z]*','Aa').group()
'Aa'
 >>> re.match('[A-Z][a-z]*','A').group()
'A'
  • 匹配前一个字符1次或者无限次
 # 匹配前一个字符至少一次,如果一次都没有就会报错
 >>> re.match('[A-Z][a-z]+','A').group()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'
 >>> re.match('[A-Z][a-z]+','Aa').group()
'Aa'
 >>> re.match('[A-Z][a-z]+','Aaaaaaa').group()
'Aaaaaaa'
  • 匹配前一个字符0次或者1次
 >>> re.match('[A-Z][a-z]?','A').group()
'A'
 # 只匹配出一个a
 >>> re.match('[A-Z][a-z]?','Aaaa').group()
'Aa'
  • 匹配前一个字符m次或者N次
 #匹配前一个字符至少5次
 >>> re.match('\w{5}','asd234').group()
'asd23'
 # 匹配前面的字符6-10次
 >>> re.match('\w{6,10}','asd234').group()
'asd234'
 # 超过的字符就匹配不出来
 >>> re.match('\w{6,10}','asd2313qeadsd4').group()
'asd2313qea'
  • 匹配模式变为贪婪模式
 >>> re.match(r'[0-9][a-z]*','1bc').group()
'1bc'
 # *?匹配0次或者多次
 >>> re.match(r'[0-9][a-z]*?','1bc').group()
'1'
 # +?匹配一次或者多次,但是只匹配了一次
 >>> re.match(r'[0-9][a-z]+?','1bc').group()
'1b'
 # ??匹配0次或者一次
 >>> re.match(r'[0-9][a-z]??','1bc').group()
'1'

贪婪匹配和非贪婪匹配

边界匹配

字符匹配
^匹配字符串开头
$匹配字符串结尾
\A \Z指定的字符串必须出现在开头/结尾
  • 匹配字符串开头
 # 必须以指定的字符串开头,结尾必须是@163.com
 >>> re.match('^[\w]{4,6}@163.com$','asdasd@163.com').group()
'asdasd@163.com'
  • 匹配字符串结尾
 # 必须以.me结尾
 >>> re.match('[\w]{1,20}.me$','ansheng.me').group()
'ansheng.me'
  • 指定的字符串必须出现在开头/结尾
 >>> re.match(r'\Awww[\w]*\me','wwwanshengme').group()
'wwwanshengme'

正则表达式分组匹配

  • | 匹配左右任意一个表达式
 >>> re.match("www|me","www").group()
'www'
 >>> re.match("www|me","me").group()
'me'
  • (ab) 括号中表达式作为一个分组
# 匹配163或者126的邮箱
 >>> re.match(r'[\w]{4,6}@(163|126).com','asdasd@163.com').group()
'asdasd@163.com'
 >>> re.match(r'[\w]{4,6}@(163|126).com','asdasd@126.com').group()
'asdasd@126.com'
  • (?P) 分组起一个别名
 >>> re.search("(?P<zimu>abc)(?P<shuzi>123)","abc123").groups()
('abc', '123')
  • 引用别名为name的分组匹配字符串
 >>> res.group("shuzi")
'123'
 >>> res.group("zimu")
'abc'

re模块常用的方法

  • re.match()

语法格式:

match(pattern, string, flags=0)

释意:

Try to apply the pattern at the start of the string, returning a match object, or None if no match was found.

实例:

 # 从头开始匹配,匹配成功则返回匹配的对象
 >>> re.match("abc","abc123def").group()
'abc'
 # 从头开始匹配,如果没有匹配到对应的字符串就报错
 >>> re.match("\d","abc123def").group()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'
  • re.search()

语法格式:

search(pattern, string, flags=0)

释意:

Scan through string looking for a match to the pattern, returning a match object, or None if no match was found.

实例:

 # 匹配整个字符串,匹配到第一个的时候就返回匹配到的对象
 >>> re.search("\d","abc1123def").group()
'1'
  • re.findall()

语法格式:

findall(pattern, string, flags=0)

释意:

Return a list of all non-overlapping matches in the string.

实例:

 # 匹配字符串所有的内容,把匹配到的字符串以列表的形式返回
 >>> re.findall("\d","abc123def456")
['1', '2', '3', '4', '5', '6']
  • re.split

语法格式:

split(pattern, string, maxsplit=0)

释意:

Split the source string by the occurrences of the pattern, returning a list containing the resulting substrings.

实例:

 # 指定以数字进行分割,返回的是一个列表对象
 >>> re.split("\d+","abc123def4+-*/56")
['abc', 'def', '+-*/', '']
 # 以多个字符进行分割
 >>> re.split("[\d,]","a,b1c")
['a', 'b', 'c']
  • re.sub()

语法格式:

sub(pattern, repl, string, count=0)

释意:

Return the string obtained by replacing the leftmost non-overlapping occurrences of the pattern in string by the replacement repl. repl can be either a string or a callable;
if a string, backslash escapes in it are processed. If it is a callable, it's passed the match object and must return a replacement string to be used.

实例:

 # 把abc替换成def
 >>> re.sub("abc","def","abc123abc")
'def123def'
 # 只替换查找到的第一个字符串
 >>> re.sub("abc","def","abc123abc",count=1)
'def123abc'

实例

string方法包含了一百个可打印的ASCII字符,大小写字母、数字、空格以及标点符号

 >>> import string
 >>> printable = string.printable
 >>> printable
'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'
 >>> import re
 # 定义的字符串
 >>> source = '''I wish I may, I wish I migth
... Hava a dish of fish tonight.'''
 # 在字符串中检索wish
 >>> re.findall('wish',source)
['wish', 'wish']
 # 对源字符串任意位置查询wish或者fish
 >>> re.findall('wish|fish',source)
['wish', 'wish', 'fish']
 # 从字符串开头开始匹配wish
 >>> re.findall('^wish',source)    
[]
 # 从字符串开头匹配I wish
 >>> re.findall('^I wish',source)
['I wish']
 # 从字符串结尾匹配fish
 >>> re.findall('fish$',source)   
[]
 # 从字符串结尾匹配fish tonight.
 >>> re.findall('fish tonight.$',source)
['fish tonight.']
 # 查询以w或f开头,后面紧跟着ish的匹配
 >>> re.findall('[wf]ish',source)
['wish', 'wish', 'fish']
 # 查询以若干个w\s\h组合的匹配
 >>> re.findall('[wsh]+',source) 
['w', 'sh', 'w', 'sh', 'h', 'sh', 'sh', 'h']
 # 查询以ght开头,后面紧跟着一个非数字和字母的匹配
 >>> re.findall('ght\W',source)
['ght.']
 # 查询已以I开头,后面紧跟着wish的匹配
 >>> re.findall('I (?=wish)',source)
['I ', 'I ']
 # 最后查询以wish结尾,前面为I的匹配(I出现次数尽量少)
 >>> re.findall('(?<=I) wish',source)
[' wish', ' wish']
  • 匹配时不区分大小写
 >>> re.match('a','Abc',re.I).group()
'A'
  • r 源字符串,转义,如果要转义要加两个\n
 >>> import re
 >>> pa = re.compile(r'ansheng')
 >>> pa.match("ansheng.me")
<_sre.SRE_Match object; span=(0, 7), match='ansheng'>
 >>> ma = pa.match("ansheng.me")
 >>> ma
<_sre.SRE_Match object; span=(0, 7), match='ansheng'>
 # 匹配到的值存到group内
 >>> ma.group()
'ansheng'
 # 返回字符串的所有位置
 >>> ma.span()
(0, 7)
 # 匹配的字符串会被放到string中
 >>> ma.string
'ansheng.me'
 # 实例放在re中
 >>> ma.re
re.compile('ansheng')

time模块

import time

#时间戳
print(time.time())

#结构化的时间(struct_time):struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)
print(time.localtime())     #本地时区的struct_time
print(time.localtime().tm_year)
print(time.gmtime())      #UTC时区的struct_time

#格式化字符串
print(time.strftime('%Y-%m-%d %H:%M:%S'))
print(time.strftime('%Y-%m-%d %X'))

print(time.localtime(123123131))   #将一个时间戳转换为当前时区的struct_time

print(time.localtime(time.time()))      #时间戳->结构化时间
print(time.mktime(time.localtime()))    #将一个struct_time转化为时间戳。

print(time.strftime('%Y %X',time.localtime()))  #结构化时间->格式化字符串时间
print(time.strptime('2017-06-19 10:41:28','%Y-%m-%d %X'))  #格式化字符串时间->结构化时间

print(time.ctime(123123132))
print(time.asctime(time.localtime()))

random 模块

import random
print(random.random())  # (0,1)----float    大于0且小于1之间的小数

print(random.randint(1, 3))  # [1,3]  大于等于1且小于等于3之间的整数

print(random.randrange(1, 3))  # [1,3)  大于等于1且小于3之间的整数
print(random.randrange(1, 10,2))

print(random.choice([1, '23', [4, 5]]))  # 1或者23或者[4,5]

print(random.sample([1, '23', [4, 5]], 2))  # 列表元素任意2个组合

print(random.uniform(1, 3))  # 大于1小于3的小数,如1.927109612082716

item = [1, 3, 5, 7, 9]
random.shuffle(item)  # 打乱item的顺序,相当于"洗牌"
print(item)

随机选择IP

proxy_ip=[
    '1.1.1.1',
    '1.1.1.2',
    '1.1.1.3',
    '1.1.1.4',
]
print(random.choice(proxy_ip))

生成验证码

def v_code(n=5):
    res= ''
    for i in range(n):
        a = random.randint(0,9)
        b = chr(random.randint(65,90))
        c = random.choice([a,b])
        res +=str(c)
    return res

a = v_code(5)
print(a)

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所指向的文件或者目录的最后修改时间
os.path.getsize(path) 返回path的大小
在Linux和Mac平台上,该函数会原样返回path,在windows平台上会将路径中所有字符转换为小写,并将所有斜杠转换为饭斜杠。
>>> os.path.normcase('c:/windows\\system32\\')   
'c:\\windows\\system32\\'   
   

规范化路径,如..和/
>>> os.path.normpath('c://windows\\System32\\../Temp/')   
'c:\\windows\\Temp'   

>>> a='/Users/jieli/test1/\\\a1/\\\\aa.py/../..'
>>> print(os.path.normpath(a))
/Users/jieli/test1
os路径处理
#方式一:推荐使用
import os
#具体应用
import os,sys
possible_topdir = os.path.normpath(os.path.join(
    os.path.abspath(__file__),
    os.pardir, #上一级
    os.pardir,
    os.pardir
))
sys.path.insert(0,possible_topdir)


#方式二:不推荐使用
os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

sys模块

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(50):
    sys.stdout.write('%s\r' %('#'*i))   #\r将光标移动到首行
    sys.stdout.flush()
    time.sleep(0.1)

'''
注意:在pycharm中执行无效,请到命令行中以脚本的方式执行
'''

shutil模块

高级的 文件、文件夹、压缩包 处理模块

将文件内容拷贝到另一个文件中

import shutil
shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w'))

拷贝文件

shutil.copyfile('f1.log', 'f2.log') #目标文件无需存在

仅拷贝权限。内容、组、用户均不变

shutil.copymode('f1.log', 'f2.log') #目标文件必须存在

仅拷贝状态的信息,包括:mode bits, atime, mtime, flags

shutil.copystat('f1.log', 'f2.log') #目标文件必须存在

拷贝文件和权限

import shutil
shutil.copy('f1.log', 'f2.log')

拷贝文件和状态信息

import shutil
shutil.copy2('f1.log', 'f2.log')

shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的,详细:

import zipfile

# 压缩
z = zipfile.ZipFile('laxi.zip', 'w')
z.write('a.log')
z.write('data.data')
z.close()

# 解压
z = zipfile.ZipFile('laxi.zip', 'r')
z.extractall(path='.')
z.close()

zipfile压缩解压缩
import tarfile

# 压缩
>>> t=tarfile.open('/tmp/egon.tar','w')
>>> t.add('/test1/a.py',arcname='a.bak')
>>> t.add('/test1/b.py',arcname='b.bak')
>>> t.close()


# 解压
>>> t=tarfile.open('/tmp/egon.tar','r')
>>> t.extractall('/egon')
>>> t.close()

tarfile压缩解压缩

json 模块

import json
#序列化的过程:dic--->res=json.dups(dic)--->f.write(res)
dic={
    'name':'alex',
    'age':9000,
    'height':'150cm',
}
with open('a.json','w') as f:
    res = json.dumps(dic)
    print(res, type(res))
    f.write(res)

#反序列化的过程:dic =f.read()---> res = json.loads(res)--->dic=res
with open('a.json','r') as f:
    res = f.read()
    dic = json.loads(res)
    print(dic,type(dic))
    print(dic['name'])

#json的便捷操作
json.dump(dic,open('b.json','w'))

res = json.load(open('b.json','r'))
print(res)

pickle 模块

import pickle
dic={'name':'alex','age':13}
print(pickle.dumps(dic))
with open('a.pkl','wb') as f:
    f.write(pickle.dumps(dic))

with open('a.pkl','rb') as f:
    d = pickle.loads(f.read())
    print(d,type(d))

pickle.dump(dic,open('b.pkl','wb'))
res = pickle.load(open('b.pkl','rb'))
print(res)

import json
import pickle
def func():
    print('from func')

#json.dumps(func)# 报错,json不支持python的函数类型
f=pickle.dumps(func)
print(f)

pickle.dump(func,open('c.pkl','wb'))
res=pickle.load(open('c.pkl','rb'))
print(res)
res()

Pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据,不能成功地反序列化也没关系。


shelve模块

shelve模块比pickle模块简单,只有一个open函数,返回类似字典的对象,可读可写;key必须为字符串,而值可以是python所支持的数据类型

import shelve
f=shelve.open(r'sheve.txt')
f['student1']={'name':'egon','age':18,'height':'180cm'}
print(f['student1']['name'])
f.close()

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数据

xml操作:

#!/usr/bin/python
# -*- coding:utf-8 -*-

import xml.etree.ElementTree as ET

tree = ET.parse("a")
root = tree.getroot()

print(root.iter('year'))        #全文搜索
print(root.find('country'))     #在root的子节点找,只找一个
print(root.findall('country'))  #在root的子节点找,找所有


for country in root:
    print('=====>',country.attrib['name'])
    for item in country:
        print(item.tag,item.text,item.attrib)

for year in root.iter('year'):
    print(year.tag,year.text,year.attrib)   #tag,text,attrib 分别描述不同的内容


#修改
for year in root.iter('year'):
    print(year.text)
    year.text=str(int(year.text)+1)
    print(year.attrib)
    year.set('update','yes')


tree.write('b.xml')     #创建并修改文件
tree.write('a')         #更改当前文件


for country in root:
    print(country)
    print('===>',country.find('year'))
    year=country.find('year')
    if int(year.text) > 2010:
        country.remove(year)

tree.write('d.xml')


#增加
for country in root:
    print(country)
    # print('===>',country.find('year'))
    year=country.find('year')
    if int(year.text) > 2010:
        year2 = ET.Element('year2')
        year2.text=str(int(year.text)+1)
        year2.set('update','yes')
        country.append(year2)
tree.write('e.xml')


#自己创建xml文档:
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)  # 打印生成的格式

参考

Python标准库系列之xml模块

Python’s interfaces for processing XML are grouped in the xml package.

带分隔符的文件仅有两维的数据:行和列。如果你想在程序之间交换数据结构,需要一种方法把层次结构、序列、集合和其他的结构编码成文本。

XML是最突出的处理这种转换的标记(markup)格式,它使用标签(tag)分个数据,如下面的实例文件menu.xml所示:

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>安生&#39;s Blog</title>
  <subtitle>大好时光!</subtitle>
  <link href="/atom.xml" rel="self"/>
  
  <link href="https://blog.ansheng.me/"/>
  <updated>2016-05-24T15:29:19.000Z</updated>
  <id>https://blog.ansheng.me/</id>
  
  <author>
    <name>安生</name>
  </author>
</feed>

XML的一些重要特性

  1. 标签以一个<字符开头,例如实例中的feed、title、subtitle、author。
  2. 忽略空格
  3. 通常一个开始标签跟一段其他的内容,然后是最后相匹配的结束标签,例如大好时光!
  4. 标签之间是可以存在多级嵌套的
  5. 可选属性(attribute)可以出现在开始标签里
  6. 标签中可以包含值(value)
  7. 如果一个命名为thing的标签内没有内容或者子标签,那么它可以用在右尖括号的前面添加斜杠的简单标签所表示,例如代替开始和结束都存在的标签。
  8. 存放数据的位置可以是任意的---属性、值或者子标签。

XML通常用于数据传送和消息,它存在一些子格式,如RSS和Atom,例如:https://blog.ansheng.me/atom.xml

在Python中解析XML最简单的方法是使用ElementTree

模块说明
xml.etree.ElementTreethe ElementTree API, a simple and lightweight XML processor

创建xml文件

导入ElementTree方法,起一个别名为ET

>>> from xml.etree import ElementTree as ET

创建顶级标签

>>> level_1 = ET.Element("famliy")

创建二级标签,tag名name,attrib标签属性

>>> level_2 = ET.SubElement(level_1, "name", attrib={"enrolled":"yes"}) 

创建三级标签

>>> level_3 = ET.SubElement(level_2, "age", attrib={"checked":"no"})

生成文档

>>> tree = ET.ElementTree(level_1)

写入文件中

>>> tree.write('oooo.xml',encoding='utf-8', short_empty_elements=False)

导入os模块,用os模块中的system方法执行shell命令查看刚才创建的oooo.xml文件

>>> import os
>>> os.system("cat oooo.xml")
# 生成出来的文档是没有换行的
<famliy><name enrolled="yes"><age checked="no"></age></name></famliy>0

把刚才生成的文件下载到本地,然后用浏览器打开就可以看到分级层次了。

创建一个有换行的XML文件

代码

from xml.etree import ElementTree as ET
from xml.dom import minidom

root = ET.Element('level1',{"age":"1"})
son = ET.SubElement(root,"level2",{"age":"2"})
ET.SubElement(son, "level3", {"age":"3"})

# tree = ET.ElementTree(root)
# tree.write("abc.xml", encoding="utf-8",xml_declaration=True,short_empty_elements=False)

def prettify(root):
    rough_string = ET.tostring(root, 'utf-8')
    reparsed = minidom.parseString(rough_string)
    return reparsed.toprettyxml(indent="\t")

new_str = prettify(root)
f = open("new_out.xml", "w")
f.write(new_str)
f.close()

生成的xml文件

<?xml version="1.0" ?>
<level1 age="1">
    <level2 age="2">
        <level3 age="3"/>
    </level2>
</level1>

解析XML

first.xml文件内容为:

<data>
    <country name="Liechtenstein">
        <rank updated="yes">2</rank>
        <year age="19">2025</year>
        <gdppc>141100</gdppc>
        <neighbor direction="E" name="Austria" />
        <neighbor direction="W" name="Switzerland" />
    </country>
    <country name="Singapore">
        <rank updated="yes">5</rank>
        <year age="19">2028</year>
        <gdppc>59900</gdppc>
        <neighbor direction="N" name="Malaysia" />
    </country>
    <country name="Panama">
        <rank updated="yes">69</rank>
        <year age="19">2028</year>
        <gdppc>13600</gdppc>
        <neighbor direction="W" name="Costa Rica" />
        <neighbor direction="E" name="Colombia" />
    </country>
</data>

first.xml文件在/root目录下

利用ElementTree.XML将字符串解析成xml对象

>>> from xml.etree import ElementTree as ET
# 打开文件,读取XML内容,将字符串解析成xml特殊对象,root代指xml文件的根节点 
>>> root = ET.XML(open('first.xml', 'r').read())
>>> root.tag
'data'
>>> for node in root:
...  print(node.tag, node.attrib)
... 
('country', {'name': 'Liechtenstein'})
('country', {'name': 'Singapore'})
('country', {'name': 'Panama'})
>>> print(node.find('rank').text)
69

利用ElementTree.parse将文件直接解析成xml对象


>>> from xml.etree import ElementTree as ET
# 直接解析xml文件
>>> tree = ET.parse("first.xml")
# 获取xml文件的根节点
>>> root = tree.getroot()
>>> root.tag
'data'

遍历XML中指定的节点

>>> from xml.etree import ElementTree as ET
>>> tree = ET.parse("first.xml")
>>> root = tree.getroot()
>>> for node in root.iter('year'):
        # 输出node的tag和内容
...     print(node.tag, node.text)
...
year 2025
year 2028
year 2028 

增、删、改XML

为节点添加属性

>>> from xml.etree import ElementTree as ET
>>> tree = ET.parse("first.xml")
>>> root = tree.getroot()
>>> for node in root.iter("year"):
        # 查看原来的属性
...     print(node.attrib)
...
{}
{}
{}
>>> for node in root.iter("year"):
       # 添加属性
...    node.set("OS","Linux")
...
>>> for node in root.iter("year"):
        # 查看添加的属性
...     print(node.attrib) 
...
{'OS': 'Linux'}
{'OS': 'Linux'}
{'OS': 'Linux'}
# 把内容写入文件
>>> tree.write("first.xml") 

删除节点属性

>>> from xml.etree import ElementTree as ET
>>> tree = ET.parse("first.xml")
>>> root = tree.getroot()
>>> for node in root.iter("year"):
        # 删除节点的OS属性
...     del node.attrib['OS']
...
# 写入到文件当中
>>> tree.write("first.xml") 

查看属性

>>> from xml.etree import ElementTree as ET
>>> tree = ET.parse("first.xml")
>>> root = tree.getroot()
>>> for node in root.iter("year"):
...  print(node.attrib)
...
# 节点内容为空
{}
{}
{}

修改节点内容

修改year内的数字自加1

>>> from xml.etree import ElementTree as ET
>>> tree = ET.parse("first.xml")
>>> root = tree.getroot() 
>>> for node in root.iter("year"):
        # 输出原来year的内容
...     print(node.text)
        # 原来的值自加+
...     new_year = int(node.text) + 1
...     node.text = str(new_year)
...
2025
2028
2028 
# 写入文件中
>>> tree.write("first.xml")
>>> for node in root.iter("year"):
        # 输出写入文件之后year的内容
...     print(node.text)
...
2026
2029
2029

对节点操作的方法

获取节点的方法

>>> from xml.etree import ElementTree as ET
>>> tree = ET.parse("first.xml")
>>> root = tree.getroot()
>>> print(dir(root))
['__class__', '__copy__', '__deepcopy__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getstate__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'extend', 'find', 'findall', 'findtext', 'get', 'getchildren', 'getiterator', 'insert', 'items', 'iter', 'iterfind', 'itertext', 'keys', 'makeelement', 'remove', 'set']  

方法有这么多,那么我们常用的也就是下面的几个

方法名说明
tag获取tag标签名
attrib获取节点的属性
find获取节点的内容
iter进行迭代
set设置属性
get获取属性

实例

判断QQ是否在线

腾讯提供了能够查看QQ号码是否在线的API,Y=在线;N=离线;E=QQ号码错误;A=商业用户验证失败;V=免费用户超过数量

>>> import requests
>>> from xml.etree import ElementTree as ET
>>> r = requests.get("http://www.webxml.com.cn//webservices/qqOnlineWebService.asmx/qqCheckOnline?qqCode=6087414")
>>> result = r.text
>>> from xml.etree import ElementTree as ET
>>> node = ET.XML(result)
>>> if node.text == "Y":
...    print("在线")
... else:
...    print("离线")
...
在线

获取列车起止时间

代码

r = requests.get("http://www.webxml.com.cn/WebServices/TrainTimeWebService.asmx/getDetailInfoByTrainCode?TrainCode=K234&UserID=")
result = r.text
root = ET.XML(result)
for node in root.iter('TrainDetailInfo'):
    print(node.find('TrainStation').text,node.find('ArriveTime').text,node.find("StartTime").text)

执行结果

C:\Python35\python.exe F:/Python_code/sublime/Week5/Day01/xml_mod.py
上海(车次:K234\K235) None 11:12:00
# 地点 停止    启动
昆山 11:45:00 11:48:00
苏州 12:12:00 12:16:00
无锡 12:44:00 12:55:00
常州 13:22:00 13:26:00
镇江 14:13:00 14:16:00
南京 15:04:00 15:16:00
蚌埠 17:27:00 17:50:00
徐州 19:38:00 19:58:00
商丘 22:12:00 22:17:00
开封 23:49:00 23:53:00
郑州 00:37:00 01:14:00
新乡 02:20:00 02:22:00
鹤壁 03:01:00 03:03:00
安阳 03:33:00 03:36:00
邯郸 04:11:00 04:16:00
邢台 04:47:00 04:51:00
石家庄 06:05:00 None

Process finished with exit code 0

hashlib 模块

This module implements a common interface to many different secure hash and message digest algorithms. Included are the FIPS secure hash algorithms SHA1, SHA224, SHA256, SHA384, and SHA512 (defined in FIPS 180-2) as well as RSA’s MD5 algorithm (defined in Internet RFC 1321). The terms “secure hash” and “message digest” are interchangeable. Older algorithms were called message digests. The modern term is secure hash.

官方文档:https://docs.python.org/3.5/library/hashlib.html

用于加密相关的操作,代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法

md5加密

>>> import hashlib
m = hashlib.md5()
m.update('me'.encode('utf-8'))
print(m.hexdigest())

m = hashlib.md5()
with open('a','rb') as f:
    for i in f:
        m.update(i)
    md5_num = m.hexdigest()
print(md5_num)

sha1

>>> import hashlib
>>> hash = hashlib.sha1()
>>> hash.update(bytes('ansheng', encoding='utf-8'))
>>> hash.hexdigest()
'd1dec3927fbe94ace7f7ebe6c53a844e0265455a'

sha256

import hashlib
s = hashlib.sha256()
s.update('helloword'.encode('utf-8'))
print(s.hexdigest())

sha384

>>> import hashlib
>>> hash = hashlib.sha384()
>>> hash.update(bytes('ansheng', encoding='utf-8'))
>>> hash.hexdigest()
'01cab50e3cc7801fec2988573ad62a645daf636a6d2a47d41c7a456113bee6e657a3ff367029f617e38a03d732c8113d'

sha512

>>> import hashlib
>>> hash = hashlib.sha512()
>>> hash.update(bytes('ansheng', encoding='utf-8'))
>>> hash.hexdigest()
'79cc48a191152112bd8285979784fc4bba9b0f2d5ac26f96de1ec87a6fbf4935dcb3ba9bc027c3791875b96dd725e01863602f59d4a561bbd2823495cd4553fc'

撞库实例:

import hashlib
passwds=[
    'alex3714',
    'alex1313',
    'alex94139413',
    'alex123456',
    '123456alex',
    'a123lex',
    ]

def make_pass_dic(passwords):
    dic = {}
    m = hashlib.md5()
    for passwd in passwds:
        m.update(passwd.encode('utf-8'))
        dic[passwd] = m.hexdigest()
    return dic


def break_code(cryptograph,dic_passwd):
    for k,v in dic_passwd.items():
        if v == cryptograph:
            print('密码是--->',k)


cryptograph = 'aee949757a2e698417463d47acac93df'
break_code(cryptograph,make_pass_dic(passwds))

为防止别人对我们的md5值进行撞库,我们可以给md5加个盐

import hashlib
m=hashlib.md5('yihangbailushangqingtian'.encode('utf-8'))
m.update('alex3714'.encode('utf-8'))
print(m.hexdigest())

另外一个加盐的模块

import hmac
h = hmac.new('egon123456'.encode('utf-8'))
h.update('alex3714'.encode('utf-8'))
print(h.hexdigest())

实例

根据用户输入的登录名和口令模拟用户注册,计算更安全的MD5:
然后,根据修改后的MD5算法实现用户登录的验证.

import hashlib
db = {}
def calc_md5(password):
    md5 = hashlib.md5()
    md5.update(password.encode())
    return md5.hexdigest()

def register(user,password):
    db[user] = calc_md5(password + user + 'the-Salt')

def login(user,password):
    p = calc_md5(password + user + 'the-Salt')
    if user in db:
        if db[user] == p:
            print('login successful')
        else:
            print('wrong')
    else:
        print('can not find',username)

while True:
    x = input('register:1 login:2 quit:0\n')
    if x == '0':
        break
    elif x == '1':
        user = input('input your name:\n')
        password = input('input your password:\n')
        register(user, password)

    elif x == '2':
        user = input('input your name:\n')
        password = input('input your password:\n')
        login(user, password)
    else:
        print('wrong')

subprocess 模块

import subprocess
res = subprocess.Popen('ls',shell=True,stdout=subprocess.PIPE)
print(res)
print(res.stdout.read().decode('gbk'))


#stderr 可以在出错是不报错
res = subprocess.Popen('diasd',shell=True,
                       stderr = subprocess.PIPE,
                       stdout = subprocess.PIPE
                       )

print('---->',res.stdout.read())
print('---->',res.stderr.read().decode('gbk'))


res1 = subprocess.Popen(r'ls /Users/boxfish-edu/PycharmProjects/untitled/e',shell=True,stdout=subprocess.PIPE)
#print(res1.stdout.read())
res=subprocess.Popen(r'ls test*',shell=True,
                     stdin=res1.stdout,
                     stderr=subprocess.PIPE,
                     stdout=subprocess.PIPE)

print('===>',res.stdout.read().decode('gbk'))#管道取一次就空了
print('===>',res.stdout.read().decode('gbk'))#管道取一次就空了

官网介绍:

This module allows you to spawn processes, connect to their input/output/error pipes, and obtain their return codes.

常用方法实例

call()

执行命令,并返回状态码,状态码0代表命令执行成功,其他的都表示命令执行不成功

>>> ret = subprocess.call(["ls", "-l"], shell=False)
total 4
-rw-r--r-- 1 root root 172 May 25 21:21 file.conf
>>> ret
0

另一种执行方式

# shell=True表示调用原生的shell命令去执行
>>> ret = subprocess.call("ls -l", shell=True)
total 4
-rw-r--r-- 1 root root 172 May 25 21:21 file.conf
>>> ret
0

check_call()

执行命令,如果执行状态码是0,则返回0,否则抛异常

# 执行一个正确的命令就会返回执行结果和状态码
>>> subprocess.check_call(["ls", "-l"])
total 4
-rw-r--r-- 1 root root 172 May 25 21:21 file.conf
0
# 如果执行的是一个错误的命令,那么就会返回错误信息
>>> subprocess.check_call(["ls", "a"])  
ls: cannot access a: No such file or directory
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python2.6/subprocess.py", line 505, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['ls', 'a']' returned non-zero exit status 2

check_output()

执行命令,如果状态码是0,则返回执行结果,否则抛异常

# 执行成功就把执行的结果赋值给变量V
>>> V = subprocess.check_output("python -V", shell=True)
# 执行错误的命令就会输出异常
>>> subprocess.check_output("pasas", shell=True)
'pasas' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python35\lib\subprocess.py", line 629, in check_output
    **kwargs).stdout
  File "C:\Python35\lib\subprocess.py", line 711, in run
    output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command 'pasas' returned non-zero exit status 1

以上的三种执行方式在执行命令的时候,shell默认等于True,等于True的时候,括号内的命令是一行的,如果shell等于False,那么[]内的字符串就是命令的一个元素,执行的时候会把[]内的字符串拼接起来执行。

subprocess.Popen()

call()check_call()check_output()默认内部调用的都是subprocess.Popen(),而subprocess.Popen()则用于执行更复杂的系统命令。

参数

参数说明
stdin标准输入
stdout标准输出
stderr错误句柄
cwd用于设置子进程的当前目录
env用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父进程中继承

执行普通命令

>>> subprocess.Popen("Python -V", shell=True)
<subprocess.Popen object at 0x0000025C97233C88>
# Python 3.5.1是输出出来的结果
>>> Python 3.5.1

执行命令分为两种:

  1. 输入即可得到输出,如:ifconfig
  2. 输入进行某交互式环境,依赖再输入,如:python
>>> import subprocess
# 先进入'/tmp'目录,然后在创建subprocess文件夹,shell=True可有可无
>>> subprocess.Popen("mkdir subprocess", shell=True, cwd='/tmp',)
<subprocess.Popen object at 0x7f267cc3d390>
>>> import os
>>> os.system("ls /tmp")
subprocess

subprocess.Popen()实例

# 导入subprocess模块
import subprocess

# 执行python命令,进入python解释器,stdin标准输入、stdout标准输出、stderr错误输出,universal_newlines=True自动输入换行符
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)

# 执行标准输入,write后面是输入的命令
obj.stdin.write("print(1)\n")
obj.stdin.write("print(2)")
# 输入之后关闭
obj.stdin.close()

# 读取标准输出的内容,赋值给cmd_out对象
cmd_out = obj.stdout.read()
# 关闭标准输出
obj.stdout.close()

# 读取错误输出的内容,赋值给cmd_error对象
cmd_error = obj.stderr.read()

# 关闭错误输出
obj.stderr.close()

# 输出内容
print(cmd_out)
print(cmd_error)

执行结果

C:\Python35\python.exe F:/Python_code/sublime/Week5/Day02/sub.py
1
2



Process finished with exit code 0
# 导入subprocess模块
import subprocess

# 执行python命令,进入python解释器,stdin标准输入、stdout标准输出、stderr错误输出,universal_newlines=True自动输入换行符
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)

# 执行两条命令
obj.stdin.write("print(1)\n")
obj.stdin.write("print(2)")

# communicate把错误输出或者标准输出的内容赋值给out_error_list对象,如果有错误就赋值错误输出,否则就复制标准输出
out_error_list = obj.communicate()

# 输出out_error_list对象的内容
print(out_error_list)

执行结果

C:\Python35\python.exe F:/Python_code/sublime/Week5/Day02/sub.py
('1\n2\n', '')

Process finished with exit code 0
# 导入subprocess模块
import subprocess

# 执行python命令,进入python解释器,stdin标准输入、stdout标准输出、stderr错误输出,universal_newlines=True自动输入换行符
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)


# 直接执行print("hello")命令,然后把错误或者正确的结果赋值给out_error_list对象
out_error_list = obj.communicate('print("hello")')

# 输出out_error_list对象的内容
print(out_error_list)

执行结果

C:\Python35\python.exe F:/Python_code/sublime/Week5/Day02/sub.py
('hello\n', '')

Process finished with exit code 0

logging日志模块

This module defines functions and classes which implement a flexible event logging system for applications and libraries.

The key benefit of having the logging API provided by a standard library module is that all Python modules can participate in logging, so your application log can include your own messages integrated with messages from third-party modules.

官方文档:https://docs.python.org/3.5/library/logging.html

logging模块用于便捷记录日志且线程安全。

日志级别

LevelNumeric value
CRITICAL50
ERROR40
WARNING30
INFO20
DEBUG10
NOTSET0

只有大于当前日志等级的操作才会被记录。

写入单文件

代码

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
# 导入logging模块
import logging

# 创建一个log.log日志文件
logging.basicConfig(filename='log.log',
                    # 格式化的字符串
                    format='%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s',
                    # 时间
                    datefmt='%Y-%m-%d %H:%M:%S %p',
                    # 错误级别
                    level=logging.NOTSET
                    )

logging.critical('critical')
logging.error('error')
logging.warning('warning')
logging.info('info')
logging.debug('debug')
logging.log(logging.INFO, 'NOTSET')

执行结果

ansheng@ansheng-me:~$ ls 
log.py
ansheng@ansheng-me:~$ python log.py 
ansheng@ansheng-me:~$ ls
log.log  log.py
ansheng@ansheng-me:~$ cat log.log 
2016-05-27 21:46:15 PM - root - CRITICAL - log: critical
2016-05-27 21:46:15 PM - root - ERROR - log: error
2016-05-27 21:46:15 PM - root - WARNING - log: warning
2016-05-27 21:46:15 PM - root - INFO - log: info
2016-05-27 21:46:15 PM - root - DEBUG - log: debug
2016-05-27 21:46:15 PM - root - INFO - log: NOTSET

logging.basicConfig函数各参数

参数说明
filename指定日志文件名
filemode和file函数意义相同,指定日志文件的打开模式,'w'或'a'
format指定输出的格式和内容,format可以输出很多有用信息,如下所示
datefmt指定时间格式,同time.strftime()
level设置日志级别,默认为logging.WARNING

format参数

参数说明
%(levelno)s打印日志级别的数值
%(levelname)s打印日志级别名称
%(pathname)s打印当前执行程序的路径,其实就是sys.argv[0]
%(filename)s打印当前执行程序名
%(funcName)s打印日志的当前函数
%(lineno)d打印日志的当前行号
%(asctime)s打印日志的时间
%(thread)d打印线程ID
%(threadName)s打印线程名称
%(process)d打印进程ID
%(message)s打印日志信息

多文件日志

对于上述记录日志的功能,只能将日志记录在单文件中,如果想要设置多个日志文件,logging.basicConfig将无法完成,需要自定义文件和日志操作对象。

#!/usr/bin/env python
# _*_ coding:utf-8 _*_

import logging

# 创建文件
file_1 = logging.FileHandler("log1.log", "a")
# 创建写入的日志格式
fmt1 = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s - %(module)s : %(message)s")
# 文件用格式
file_1.setFormatter(fmt1)

file_2 = logging.FileHandler("log2.log", "a")
fmt2 = logging.Formatter()
file_2.setFormatter(fmt2)

logger1 = logging.Logger("s1", level=logging.ERROR)
logger1.addHandler(file_1)
logger1.addHandler(file_2)

logger1.critical("1111")
# 定义文件
file_2_1 = logging.FileHandler('l2_1.log', 'a')
fmt = logging.Formatter()
file_2_1.setFormatter(fmt)

# 定义日志
logger2 = logging.Logger('s2', level=logging.INFO)
logger2.addHandler(file_2_1)

如上述创建的两个日志对象

  1. 当使用logger1写日志时,会将相应的内容写入 l1_1.log 和 l1_2.log 文件中
  2. 当使用logger2写日志时,会将相应的内容写入 l2_1.log 文件中

configparser模块

This module provides the ConfigParser class which implements a basic configuration language which provides a structure similar to what’s found in Microsoft Windows INI files. You can use this to write Python programs which can be customized by end users easily.

configparser用于处理特定格式的文件,其本质上是利用open来操作文件。

配置文件格式如下:

# 第一种注释方式
; 第二种注释方式
 
[node1]  # 节点
k1 = v1  # key = value
k2 : v2  # key : value

实例

import configparser

#为文件添加节点
config=configparser.ConfigParser()
config.read('a.ini',encoding='utf-8')

config.add_section('node1')
config.add_section('node2')
config.write(open('a.ini','w'))

#检查节点是否存在
print(config.has_section('node1'))      #存在返回True

#删除节点
config.remove_section('node2')
config.write(open('a.ini','w'))

#设置节点内的键值对
config.set('node1','name','ansheng')
config.set('node1', 'Blog_URL', "https://blog.ansheng.me")
config.set('node1', 'Hostname', "localhost.localhost")
config.set('node1', 'IP', "127.0.0.1")
config.write(open('a.ini', 'w'))

#检查节点内的key是否存在
#如果节点的Key存在就返回"True",否则返回"False"
print(config.has_option('node1', 'Name'))


#删除节点内的key

#如果删除的节点存在就返回"True",否则就返回"False"
print(config.remove_option('node1', 'IP'))


#获取指定节点下指定key的值
print(config.get('node1','name'))
#返回的字符串我们可以设置成一下三种数据类型,分别是"int","float","bool"
v = config.getint('node1', 'name')
v = config.getfloat('node1', 'k1')
v = config.getboolean('node1', 'k1')

#获取指定节点下所有的key
#返回节点下面所有的Key列表
print(config.options('node1'))

#获取指定节点下所有的键值对
#返回一个列表,列表中每个元组就是一个键值对
print(config.items('node1'))

#获取所有节点
#获取当前文件中有多少个节点
print(config.sections())

itertools 模块

datetime\traceback模块

json\pickle\xml\yaml\configparser 处理模




包的导入方式

执行文件都是test.py
1.
import glance.api.policy.get #报错,点的左边必须是包
import glance.api.policy
glance.api.policy.get()

2.
from glance.api import policy,versions
from glance.cmd import manage
from glance.db import models

policy.get()
manage.main()
models.register_models('mysql')
---
#注意与本文件内函数名之间的冲突
from glance.api.policy import get
from glance.api.versions import create_resource
from glance.cmd.manage import main
from glance.db.models import register_models
get()
create_resource('mysql')
main()
register_models('mysql')


3.
#前提在api下的__init__.py内加入__all__=['policy','versions']
from glance.api import *
policy.get()
print(policy)
print(versions)

4.
#前提在glance下的__init__py配置
from .api import *  #policy,versions
from .cmd import *  #mange
from .db import *   #models

#test.py
import glance
glance.policy.get()
glance.versions.create_resource('mysql')


备注:
import glance
print(glance)
直接倒入glace打印的是glace下的__init__.py

实例目录结构:
包可以是结构更清晰,便于开发者修改
'''
---glance
   |
   --api
        |
        ---__init__py
        ---policy.py
        ---versions.py
   --cmd
        |
        ---__init__.py
        ---manage.py
   --db
        |
        ---__init__.py
        ---models.py
   __init__.py
'''

转载于:https://www.cnblogs.com/ma-ke/p/7058763.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值