9.python模塊化-經常使用的python標準庫模塊

模塊化
一.模塊
1.模塊module:爲了編寫可維護的代碼,咱們把不少函數分組,分別放到不一樣的文件裏,這樣,每一個文件包含的代碼就相對較少,不少編程語言都採用這種組織代碼的方式。在python中,一個.py文件就稱之爲一個模塊(Module)
2.模塊的好處:
(1)提升了代碼的可維護性
(2)編寫代碼沒必要從零開始。當一個模塊編寫完畢,就能夠被其餘地方引用。
3.模塊一共分三種:
(1)python標準庫(python自帶的模塊)
(2)第三方模塊(須要安裝)
(3)應用程序自定義模塊
二.導入語句
1.導入語句的三種方式(import語句--from語句--自定義語句)
方式一:import語句
(1)找到指定的模塊,加載和初始化它,生成模塊對象。找不到,拋出ImportError異常
(2)在import所在的做用域的局部命名空間中,增長名稱和上一步建立的對象關聯node

      語句                   含義
import 模塊1,[,模塊2,...]    徹底導入
import ... as ...          模塊別名

例子1:python

#導入functools模塊到本地做用域
import functools

#打印當前做用域模塊屬性包含導入的functools模塊
print(dir())                                #打印結果:[...,'functools']

#收集functools模塊的全部屬性
print(dir(functools))                        #打印結果:[...,'wraps']

#打印functools這個模塊對象,經過functools名稱放到當前做用域內
print(functools)                             #打印結果:<module 'functools' from 'E:\\python3\\lib\\functools.py'>

#經過functools這個模塊對象訪問它其中的資源wraps
print(functools.wraps)                       #打印結果:<function wraps at >

例子2:mysql

#導入os模塊到本地做用域
import os.path

#打印當前做用域模塊屬性包含導入的os模塊不包含path
print(dir())                           #打印結果:[....,'os']

#收集os模塊的全部屬性
print(dir(os))                        #打印結果:[...,'path']

#打印os這個模塊對象,經過os名稱放到當前做用域內
print(os)                             #打印結果:<module 'os' from 'E:\\python3\\lib\\os.py'>

#經過os這個模塊對象訪問它其中的資源path(徹底限定名稱訪問path)
print(os.path)                        #打印結果:<module 'ntpath' from 'E:\\python3\\lib\\ntpath.py'>

例子3:linux

#導入os.path並賦值給osp到本地做用域
import os.path as osp

#打印當前做用域模塊屬性包含導入的ops(os.path模塊對象)
print(dir())                           #打印結果:[....,'osp']

#打印ops(os.path)這個模塊對象
print(osp)                             #打印結果:<module 'ntpath' from 'E:\\python3\\lib\\ntpath.py'>

總結:
①導入頂級模塊,其名稱會加入到本地名詞空間中,並綁定到其模塊對象
②導入非頂級模塊,將其頂級模塊加入到本地名次空間中。導入的模塊必須使用徹底限定名來訪問
③若是使用了as,其後的名稱直接加入到本地名次空間中,並直接綁定到導入的模塊對象
方式二:from語句程序員

        語句                   含義
from ... import ...           部分導入
from ... improt ... as ...    別名

例子1:web

#加載初始化pathlib模塊下的指定成員Path和PosixPath加入本地名次空間並綁定
from pathlib import Path,PosixPath

#打印當前做用域模塊屬性
print(dir())           #打印結果:['Path', 'PosixPath', ....]

#打印pathlib模塊下的模塊屬性Path
print(Path)            #打印結果:<class 'pathlib.Path'>

#打印pathlib模塊下的模塊屬性PosixPath
print(PosixPath)       #打印結果:<class 'pathlib.PosixPath'>

例子2:正則表達式

#加載初始化pathlib模塊下全部公共成員
from pathlib import *

#打印當前做用域模塊屬性
print(dir())           #打印結果:['Path', 'PosixPath', 'PurePath', 'PurePosixPath', 'PureWindowsPath', 'WindowsPath', .....]

#打印pathlib模塊下的其中一個模塊屬性Path
print(Path)            #打印結果:<class 'pathlib.Path'>

#打印pathlib模塊下的其中一個模塊屬性PosixPath
print(PosixPath)       #打印結果:<class 'pathlib.PosixPath'>

例子3:算法

#導入pathlib模塊下的指定成員wraps取別名爲wr
from functools import wraps as wr

#打印當前做用域模塊屬性
print(dir())           #打印結果:[...', 'wr']

#打印pathlib模塊下的屬性對象wr(wraps)
print(wr)             #打印結果:<function wraps at 0x0000000000D99BF8>

例子4:sql

#加載初始化os.path模塊,exists加入本地名次空間並綁定
from os.path import exists
#打印當前做用域模塊屬性(只有exists沒有os和os.path)
print(dir())           #打印結果:['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'exists']
#打印os.path模塊模塊下的屬性對象exists
print(exists)          #打印結果:<function wraps at 0x0000000000D99BF8>

#導入os模塊到本地做用域
import os
#打印當前做用域模塊屬性包含導入的os模塊
print(dir())           #打印結果:['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'exists', 'os']
#經過os模塊找到path.exists
print(os.path.exists)  #打印結果:<function wraps at 0x0000000000D99BF8>

總結:
①找到from子句中指定的模塊,加載並初始化它(注意不是導入)
②對於import子句後的名稱
-先查from子句導入的模塊是否居右該名稱的屬性
-若是不是,則常識導入該名稱的子模塊
-尚未找到,則拋出ImportError異常
-這個名稱保存到本地名詞空間中,若是有as子句,則使用as子句後的名稱
方式三:自定義模塊:py文件就是一個模塊
舉例1:
<1>test1.py模塊裏shell

x = 123

<2>test2.py

#導入test1文件
import test1

#打印當前做用域模塊屬性包含導入的test1
print(dir())           #打印結果:['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'test1']
#調用test1模塊裏的x
print(test1.x)         #打印結果:123

舉例2:
<1>test1.py文件

x = 123

<2>test2.py加載初始化test1模塊,x加入本地名次空間並綁定

from test1 import x

#打印當前做用域模塊屬性包含導入的x
print(dir())           #打印結果:['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'x']
#調用test1模塊裏的x
print(x)               #打印結果:123

舉例3:
<1>test1.py文件

print('this is test1 module')     #第二步:經過導入模塊找到test1文件打印:this is test1 module

class A:
    def show(self):
        print(type(self).__name__)

a = A()
#第三步:test1模塊內部執行了實例a調用show方法
a.show()                              #打印:A

#第四步:打印當前做用域模塊屬性包含
print(dir())                          #打印結果:['A', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'a']

#第五步:打印test1的名字
print(__name__)                       #打印結果:test1

<2>test2.py文件

print('this is test2 module')   #第一步:打印:this is test2 module

#導入test1文件初始化test1.py本身運行
import test1

#第六步:打印當前做用域模塊屬性包含導入的test1
print(dir())    #打印結果:['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'test1']

#用test1的類構建出一個新的實例,這個實例放在當前模塊屬性裏
b = test1.A()

#第七步:打印當前做用域模塊屬性包含b實例
print(dir())     #打印結果:['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'b', 'test1']

#第八步:用實例b調用show方法
b.show()         #打印結果:A

#第九步:能夠調用到test1裏的名詞空間a
c = test1.a
print(c)         #打印結果:<test1.A object at 0x0000000000AD2978>

#第十步:查看test2的名字由於是入口叫__main__
print(__name__)  #打印結果:__main__

總結:自定義模塊命名規範
①模塊名就是文件名
②模塊名必須符合標識符的要求,非數字開頭的字母數字和下劃線的組合。test-module.py這樣的文件名不能做爲模塊名
③不要使用系統模塊名來避免衝突,除非你明確知道這個模塊名的用途
④一般模塊名爲全小寫,下劃線來分割
2.導入語句問題
from json import encoder以後,json.dump函數用不了?爲何
import json.encoder以後呢?json.dump函數能用嗎
緣由是from json import encoder以後,當前名次空間沒有json,可是json模塊已經加載過了,沒有json的引用,沒法使用dump函數
import json.encoder也加載json模塊,可是當前名次空間有json,所以能夠調用。
三.模塊的屬性與運行
1.模塊的屬性

   屬性                 含義
__file__         字符串,源文件路徑
__cached__       字符串,編譯後的字節碼文件路徑
__spec__         顯示模塊的規範
__name__         模塊名
__package__      當模塊的包,同__name__,不然,能夠設置爲頂級模塊的空字符串

2.模塊運行
(1)__name__,每一個模塊都會定一個__name__特殊變量來存儲當前模塊的名稱,若是不指定,則默認爲源代碼文件名詞,若是是包則有限定名。
(2)解釋器初始化的時候,會初始化sys.modules字典(保存已加載的模塊),建立builtins(全局函數,常量)模塊,__main__模塊,sys模塊,以及模塊搜索路徑sys.path
(3)python是腳本語言,任何一個腳本均可以直接執行,也能夠做爲模塊被導入:
①當從標準輸入(命令行方式敲代碼),腳本($python test.py)或交互式讀取的時候,會將模塊的__name__設置爲__main__,模塊的頂層代碼就在__main__這個做用域執行。頂層代碼:模塊中縮進最外層的代碼。

import sys

#初始化sys.modules字典打印__main__
print(sys.modules['__main__'])          #打印結果:<module '__main__' from 'E:/wangshiyao/aaa/xi/test1.py'>

#打印當前模塊(頂層模塊)名,將模塊的__name__設置爲__main__
print(__name__)                         #打印結果:__main__

②若是是import導入的,其__name__默認就是模塊名
<1>test1.py文件

import sys
#導入teset2文件
import test2
#打印當前模塊(頂層模塊)名,將模塊的__name__設置爲__main__
print(__name__)                 #打印結果:__main__

<2>test2.py文件

print('this is test2 module')   #打印結果:this is test2 module
print("~~~~~~~~~~~",__name__)   #打印結果:~~~~~~~~~~~ test2
####打印結果:
this is test2 module
~~~~~~~~~~~ test2
__main__

總結:當運行test1.py文件導入test2.py模塊的時候默認名就是模塊的名字
(4)if __name__=="__main__": 用途:
①本模塊的功能測試:
測試本模塊內的函數,類
②避免主模塊變動的副做:
用頂層代碼,沒有封裝,主模塊使用沒有問題。可是,一單有了新的主模塊,當前模塊要被導入,因爲原來代碼沒有封裝,一併執行了
<1>test1.py文件

#主模塊
import sys

#判斷是不是主模塊
if __name__ == "__main__":
    #若是是主模塊執行如下代碼
    print('我是主模塊')
    #導入teset2文件
    import test2
else :
    #若是不是主模塊執行如下代碼
    print('in module {}'.format(__name__))

<2>test2.py文件

#不是主模塊
print('this is test2 module')   #打印:this is test2 module

#判斷是不是主模塊
if __name__ == "__main__":
    #若是是主模塊執行如下代碼
    #測試代碼:
    print('本身調用測試代碼')
else :
    #若是不是主模塊執行如下代碼
    #主模塊調用到
    print('in module {}'.format(__name__))
###當執行test2.py返回 this is test2 module 本身調用測試代碼 ###當執行test1.py返回 我是主模塊 this is test2 module in module test2

四.包
1.包(package)
(1)Python中只有一種模塊對象類型,可是爲了模塊化組織模塊的便利,提供一個概念---包Python中只有一種模塊對象類型,可是爲了模塊化組織模塊的便利,提供一個概念---包
(2)包指的是模塊組織在一塊兒的和包名同名的目錄及其相關文件
(3)python的模塊能夠按照目錄組織爲包,引入了包之後,只要頂層的包名不與別人衝突,那全部模塊都不會與別人衝突
(4)ptyhon中,目錄能夠做爲模塊,這就是包,不過代碼須要寫在該目錄下__init__.py中
舉例:
<1>m目錄包含:__init__.py文件

y = 123

<2>m目錄包含:x.py文件
<3>m目錄上層目錄test.py文件:

import m.x
#打印當前做用域包含調用的模塊m
print(dir())                 #打印結果:['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'm']

#打印這個目錄究竟是什麼?
print(type(m))              #打印結果:<class 'module'>

#查看m模塊包含x.py和y
print(dir(m))                #打印結果:['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'x', 'y']

#m是模塊能把m目錄裏的 x.py文件歸到我管
print(m.x)                  #打印結果:<module 'm.x' from 'E:\\shishi\\aaa\\m\\x.py'>

#m模塊能夠藉助__init__.py調用到裏面的東西
print(m.y)                  #打印結果:123

#編譯後的字節碼文件路徑
print(m.__cached__)        #打印結果:E:\shishi\aaa\m\__pycache__\__init__.cpython-35.pyc

#打印源文件路徑
print(m.__file__)          #打印結果:E:\shishi\aaa\m\__init__.py

 

 

包目錄下的py文件,子目錄都是其子模塊:如圖

如上創建子模塊目錄和文件,全部py文件中就寫一句話print(__name__)
<1>test.py

from m.m1.m11 import *

<2>\m\__init__.py

print(__name__)

<3>\m\m1\__init__.py

print(__name__)

<4>\m\m1\m11\__init__.py

print(__name__)

###打印結果:
m
m.m1
m.m1.m11
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'm11prop']

3.模塊和包的總結
(1)包可以更好的組織模塊,尤爲是大模塊代碼不少,能夠拆分紅不少子模塊,便於使用某些功能就加載相應的子模塊。
(2)包目錄__init__.py是在包第一次導入的時候就會執行,內容能夠爲空,也能夠是用於該包初始化工做的代碼,最好不要刪除它(低版本不可刪除)
(3)導入子模塊必定會加載父模塊,可是導入父模塊必定不會導入子模塊
(4)包目錄之間只能使用.點號做爲間隔符,表示模塊及其子模塊的層級關係
(5)模塊也就是封裝,如同類,函數,不過它可以封裝變量,類,函數。
(6)模塊就是命名空間,其內部的頂層標識符,都是它的屬性,能夠經過__dict__或dir(module)查看
(7)包也是模塊,但模塊不必定是包,包是特殊的模塊,是一種組織方式,它包含__path__屬性
五.絕對導入和相對導入
1.絕對導入
在import語句或者from導入模塊,模塊名稱最前面不是以.點開頭的
絕對導入老是去搜索模塊搜索路徑中找
2.相對導入
只能在包內使用,且只能用在from語句中
使用.點號,表示單曲目錄內
..表示上一級目錄
不要在頂層模塊中使用相對導入
舉例:
<1>一級目錄m包括二級目錄m1和本身的__init__.py文件,還包括mm.py文件,mmm.py文件,mmmm.py文件
①__init__.py文件

print(__name__)
#調用本身目錄下的mm
from . import mm

②mm.py文件

print('我是m目錄下的文件mm.py,我被m目錄下的__init.py導入')

③mmm.py文件

print('我是m目錄下的文件mmm.py,我被m目錄下的m1目錄的__init.py導入')

④mmmm.py文件

print('我是m目錄下的文件mmmm.py,我被m目錄下的m1目錄下的m11目錄的__init.py導入')

<2>二級目錄m1包括三級目錄m11和本身的__init__.py文件

print(__name__)
#調用上一層目錄m目錄下的mm
from .. import mmm

<3>三級目錄m11包括本身的__init__.py文件

print(__name__)
#調用上一層目錄的上一層目錄m目錄下的mmm
from ... import mmmm

<4>一級目錄m同級有一個調用文件a.py

#調用m,m1,m11模塊
from m.m1.m11 import *
####返回結果:
m
我是m目錄下的文件mm.py,我被m目錄下的__init.py導入
m.m1
我是m目錄下的文件mmm.py,我被m目錄下的m1目錄的__init.py導入
m.m1.m11
我是m目錄下的文件mmmm.py,我被m目錄下的m1目錄下的m11目錄的__init.py導入

六.下劃線開頭的模塊名
1.模塊內的標識符
普通變量,保護變量,私有變量,特殊變量,都沒有被隱藏,也就是說模塊內沒有私有變量,在模塊中定義不作特殊處理
2.三種語句調用方式的不一樣
方式一:import語句
<1>一級目錄m包括本身的__init__.py文件
①__init__.py文件

_x = 'x'
__y = 'y'

<2>一級目錄m同級有一個調用文件a.py

#導入m模塊到本地做用域
import m

#打印當前做用域模塊屬性包含導入的m模塊
print(dir())

#能夠經過m模塊調用到裏面的_x
print(m._x)

#能夠經過m模塊調用到裏面的__y
print(m.__y)
####返回結果:
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'm']
x
y

方式二:from語句
<1>一級目錄m包括本身的__init__.py文件
①__init__.py文件

_x = 'x'
__y = 'y'

<2>一級目錄m同級有一個調用文件a.py

#加載初始化m模塊,_x和__y加入本地名次空間並綁定
from m import _x,__y

#打印當前做用域模塊屬性包含導入的_x,__y
print(dir())

#能夠經過m模塊調用到裏面的_x
print(_x)

#能夠經過m模塊調用到裏面的__y
print(__y)
#####打印結果:
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '__y', '_x']
x
y

總結:依然可使用from語句,訪問全部變量
方式三:from ...import *和__all__
(1)__all__是一個列表,元素是字符串,每個元素都是一個模塊內的變量名
<1>一級目錄m包括本身的__init__.py文件
①__init__.py文件

#加上__all__可讓下劃線開頭的被*導入
__all__ = ['_x','__y']
_x = 'x'
__y = 'y'

<2>一級目錄m同級有一個調用文件a.py

#加載初始化m模塊下全部公共成員(不包括下劃線開頭的)
from m import *

#打印當前做用域模塊屬性包含導入的_x,__y
print(dir())

#能夠經過m模塊調用到裏面的_x
print(_x)

#能夠經過m模塊調用到裏面的__y
print(__y)
#####打印結果:
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '__y', '_x']
x
y

總結:使用from m import *能夠導入__all__列表中的名稱
七.包和子模塊
1.包和子模塊調用方式
<1>一級目錄m包括本身的__init__.py文件,還包括m1.py文件
①__init__.py文件

print(__name__)
x = 5

②m1.py文件

print(__name__)
y  =6

<2>一級目錄m同級有一個調用文件a.py
如何訪問到m1.py中的變量m1?
方式一:a.py

#導入m模塊和m模塊裏的m1
import m.m1
#打印當前做用域模塊m
print(dir())
#經過m1訪問到裏面的y
print(m.m1.y)

###打印結果:
m
m.m1
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'm']
6

方式二:

#直接導入m.m1的屬性y
from m.m1 import y
#打印當前做用域模塊屬性包含y
print(dir())

print(y)
###打印結果:
m
m.m1
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'y']
6

方式三:
須要在__init__.py增長:__all__ = ['x','m1'],使用__all__提供導出的名稱

#加載初始化m模塊下全部公共成員(不包括下劃線開頭的)
from m import *

#打印當前做用域模塊屬性
print(dir())

print(m1.y)
###打印結果:
m
m.m1
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'm1', 'x']
6

方式四:不用__all__使用相對導入
須要在__init__.py增長:from . import m1  #當前目錄下的m1模塊

#加載初始化m模塊下全部公共成員(不包括下劃線開頭的)
from m import *

#打印當前做用域模塊屬性
print(dir())

print(m1.y)
###打印結果:
m
m.m1
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'm1', 'x']
6

2.包和子模塊調用方式總結
(1)使用from m import * 導入
①若是模塊沒有__all__,from m import *只導入非下劃線開頭的模塊的變量。若是是包,子模塊也不會導入,除非在__all__中設置,或__init__.py中使用相對導入
②若是模塊有__all__,from m import * 只導入__all__列表中指定的名稱,哪怕這個名次是下劃線開頭的,或者是子模塊
③from m import (方式導入,使用簡單,可是其反作用是導入大量不須要使用的變量,甚至有可能形成名稱衝突。而__all__能夠控制被導入模塊在這種導入方式下可以提供的變量名稱,就是爲了阻止from m import *導入過多的模塊變量,從而避免衝突。所以,編寫模塊時,應該儘可能加入__all__
(2)from module import name,name2導入
①這種方式的導入是明確的,哪怕是導入子模塊,或者導入下劃線開頭的名稱,程序員能夠有控制的導入名稱和其對應的對象
八.模塊變量修改
<1>一級目錄m包括本身的__init__.py文件,還包括m1.py文件
①__init__.py文件

print(__name__)
x = 5

②m1.py文件

print(__name__)
y  =6

<2>一級目錄m同級有一個調用文件a.py
a.py文件修改m1.py模塊裏的y
#導入m模塊和m模塊裏的m1

from m import m1

#打印當前做用域模塊屬性
print(dir())

#打印y
print(m1.y)
#修改y
m1.y = 100
#再次打印y
print(m1.y)
######打印結果:
m
m.m1
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'm1']
6
100

總結:
模塊對象是同一個,所以模塊的變量也是同一個,對模塊變量的修改,會影響全部使用者。除非萬不得已,或明確知道本身在作什麼,不然不要修改模塊的變量(能夠經過猴子補丁動態修改模塊)
九.包管理
1.爲何使用包管理
(1)python的模塊或者源文件直接能夠複製到目標項目目錄中,就能夠導入使用了。可是爲了更多項目調用,或者共享給別人,就須要打包,或發佈到網絡,以便供人使用。目的也是爲了複用。
(2)Pypi(Python Package Index),公共的模塊存儲中心
2.主要工具
(1)distutils:官方distutils,使用安裝腳本setup.py來構建,安裝包
(2)setuptools:它是替代distutils的加強版工具集,包含easy_install工具,使用ez_setup.py文件。支持egg格式的構建和安裝提供查詢,下載,安裝,構建,發佈,管理等包管理功能,setuptools是包管理的核心模塊
(3)pip:pip目前包管理的事實標準。構建在setuptools之上,替代easy_install的。一樣提供豐富的包管理功能。
(4)wheel:提供bdist_wheel做爲setuptools的擴展命令,這個命令能夠用來生成wheel打包格式。pip提供了一個wheel子命令來安裝wheel包。固然,須要先安裝wheel模塊。它可讓Python庫以二進制形式安裝,而不須要在本地編譯
3.使用setup.py打包:setup.py建立一個源代碼分發包
(1)查看命令:python setup.py --help-commands
(2)查看命令的幫助命令:python setup.py --help
(3)build命令,編譯
<1>一級目錄m包括二級目錄m2和本身的__init__.py文件,二級目錄m2包括m21目錄和本身的__init__.py,三級目錄m2包括本身的__init__.py
<2>建立一個build目錄命令:Python setup.py build
①如下是packages=['m']配置結果

E:\shishi\aaa>python setup.py build
running build
running build_py
creating build
creating build\lib
creating build\lib\m
copying m\m1.py -> build\lib\m
copying m\__init__.py -> build\lib\m

總結:在項目目錄下多了build目錄,有一個lib子目錄,lib下就是模塊m的目錄了。m目錄下的*.py文件被複制了,可是子目錄沒有被複制
②如下packages=['m.m2.m21']配置的結果

E:\shishi\aaa>python setup.py build
running build
running build_py
creating build\lib
creating build\lib\m
creating build\lib\m\m2
creating build\lib\m\m2\m21
copying m\m2\m21\__init__.py -> build\lib\m\m2\m21

總結:能夠看出,逐級構建了童顏的目錄結構,並只拷貝了m21的__init__.py文件
③如下packages=['m','m.m2','m.m2.m21']配置結果

E:\shishi\aaa>python setup.py build
running build
running build_py
creating build\lib
creating build\lib\m
copying m\__init__.py -> build\lib\m
creating build\lib\m\m2
copying m\m2\__init__.py -> build\lib\m\m2
creating build\lib\m\m2\m21
copying m\m2\m21\__init__.py -> build\lib\m\m2\m21

總結:build獲得的文件,直接拷貝到其餘項目就能夠用
(5)install命令,安裝
build後就能夠install,直接運行命令:python setup.py install
就把當前打的包安裝到當前python3環境裏(E:\python3\Lib\site-packages)
若是沒有build,會先build編譯,而後安裝
(6)sdist命令,分發
<1>sdist命令:建立源代碼的分發包
<2>產生一個dist目錄,裏面生成一個帶版本號的壓縮包。
<3>在其餘地方解壓這個文件,裏面有setup.py,就可使用python setup.py install 安裝了,也能夠pip install m-0.1.0zip直接使用ipi安裝這個壓縮包
①製做windows下的分發包命令:python setup.py sdist_wininst
獲得zip包:E:\shishi\aaa\dist\m-0.0.1.zip包
②製做python setup.py bdist_rpm
能夠把本身寫好的模塊發佈到公共的Pypi上,也能夠搭建Pypi私服,供企業內部使用,Pypi裏面的模塊沒有太好的審覈機制,不保證安全,請慎重使用。

十.經過模塊實現插件化開發
動態導入:運行時,根據用戶需求(提供字符串),找到模塊的資源動態加載起來。
1.內建函數__import__()
__import__(name,globals=None,locals=None,fromlist=(),level=0)
name:模塊名
import語句本質上就是調用這個函數。可是不鼓勵直接使用它。建議使用importlib.import_module()
<1>test函數

class A:
    def showme(self):
        print('test模塊下的A類')

<2>插件函數

#插件函數接
def plugin_load():

    #使用__import__是字符串方式導入模塊賦值給mod(等價於import test)
    mod = __import__('test')

    #打印這個模塊對象
    #print(mod)                         #打印結果:<module 'test' from 'E:\\shishi\\aaa\\m\\test.py'>

    #模塊對象mod.A拿屬性
    #print(mod.A)                       #打印結果:<class 'test.A'>

    #實例化A類
    getattr(mod, 'A')().showme()       #打印結果:test模塊下的A類

if __name__ == '__main__':
    #須要的時候動態加載
    plugin_load()

2.內建函數importlib.import_module()
importlib.import_module(name,package=None)
支持絕對導入和相對導入,若是是相對導入,package必須設置
<1>test函數

class A:
    def showme(self):
        print('test模塊下的A類')

<2>插件函數

import importlib

#插件函數接
def plugin_load():

    #使用importlib方式導入模塊賦值給mod
    mod = importlib.import_module('test')

    #打印這個模塊對象
    #print(mod)                         #打印結果:<module 'test' from 'E:\\shishi\\aaa\\m\\test.py'>

    #模塊對象mod.A拿屬性
    #print(mod.A)                       #打印結果:<class 'test.A'>

    #實例化A類
    getattr(mod, 'A')().showme()       #打印結果:test模塊下的A類

if __name__ == '__main__':
    #須要的時候動態加載
    plugin_load()

3.經過importlib實現插件化核心代碼
<1>test函數

class A:
    def showme(self):
        print('test模塊下的A類')

<2>插件函數

import importlib

#插件函數接收調用的模塊名字和調用的類名
def plugin_load(plugin_name:str,sep=":"):
    #三元組方式切割得到想要的模塊名字和調用的類名
    m,_,c = plugin_name.partition(sep)

    #模塊名字
    #print(m)   #返回結果:test
    #類名名字
    #print(c)   #返回結果:A

    # 使用importlib方式導入模塊賦值給mod
    mod = importlib.import_module(m)

    #經過getattr獲取test模塊對象下的A類
    cls = getattr(mod,c)
    #把這個A類返回
    return cls()

if __name__ == '__main__':
    #第一步:須要的時候動態加載plugin_load函數把調用的模塊名字和調用的類傳進去
    #最後一步:接收返回的A類showme()實例化
    plugin_load('test:A').showme()            #返回結果:test模塊下的A類

4.插件化編程技術
(1)依賴的技術
①反射:運行時獲取類型的信息,能夠動態維護類型數據
②動態import:程序運行過程當中,接收用戶指令或請求,啓動相應的插件動態import:推薦使用importlib模塊,實現動態import模塊的能力
③多線程:能夠開啓一個線程,等待用戶輸入,從而加載指定名稱的模塊
(2)加載的時機
何時加載合適?程序啓動的時候,仍是程序運行中呢?
①程序啓動時:像pycharm這樣的工具,須要不少組件,這些組件多是插件,啓動的時候掃描固定的目錄,加載插件
②程序運行中:程序運行過程當中,接收用戶指令或請求,啓動相應的插件
兩種方式各有利弊,若是插件過多,會致使程序啓動很慢,若是用戶須要時再加載,若是插件太大或者依賴多,插件也會啓動慢。因此先加載必須的,經常使用的插件,其餘插件使用時,發現須要,動態載入。
5.插件化開發的應用
軟件的設計不可能作到盡善盡美,或者在某些功能上,不可能作的專業,須要專業的客戶本身加強。
(1)接口和插件的區別?
①接口:每每是暴露出來的功能(類的方法或者是函數),實現動態模塊加載(操做),例如模塊提供的函數或方法,加載模塊後調用這些函數完成功能。接口也是一種規範,它約定了必須實現的功能(必須提供某名稱的函數),可是不關心怎麼實現這個功能。有的地方叫api,是經過一個網址訪問後臺某一個python模塊的某一個類的某一個方法,由於方法才能作事,因此瀏覽器的某一個地址實際指向的是後臺的某一個進行的server裏面的一個某一個模塊某一個類的某一個方法。通常不關內心面怎麼實現,只關心這個操做能作什麼事情,這個操做的名稱和簽名
②插件:是能不能把模塊的資源動態的加載進去用。是把模塊加載到系統中,運行它,加強當前系統功能,或者提供系統不具有的功能,每每插件技術應用的框架設計中。系統自己設計簡單化,輕量級,實現基本功能後,其餘功能經過插件加入進來,方便擴展。
經常使用的python標準庫模塊
包括:(time模塊-datetime模塊-random模塊-pathlib模塊-os模塊-shutil模塊-CSV模塊-argparse模塊-sys模塊-json&pickle&shelve&xml模塊-re模塊-logging模塊-hashlib模塊)
time模塊
1.三個掌握時間的表達式(時間戳Timestamp-結構化struct_time-字符串時間Fomat string)
(1)時間戳Timestamp表達式

 

 

import time
#秒數,從1970年1月1日開始算到如今
print(time.time())               #輸出結果:1517556698.214673

(2)結構化時間struct_time表達式

import time
##時間對象(年,月,周,日,時,分,秒)
print(time.localtime())                   #輸出結果:time.struct_time(tm_year=2018, tm_mon=9, tm_mday=5, tm_hour=14, tm_min=17, tm_sec=2, tm_wday=2, tm_yday=248, tm_isdst=0)
t=time.localtime()
#年份
print(t.tm_year)                          #輸出結果:2018
#
print(t.tm_wday)                          #輸出結果:2
#世界標準時間UTC          
print(time.gmtime())                      #輸出結果:time.struct_time(tm_year=2018, tm_mon=2, tm_mday=2, tm_hour=7, tm_min=43, tm_sec=17, tm_wday=4, tm_yday=33, tm_isdst=0)

經過time.mktime將結構化時間轉換成時間戳----struct_time轉Timestamp

import time
#time.localtime拿到當前結構化時間在用mktime將結構化時間轉換成時間戳
print(time.mktime(time.localtime()))        #輸出結果:1536128806.0

(3)字符串時間Fomat string表達式(須要拿時間戳,結構化時間轉換)
方式一:經過time.strftime將結構化時間轉成字符串時間-------struct_time轉Fomat string

import time
#time.localtime拿到當前結構化時間,用time.strftime將結構化時間轉換成字符串時間
print(time.strftime("%Y-%m-%d %X",time.localtime()))    #輸出結果:2018-09-05 14:28:56

方式二:經過time.strptime將字符串時間轉換成結構化時間---Fomat string轉struct_time

import time
print(time.strptime("2018:09:05:14:36:22","%Y:%m:%d:%X"))   #輸出結果:time.struct_time(tm_year=2018, tm_mon=9, tm_mday=5, tm_hour=14, tm_min=36, tm_sec=22, tm_wday=2, tm_yday=248, tm_isdst=-1)

2.顯示直觀時間的方式
方式一:asctime將結構化時間轉化成固定的字符串時間,若是沒有參數,將會 time.localtime()做爲參數轉入

import time
print(time.asctime())     #輸出結果:Fri Feb  2 16:20:49 2018

方式二:ctime把時間戳轉化成固定的字符串時間,若是沒有參數,將會 time.localtime()做爲參數轉入

import time
print(time.ctime())     #輸出結果:Fri Feb  2 16:20:49 2018

3.倆個其它參數
sleep:線程推遲指定的時間運行,單位爲秒
clock():在linux系統上返回進程時間,在windows中返回時間差
datetime模塊(對日期,時間,時間戳的處理)
1.datetime類
(1)類方法:
<1>today()返回本地時區當前時間的datetime對象

import datetime
time=datetime.datetime.today()
print(time)
##返回:
2019-07-19 10:34:51.816176

<2>now(tz=None)返回當前時間的datetime對象,時間到微秒,若是tz爲None,返回和today()同樣

import datetime
time = datetime.datetime.now()
print(time)
##返回:
2019-07-19 10:44:05.326834

<3>utcnow()沒有時區的當前時間(跟東8區差8個小時)

import datetime
time=datetime.datetime.utcnow()
print(time)
##返回:
2019-07-19 02:37:05.023794

<4>fromtimestamp(timestamp,tz=None)從一個時間戳返回一個datetime對象

import datetime
time = datetime.datetime.now().timestamp()
print('當前時間戳:',time)
t = datetime.datetime.fromtimestamp(int(time))  #時間戳time構造出一個datetime對象
print('經過時間戳返回datetime對象:',t)
##返回:
當前時間戳: 1563505535.150608
經過時間戳返回datetime對象: 2019-07-19 11:05:35

(2)datetime對象
<1>timestamp()返回一個到微秒的時間戳
---時間戳:格林威治時間1970年1月1日0點到如今的秒數

import datetime
time = datetime.datetime.now().timestamp()
print(time)
返回:前面整數部分是到如今的秒數
1563504009.518347

<2>構造方法datetime.datetime(2019,07,19,29,43,79043)
舉例:構造一個新時間

>>> import datetime
>>> a = datetime.datetime(2019, 7,19,17,22)
>>> a
datetime.datetime(2019, 7, 19, 17, 22)

<3>year,month,day,hour,minute,second,microsecond,取datetime對象的年月日時分秒及微秒

>>> import datetime
>>> a = datetime.datetime(2019, 7,19,17,22)
>>> a
datetime.datetime(2019, 7, 19, 17, 22)
#取年
>>> a.year
2019
#取日
>>> a.day
19

<4>weekday()返回星期的天,週一0,週日6

>>> import datetime
>>> a = datetime.datetime.now()
>>> a
>>> datetime.datetime(2019, 7, 19, 12, 2, 34, 941509)
>>> a.weekday()
4

<5>isoweekday()返回星期的天,週一1,週日7

>>> import datetime
>>> a = datetime.datetime.now()
>>> a
datetime.datetime(2019, 7, 19, 12, 2, 34, 941509)
>>> a.isoweekday()
5

<6>date()返回日期date對象

>>> import datetime
>>> a = datetime.datetime.now()
>>> a
datetime.datetime(2019, 7, 19, 12, 5, 35, 946047)
>>> a.date()
datetime.date(2019, 7, 19)

<7>time()返回時間time對象

>>> import datetime
>>> a = datetime.datetime.now()
>>> a
datetime.datetime(2019, 7, 19, 12, 5, 35, 946047)
>>> a.time()
datetime.time(12, 5, 35, 946047)

<8>replace()修改並返回新的時間

>>> import datetime
>>> a = datetime.datetime.now()
>>> a
datetime.datetime(2019, 7, 19, 12, 5, 35, 946047)
>>> a.replace(2020)
datetime.datetime(2020, 7, 19, 12, 5, 35, 946047)

<9>isocalendar()返回一個三元組(年,週數,周的天)

>>> import datetime
>>> a = datetime.datetime.now()
>>> a
datetime.datetime(2020, 7, 19, 12, 5, 35, 946047)
>>> a.isocalendar()
(2019, 29, 5)

2.日期格式化
(1)類方法strptime(date_string,format),返回datetime對象
(2)對象方法strftime(format),返回字符串
(3)字符串format函數格式化

import datetime
dt = datetime.datetime.strptime("19/07/19 16:30", "%d/%m/%y %H:%M")
#strftime對象方法
print(dt.strftime("%Y-%m-%d %H:%M:%S"))
#format函數格式化
print("{0:%Y}/{0:%m}/{0:%d} {0:%H}:{0:%M}:{0:%S}".format(dt))
返回:
2019-07-19 16:30:00
2019/07/19 16:30:00

3.timedelta對象
(1)datetime2 = datetime1 + timedelta
(2)datetime2 = datetime1 - timedelta
(3)timedelta = datetime1 - datetime1
(4)構造方法
<1>datetime.timedelta(days=0,seconds=0,microsecond=0,microsecond=0,minutes=0,hours=0,weeks=0)
<2>year = datetime.timedelta(days=365)

import datetime
#當前時間
now = datetime.datetime.now()
print(now)
#構造24小時時間差對象
h = datetime.timedelta(hours=24)
print(h)
#當前時間減去24小時時間
new =datetime.datetime.now() - h
print(new)
返回:
2019-07-19 11:53:45.091903
1 day, 0:00:00
2019-07-18 11:53:45.091903

(5)total_seconds()返回時間差的總秒數

import datetime
#當前時間
now = datetime.datetime.now()
print(now)
#構造24小時時間差對象
h = datetime.timedelta(hours=24)
print(h)
#當前時間減去24小時時間
new =datetime.datetime.now() - h
print(new)
#求當前時間和最新時間的時間差
xx =(datetime.datetime.now() - new).total_seconds()
print(xx)
返回:
2019-07-19 12:01:58.609131
1 day, 0:00:00
2019-07-18 12:01:58.609131
86400.0

random模塊(隨機模塊)
(1)random默認0-1的隨機浮點數

import random
ret=random.random()
print(ret)

輸出:
0.4613546703901257
(2)random.randin隨機取出範圍裏的值

import random
ret=random.randint(1,3) #1,2,3裏隨機取值 print(ret)

輸出:
1或2或3
(3)random.randrange隨機取出範圍裏的值不包括最後一個值

import random
ret=random.randrange(1,3) #隨機取出1-2裏的值 print(ret)

輸出:
1或2
(4)random.choice隨機取出裏列表裏的某一個值

import random
ret=random.choice([11,22,33,44,55]) #隨機選一個 print(ret)

輸出:
11或22或33或44或55
(5)random.sample隨機取出裏列表裏的某倆個值

import random
ret=random.sample([11,22,33,44,55],2) #隨機選倆個 print(ret)

輸出:
[44, 11]
(6)random.uniform隨機取任意範圍浮點數

import random
ret=random.uniform(1,4) print(ret)

輸出:
2.4613546703901257
(7)random.shuffle打亂順序

ret=[1,2,3,4,5]
random.shuffle(ret)
print(ret)

輸出:
[4, 2, 1, 5, 3]
舉例:隨機生成5數字跟字母相拼的位驗證碼功能:

import random

def v_code():
    ret=""
    for i in range(5):
        num=random.randint(0,9)
        alf=chr(random.randint(65,122))
        s=str(random.choice([num,alf]))
        ret+=s
    return ret
print(v_code())

思路:
定義一個結果字符串初始值爲ret=""
循環,驗證碼有幾位循環幾回for i in range(5):
隨機數字生成:random.randint(0,9)
隨機字母經過chr把數字轉換成對應字母生成:chr(random.randint(65,122))
隨機取出數字和字母的值(random.choice([num,alf])),str轉換一下
拼接起來ret+=s
最後返回return ret
pathlib模塊(文件目錄操做)
from pathlib import Path
1.目錄操做
(1)當前目錄

>>> from pathlib import Path
>>> p = Path()
>>> print(p.absolute())
/root

(2)當前目錄下的a/b/c/d

>>> from pathlib import Path
>>> p = Path('a','b','c/d')
>>> print(p)
a/b/c/d

(3)根下的etc目錄

>>> from pathlib import Path
>>> p = Path('/etc')
>>> print(p)
/etc

2.路徑拼接和分解
(1)操做符/
Paht對象 / Path對象
Path對象 / 字符串或者字符串 / Paht對象

#當前路徑
>>> from pathlib import Path
>>> p = Path('a','b')
#當前p路徑
>>> p
PosixPath('a/b')
#加上c/d
>>> p = p / 'c' / 'd'
>>> p
PosixPath('a/b/c/d')
#加上e
>>> p /= 'e'
>>> p
PosixPath('a/b/c/d/e')

(2)分解
parts屬性,能夠返回路徑中的每個部分
(3)joinpath
joinpath(*other)鏈接多個字符串到Path對象中

>>> from pathlib import Path
>>> p = Path()
>>> print(p.absolute())      #當前路徑
/root
>>> p = p.joinpath('a','b')  #返回新路徑
>>> print(p.absolute())
/root/a/b

3.獲取路徑
str獲取路徑字符串
bytes獲取路徑字符串的bytes

>>> from pathlib import Path
>>> p = Path('/etc')
>>> print(str(p),bytes(p))
/etc b'/etc'

4.父目錄
parent目錄的邏輯父目錄
parents父目錄序列,索引0是直接的父
(1)查看父目錄

>>> from pathlib import Path
>>> p = Path('/etc')
>>> p
PosixPath('/etc')
#查看父目錄
>>> p.parents                   
PosixPath('/')

(2)查看每層父目錄

>>> from pathlib import Path
>>> p = Path('a','b','c/d')
>>> p
PosixPath('a/b/c/d')
#查看每層父目錄,absolute轉化成絕對路徑
>>> list(p.absolute().parents)
[PosixPath('/root/a/b/c'), PosixPath('/root/a/b'), PosixPath('/root/a'), PosixPath('/root'), PosixPath('/')]
#迭代查看第一層父目錄
>>> next(iter(p.absolute().parents))
PosixPath('/root/a/b/c')

5.處理路徑用到的方法
(1)name目錄的最後一個部分

>>> p =Path('/etc/sysconfig/network/xx.cfg.gz')
>>> p.name
'xx.cfg.gz'

(2)suffix目錄中最後一個部分的擴展名

>>> p =Path('/etc/sysconfig/network/xx.cfg.gz')
>>> p.suffix
'.gz'

(3)stem目錄最後一個部分,沒有後綴

>>> p =Path('/etc/sysconfig/network/xx.cfg.gz')
>>> p.stem
'xx.cfg'

(4)suffixes返回多個擴展名列表

>>> p =Path('/etc/sysconfig/network/xx.cfg.gz')
>>> p.suffixes
['.cfg', '.gz']

(5)with_suffix(suffix)補充擴展名到路徑尾部,分會新的路徑,擴展名存在則無效

#把擴展名gz換成tar
>>> p =Path('/etc/sysconfig/network/xx.cfg.gz')
>>> p.with_suffix('.tar')
PosixPath('/etc/sysconfig/network/xx.cfg.tar')

(6)with_name(name)替換目錄最後一個部分返回一個新的路徑

#把最後一部分名字改成ii.ifg
>>> p =Path('/etc/sysconfig/network/xx.cfg.gz')
>>> p.with_name('ii.ifg')
PosixPath('/etc/sysconfig/network/ii.ifg')

(7)cwd()返回當前工做目錄

>>> from pathlib import Path
#當前描述路徑
>>> p = Path('a','b','c/d')
>>> p
PosixPath('a/b/c/d')
#當前工做目錄
>>> p.cwd()
PosixPath('/root')

(8)home()返回當前家目錄

>>> p = Path('a','b','c/d')
>>> p
PosixPath('a/b/c/d')
#當前家目錄
>>> p.home()
PosixPath('/root')

(9)is_dir()是不是目錄

#給/tmp下建立一個lysql.tar.gz文件
>>> p = Path('/tmp/lysql.tar.gz')
>>> p.touch()
#查看/tmp下的lysql.tar.gz是不是目錄
>>> p.is_dir()
False

(10)is_file()是不是普通文件

#給/tmp下建立一個lysql.tar.gz文件
>>> p = Path('/tmp/lysql.tar.gz')
>>> p.touch()
#查看/tmp下的lysql.tar.gz是不是普通文件
>>> p.is_file()
True

(11)is_socket()是不是socket文件
(12)is_block_device()是不是塊設備
(13)is_char_device()是不是字符設備
(14)is_absolute()是不是絕對路徑
(15)resolve()返回一個新的路徑,這個新路徑就是當前Path對象的絕對路徑,若是是軟連接則直接被解析

>>> from pathlib import Path
#給/tmp下建立一個lysql.tar.gz文件
>>> p = Path('/tmp/lysql.tar.gz')
>>> p.touch()
#返回lysql.tar.gz文件的絕對路徑
>>> p.resolve()
PosixPath('/tmp/lysql.tar.gz')

(16)absolute()也能夠獲取絕對路徑,可是推薦使用resolve()
(17)exists()目錄或文件是否存在
(18)rmdir()刪除空目錄,沒有提供判斷目錄爲空的方法
(19)touch(mode=0o666,exist_ok=True)建立一個文件

>>> from pathlib import Path
#給/tmp下建立一個lysql.tar.gz文件
>>> p = Path('/tmp/lysql.tar.gz')
>>> p.touch()

(20)as_uri()將路徑返回成URL,列如'file:///etc/passwd'

#將路/tmp/lysql.tar.gz徑返回成URL
>>> p.as_uri()
'file:///tmp/lysql.tar.gz'

(21)mkdir(mode=0o777,parents=False,exist_ok=False)
參數:parents,是否建立父目錄,True等同於mkdir -p;False時,父目錄不存在,則拋出FileNotFoundError
參數:exist_ok參數,在3.5版本加入。False時,路徑存在,拋出FileExistsError;True時,FileExistsError被忽略

>>> from pathlib import Path
#給/tmp下建立一個xixi目錄
>>> p = Path('/tmp/xixi')
>>> p.mkdir(parents=True)

(22)iterdir()迭代當前目錄

>>> from pathlib import Path
#迭代當前目錄
>>> for x in Path().iterdir():
#判斷是不是目錄打印出來
...     if x.is_dir():
...         print(x)

舉例:遍歷,並判斷文件類型,若是是目錄是否能夠判斷其是否爲空

from pathlib import Path
p = Path('/etc')    
#循環/etc全部的父目錄路徑
for x in p.parents[len(p.parents)-1].iterdir():
    print(x,end='\t')                 #打印/etc全部的父目錄
    if x.is_dir():                    #判斷是不是目錄
        flag = False
        for _ in x.iterdir():         #迭代目錄判斷是不是空目錄
            flag = True
            break
        #for循環是否可使用else子句
        print('dir','不爲空' if flag else '爲空' , sep='\t')
    elif x.is_file():   #不然判斷是不是文件
        print('文件')
    else:
        print('其它文件')

6.通配符
(1)glob(pattern)通配給定的模式
①當前目錄

>>> from pathlib import Path
#當前目錄下x*開頭的全部文件或目錄
>>> list(Path().glob('x*'))
[PosixPath('xx.py'), PosixPath('xxx.txt'), PosixPath('x.txt'), PosixPath('xixi.txt'), PosixPath('xixi')]

②當前目錄下一層目錄

>>> from pathlib import Path
#當前目錄下的下層目錄下*.py開頭的全部文件或目錄
>>> list(Path().glob('*/*.py'))
[PosixPath('xixi/xx.py')]

③當前目錄下層全部目錄

>>> from pathlib import Path
#當前目錄算起往下任意目錄*.py開頭的全部文件或目錄
>>> list(Path().glob('**/*.py'))
[PosixPath('xx.py'), PosixPath('xixi/xx.py')]

(2)rglob(pattern)通配給定的模式,遞歸目錄

>>> from pathlib import Path
#遞歸查找當前目錄算起往下任意目錄*.py開頭的全部文件或目錄
>>> list(Path().rglob('*.py'))
[PosixPath('xx.py'), PosixPath('xixi/xx.py')]

7.匹配
(1)match(pattern)
模式匹配,成功返回True

>>> from pathlib import Path
匹配當前目錄是否有*.py的文件或目錄
>>> Path('.py').match('*.py')
True

8.文件操做
(1)open(mode='r',buffering=-1,encoding=None,errors=None,newline=None):使用方法相似內建函數open。返回一個文件對象
(2)read_bytes():以'rb'讀取路徑對應文件,並返回二進制流
(3)read_text(encoding=None,errors=None):以'rt'方式讀取路徑對應文件,返回文本

>>> from pathlib import Path
#建立一個xixi.txt文件
p = Path('/tmp/xixi/xixi.txt')
#寫(每次清空)
>>> p.write_text('xixi')
4
#
>>> p.read_text()
'xixi'
(4)Path.write_bytes(data):以'wb'方式寫入數據到路徑對應文件
(5)write_text(data,encoding=None,errors=None):以'wt'方式寫入字符串到路徑對應文件。
>>> from pathlib import Path
#建立一個xixi.txt文件
p = Path('/tmp/xixi/xixi.txt')
#寫(每次清空)
>>> p.write_text('xixi')
4

os模塊(是與操做系統交互的一個接口(操做系統打交道)
(1)os.getcwd()獲取當前工做目錄,即當前python腳本工做的目錄路徑

import os
print(os.getcwd())

輸出:
E:\cc\os
(2)os.chdir('dirname')改變當前腳本工做目錄;至關於shell下cd

import os
print(os.getcwd())   #當前目錄
os.chdir("..")       #至關於cd .. print(os.getcwd())   #返回上層目錄

輸出:
E:\cc\os
E:\cc
(3)os.makedirs('dirname1/dirname2')可建立多層遞歸目錄,

import os
os.makedirs('dirname1/dirname2') #當前目錄下建立dirname1目錄裏面在建立dirname2目錄

(4)os.removedirs('dirname1') 若目錄爲空,則刪除,並遞歸到上一級目錄,若也爲空,則刪除,以此類

import os
os.removedirs('dirname1/dirname2')  #刪除dirname1和裏面的dirname2(若是dirname1裏有文件或目錄,則不會被刪除)

(5)os.mkdir('dirname') 生成單級目錄;至關於shell中mkdir dirname

import os
os.mkdir('dirname')   #當前目錄下建立dirname目錄

(6)os.rmdir('dirname') 刪除單級空目錄;若目錄不爲空則沒法刪除

import os
os.rmdir('dirname')    #刪除當前目錄下的dirname(若是dirname裏有文件或目錄,則不會被刪除)

(7)os.listdir('dirname')列出指定目錄下的全部文件和子目錄,包括隱藏文件,並以列表方式打印

import os
print(os.listdir())  

打印:
['dirname', 'os_test.py']
(8)os.remove()刪除一個文件

import os
os.remove('xixi.txt')  #刪除當前目錄下xixi.txt文件

(9)os.rename("oldname","newname")遞歸移動文件

>>> import os
#把tmp目錄下的xixi目錄裏的東西拷貝到otp目錄
>>> os.rename('/tmp/xixi','/otp')

(10)os.stat('path/filename')獲取文件/目錄信息

import os
print(os.stat("xixi.txt"))   #獲取xixi.txt的文件信息

輸出:
posix.stat_result(st_mode=33188, st_ino=3936489, st_dev=64768L, st_nlink=1, st_uid=0, st_gid=0, st_size=0, st_atime=1535704707, st_mtime=1535704707, st_ctime=1536133819)
(11)os.sep 輸出操做系統特定的路徑分隔符win下爲"\\" ,linux下爲"/"
(12)os.linesep 輸出當前平臺使用的行終止符win下爲"\r\n",linux下爲"\n"
(13)os.name 輸出字符串指示當前使用平臺
(14)os.system("bash command")運行shell命令,直接顯示

import os
os.system("ls")             #至關於當前目錄下執行ls命令

(15)os.environ獲取系統環境變量
(16)os.path.split(path)將path分割成目錄和文件名二元組返回

import os
print(os.path.split("E:\cc\os\os_test.py"))   #把路徑和名字分開以元祖方式顯示出來

輸出:
('E:\\cc\\os', 'os_test.py')
(17)os.path.dirname(path)返回path的目錄

import os
print(os.path.dirname("E:\cc\os\os_test.py"))   #取os_test.py的文件路徑

輸出:
E:\cc\os
(18)os.path.basename(path) 返回path最後的文件名。

import os
print(os.path.basename("E:\cc\os\os_test.py"))   #取os_test.py文件名字

輸出:
os_test.py
(19)os.path.exists(path)若是path存在,返回True;若是path不存在,返回False
(20)os.path.isabs(path)若是path是絕對路徑,返回True
(21)os.path.isdir(path)若是path是一個存在的目錄,則返回true。
(22)os.path.join(paht1[,path2[, ...]])將多個路徑組合返回,第一個絕對路徑以前的參數將被忽略
路徑是:E:\cc\os\os_test.py

import os
a="E:\cc"
b="os\os_test.py"
os.path.join(a,b)   #拼接好的路徑E:\cc\os\os_test.py

(23)os.path.getatime(path) 返回path所指向的文件或目錄的最後存取時間
(24)os.path.getmtime(path) 返回path所指向的文件或目錄的最後修改時間
shutil模塊(文件目錄拷貝)
1.拷貝
(1)copyfileobj(fsrc,fdst[,length])文件對象的複製,fsrc和fdst是open打開的文件對象,複製內容。fdst要求可寫
length指定了表示buffer的大小;

>>> from pathlib import Path
#建立test文件寫入abcde
>>> Path('test').write_text('abcde')
5
>>> Path('test').read_text()
'abcde'
>>> import shutil
>>> with open('test') as f1:
...     with open('test2','w') as f2:
#經過shutil模塊把test內容拷貝到test2中
...         shutil.copyfileobj(f1,f2)

(2)copyfile(src,dst,*,follow_symlinks=True):複製文件內容,不含元數據。src,dst爲文件的路徑字符串
本質山調用的就是copyfileobj,因此不帶元數據二進制內容複製。

>>> import shutil
>>> shutil.copyfile('test','test2')
'test2'

(3)copymode(src,dst,*,follow_symlinks=True):複製權限

>>> import shutil
>>> shutil.copymode('test','test2')

(4)copystat(src,dst,*follow_symlinks=True):複製元數據,stat包含權限

>>> import shutil
>>> shutil.copystat('test','test2')

(5)copy(src,dst,*,follow_symlinks=True):複製文件內容,權限和部分元數據,不包括建立時間和修改時間。
本質上是調用:copyfile(src,dst,*,follow_symlinks=True)和copymode(src,dst,*,follow_symlinks=True)

>>> import shutil
>>> shutil.copy('test','test2')

(6)copy2比copy多了個複製所有元數據,但須要平臺支持
本質上調用的是:copyfile(src,dst,*,follow_symlinks=True)和copystat(src,dst,*follow_symlinks=True)

>>> import shutil
>>> shutil.copy2('test','test2')

(7)copytree(src,dst,symlinks=False,ignore=None,copy_function=copy2,ignore_dangling_symlinks=False):遞歸複製目錄。默認使用copy2,也就是帶多的元數據複製
scr,dst必須是目錄,src必須存在,dst必須不存在
舉例:

import shutil
#把tmp下的xixi裏的全部東西拷貝到otp下的aaa裏,且aaa目錄不能存在
>>> shutil.copytree('/tmp/xixi','/otp/aaa')
'/otp/aaa'

ignore = func,提供一個callable(src,names)->ignored_names。提供一個函數,它會被調用。src是源目錄,nmaes是os.listdir(src)的結果,就是列出src中的文件名,返回值是要被過濾的文件名的set類型數據。
舉例:

import shutil
def ignore(src, names):
    #filter傳兩個參數:1.函數。2.迭代的東西
    ig = filter(lambda x: x.startswith('a'),names) #判斷文件名必須以a開頭的文件或目錄不拷貝
    return set(ig)
#把tmp目錄下的xixi目錄裏的東西拷貝到top目錄下的abc目錄(abc目錄不能存在)
shutil.copytree('/tmp/xixi','/otp/abc',ignore=ignore)

2.刪除:
shutil.rmtree(path,ignore_errors=False,onerror=None):遞歸刪除。如同rm -rf同樣危險。
它不是原子操做,有可能刪除錯誤,就會中斷,已經刪除的就刪除了。
ignore_errors爲true,忽略錯誤。當爲False或者omitted時onerror生效。
onerror爲callable,接受函數function,path和execinfo。

>>> import shutil
#刪除otp目錄下的abc
>>> shutil.rmtree('/otp/abc')   #相似rm -rf

3.move移動
move(src,dst,copy_function=copy2):遞歸移動文件,目錄到目標,返回目標
自己使用的是os.rename方法
若是不支持rename,入股歐式目錄則想copytree在刪除源目錄。
默認使用copy2方法。

>>> import os
#把tmp目錄下的xixi目錄裏的東西拷貝到otp目錄
>>> os.rename('/tmp/xixi','/otp')

CSV模塊
一.CSV文件
1.csv文件簡介
(1)逗號分隔值Comma-Separated Values
(2)CSV是一個被行分隔符,列分隔符劃分紅行和列的文本文件
(3)沒有指定字符編碼
2.行分隔符爲\r\n,最後一行能夠沒有換行符
(1)列分隔符常爲逗號或者製表符
(2)每一行成爲一條record(記錄)
3.字段可使用雙引號括起來,也能夠不使用。入股字段中出現了雙引號,逗號,換行符必須使用雙引號括起來。入股字段的值是雙引號,使用兩個雙引號表示一個轉義
(1)表頭可選,和字段列對齊就好了

from pathlib import Path
#構建文件對象
path = 'e:/wangshiyao/aaa/xixi.csv'
p = Path(path)

#判斷是否有這個路徑
if not p.parent.exists():
    p.parent.mkdir(parents=True)

#寫入內容
line = '''\
id,name,age,comment
1,dongdong,18,中國
2,xixi,"I'm 23",,
3,nannan,33,"this is a ""test"" string."
4,beibei,"中國

人民
"
'''

p.write_text(line)

返回:

二.CSV模塊
1.reader(csvfile,dialect='excel',**fmtparams):返回DictReader的實例,是個行迭代器。
(1)delimiter列分隔符,逗號
(2)lineterminator行分隔符\r\n
(3)quotechar字段的引用符號,缺省爲",雙引號
2.雙引號的處理:
(1)doublequote雙引號的處理,默認爲True.若是和quotechar爲同一個,True,則使用2個雙引號表示
(2)False表示使用轉義字符將做爲雙一號的前綴
(3)escapechar一個轉義字符,默認爲None。
(4)quoting指定雙引號的規則。QUOTE_ALL全部字段;QUOTE_MINIMAL特殊字符字段;
(5)QUOTE_NONNUMERIC非數字字段;QUOTE_NONE都不使用引號
3.writer(csvfile,dialect='excel',**fmtparams):返回DictWriter的實例
4.主要方法有writerow,writerows

from pathlib import Path
import csv

#構建文件對象
path = 'e:/wangshiyao/aaa/xixi.csv'
p = Path(path)

#判斷是否有這個路徑
if not p.parent.exists():
    p.parent.mkdir(parents=True)

#寫入內容
line = [1,"xixi",20]
line2 = [(2,'dongdong',18),(3,'nannan',23),(4,'beibei',19)]

#若是有這個路徑建立這個文件
with open(path,'w',newline='') as f:  #newline=''去除空行
    #給它一個文件對象writer寫入
    writer = csv.writer(f)
    #writerow方法
    writer.writerow(line)
    #writerows方法
    writer.writerows(line2)

with open(path) as f:
    #返回可迭代對象能夠讀取
    reader = csv.reader(f)
    #print(type(reader))
    for line in reader:
        if line:
            print(line)
###返回內容:
['1', 'xixi', '20']
['2', 'dongdong', '18']
['3', 'nannan', '23']
['4', 'beibei', '19']

csv文件內容:

argparse模塊(爲腳本傳遞命令參數功能)
1.argparse模塊初識:一個可執行文件或者腳本均可以接收參數。
舉例:ls -l /etc
/etc:是位置參數
-l:是短選項
如何把這些參數傳遞給程序呢?
從3.2開始python提供了參數分析的模塊argparse。
2.參數分類分爲:
位置參數,參數放在那裏,就要對應一個參數位置。例如/etc就是對應一個參數位置。
選項參數,必須經過前面是-的短選項或者-的長選項,而後後面的纔算它的參數,固然短選項後面也能夠沒有參數。
3.基本解析
(1)一個簡單解析器:

import argparse
parser = argparse.ArgumentParser()   #構造解析器
args = parser.parse_args()           #解析參數
parser.print_help()
運行:python3 xx.py -h
####打印結果:
usage: xx.py [-h]
optional arguments:
  -h, --help  show this help message and exit

(2)總結:
argparse不只僅作了參數的定義和解析,還自動幫助生成了幫助信息。尤爲是usage,能夠看到如今定義的參數是不是本身想要的
4.解析器的參數
(1)prog程序的名字,缺省使用sys.argv[0]
(2)add_help自動爲解析器增長-h和-help選項,默認爲True
(3)description爲程序功能添加描述
5.位置參數解析
ls基本功能應該解決目錄內容的打印
打印的時候應該指定目錄路徑,須要位置參數
程序定義爲:
ls [-h] path
-h爲幫助,無關緊要
path爲位置參數,必須提供
6.傳參
parse_args(args=None,namespace=None)
args參數列表,一個可迭代對象。內部會把可迭代對象轉換成list。若是爲None則使用命令行傳入參數,非 None則使用args參數的可迭代對象

from pathlib import Path
import argparse
#
def showdir(path:str='.'):      #接收目錄
    p = Path(path)
    for file in p.iterdir():    #返回迭代器對象
        print(file.name)

parser = argparse.ArgumentParser(prog='ls', add_help=True ,description='列出全部文件')  # 構造解析器
parser.add_argument('path')  # 位置參數跟傳參對應
parser.add_argument('-l')
parser.add_argument('-a','--all')

if __name__ == '__main__':
    #showdir('E:/wangshiyao/aaa')
    args = parser.parse_args("/etc".split())   #分析參數,同時傳入可迭代的參數
    parser.print_help()                        #打印幫助

    print('args=',args)                        #打印名次空間中收集的參數

####運行結果: usage: ls [-h] [-l L] [-a ALL] path 列出全部文件 positional arguments: #有一個位置參數定義的path path optional arguments: -h, --help show this help message and exit #自動化定義的幫助 -l L #有一個選項-l後面必須接參數 -a ALL, --all ALL #定義的-a和--all後面必須也接收參數 args= Namespace(all=None, l=None, path='/etc') #解析後會把args放到Namespace對象裏面

7.非必須位置參數
上面代碼必須輸入位置參數,不然會報錯。但有時候,ls命令不輸入任何路徑的話就表示列出當前目錄的文件列表

from pathlib import Path
import argparse
import datetime
import stat        #解決文件模式和文件類型

def listdir(path='.',all=False,detail=False,human=False):
    #實現-h文件大小
    def _get_human(size:int):
        units = ['','K','M','G','T','P']
        depth = 0

        while size >= 1000:
            size = size // 1000
            depth +=1

            print(size,units[depth])

        return "{}{}".format(size,units[depth])


    def _showdir(path='.',all=False,detail=False,human=False):      #接收目錄
        #l列出文件和目錄
        p = Path(path)
        for file in p.iterdir():                     #返回迭代器對象
            #解決all的問題
            if not all:                              #判斷是.開頭的不打印
                if str(file.name).startswith('.'):   #若是是點開頭的
                    continue                        #跳過
            #解決detail詳情打印(-l問題)
            if detail:                               #若是你是詳情打印
                #-rw-r--r--  1 root root    228911 Sep  5 09:47
                #處理-h大小
                st = file.stat()
                h =st.st_size
                if human:
                    h = _get_human(st.st_size)

                yield (stat.filemode(st.st_mode),st.st_nlink,st.st_uid,st.st_gid,h,datetime.datetime.fromtimestamp(st.st_atime).strftime('%Y-%m-%d %H:%M:%S'),file.name)
            else:                                    #若是不是詳情打印(沒有-l)
                yield (file.name,)                   #直接打印文件名

    #排序
    yield from sorted(_showdir(args.path, args.all, args.l, args.h), key=lambda x: x[-1])

parser = argparse.ArgumentParser(prog='ls', add_help=False ,description='列出全部文件')  # 構造解析器
parser.add_argument('path',nargs='?',default='.',help='paht help')  # 位置參數跟傳參對應
parser.add_argument('-l',action='store_true')
parser.add_argument('-h',action='store_true')
parser.add_argument('-a','--all',action='store_true')

if __name__ == '__main__':
    args = parser.parse_args(('E:/wangshiyao/aaa','-lh'))   #分析參數,同時傳入可迭代的參數
    parser.print_help()                        #打印幫助
    print('args=',args)                       #打印名次空間中收集的參數

    for st in listdir(args.path,args.all,args.l,args.h):
         print(st)

####打印結果:
usage: ls [-l] [-h] [-a] [path]

列出全部文件

positional arguments:
  path       paht help

optional arguments:
  -l
  -h
  -a, --all
args= Namespace(all=False, h=True, l=True, path='E:/wangshiyao/aaa')
2 K
9 K
5 K
('-rw-rw-rw-', 1, 0, 0, '2K', '2019-09-17 12:10:52', '1.py')
('-rw-rw-rw-', 1, 0, 0, '9K', '2019-09-17 11:14:21', '2.py')
('-rw-rw-rw-', 1, 0, 0, '269', '2019-09-06 14:12:34', 'a.json')
('-rw-rw-rw-', 1, 0, 0, '234', '2019-09-05 17:18:46', 'mysql.ini')
('-rw-rw-rw-', 1, 0, 0, '234', '2019-09-05 17:11:16', 'mysql_new.ini')
('drwxrwxrwx', 1, 0, 0, '0', '2019-09-09 12:13:05', 'xi')
('-rw-rw-rw-', 1, 0, 0, '15', '2019-09-06 16:00:59', 'xixi.txt')
('-rw-rw-rw-', 1, 0, 0, '5K', '2019-09-16 17:33:39', 'xx.log')

sys模塊(解釋器打交道)
1.sys.argv:命令行參數list,第一個元素是程序自己路徑
import sys
arg=sys.argv[1]
        if arg == "stop":  #啓動程序加stop
            stop()
        elif arg == "start":
            start()

2.sys.exit(n):退出程序,正常退出時exit(0)
3.sys.version:獲取python解釋程序的版本信息
4.sys.maxint:最大int值
5.sys.modules:解釋器初始化的時候,會初始化sys.modules字典(保存已加載的模塊)
6.sys.path:模塊搜索順序

import sys

for p in sys.path:
    print(p)
    
##返回搜索順序:
E:\shishi\aaa\xi                          #程序運行的主程序腳本所在的目錄
E:\shishi\aaa                             #python的path路徑
E:\python3\python35.zip
E:\python3\DLLs
E:\python3\lib
E:\python3
E:\python3\lib\site-packages              #第三方的包放在這下面
E:\python3\lib\site-packages\win32
E:\python3\lib\site-packages\win32\lib
E:\python3\lib\site-packages\Pythonwin

總結:
①顯示結果爲,python模塊的路徑搜索順序:
當加載一個模塊的時候,須要從這些搜索路徑中從前到後依次查找,不搜索這些目錄的子目錄,搜索到就加載,搜索不到就拋異常
②路徑能夠爲字典,zip文件,egg文件:
.egg文件,由setuptools庫建立的包,第三方庫經常使用的格式。添加了元數據(版本號,依賴項等)信息的zip文件
③路勁順序爲:
程序運行的主程序腳本所在的目錄
PYTHONPATH目錄,環境變量PYTHONPATH設置的目錄也是搜索模塊的路徑
標準庫目錄,Python自帶的庫模塊所在目錄
④sys.path能夠被修改,追加新的目錄
7.sys.platform:返回操做系統平臺名稱
8.sys.stdout.flush()刷新緩存:進度條

import sys
import time
for i in range(100):
    sys.stdout.write("#")
    time.sleep(0.1)
    sys.stdout.flush()

json&pickle&shelve&xml模塊(序列化與反序列化)
1.爲何要序列化
(1)內存中的字典,鏈表如何保存到一個文件中?
(2)若是是本身定義的類的實例,如何保存到一個文件中?
(3)如何從文件中讀取數據,並讓它們在內存中再次變成本身對應的類的實例?
2.什麼是序列化和反序列化:要設計一套協議,按照某種規則,把內存中數據保存到文件中。文件是一個字節序列,因此必須把數據轉換成字節序列,輸出到文件 這就是序列化,反之,從文件的字節序列恢復到內存,就是反序列化。
(1)序列化(serialization):把對象(變量)從內存中變成可存儲或傳輸的過程爲序列化,序列化以後,就能夠把序列化的內容寫入到磁盤,或者經過網絡傳輸到別的機器上。->二進制
(2)反序列化(deserialization):把變量內容從序列化的對象從新讀取到內存裏稱之爲反序列化。<-二進制
3.持久化:序列化保存到文件就是持久化
可將數據序列化後持久化,或者網絡傳輸;也能夠將從文件中或者網絡接收到字節序列反序列化
4.python程序之間能夠都是pickle解決序列化,反序列化,若是是跨平臺,跨語言,跨協議pickle就不適合了,就須要公共協議。如XML,Json,Protocol Buffer等
5.應用:本地序列化的清空,應用較少。通常來講,大多數場景都應用在網絡中。將數據序列化後經過網絡傳輸到遠程節點,遠程服務器上的服務將接收到的數據反序列化後,就可使用了。可是要注意一點,遠程接收端,反序列化時必須有對一個的數據類型,不然就會報錯,尤爲是自定義類,必須遠程的有
pickle模塊
(1)dumps對象序列化
(2)dump對象序列化到文件對象,就是存入文件
(3)loads對象反序列化
(4)load對象反序列化,從文件讀取數據
(5)序列化反序列舉例:

import pickle
###定義列表
lis = 'a b c'.split()
#print(lis)                             #返回的是列表:['a', 'b', 'c']

###定義字典
d = dict(zip('abc',range(3)))
#print(d)                              #返回的是字典{'b': 1, 'a': 0, 'c': 2}

###序列化
with open('xixi.txt','wb+') as f:   #注意是w是寫入str,wb是寫入bytes,lis和d是'bytes'
   #第一次序列化寫入列表
   pickle.dump(lis,f)                  #等價於pickle.dump(lis,f)--->傳到xixi.txt文檔中
   #第二次序列化寫入字典
   pickle.dump(d,f)                    #等價於pickle.dump(d,f)--->傳到xixi.txt文檔中

###反序列化
with open('xixi.txt','rb') as f:
   #第一次反序列化讀取列表數據
   tmp = pickle.load(f)              #經過pickle.loads()反序列化
   print(tmp)                        #['a', 'b', 'c']
   #第二次反序列化讀取字典數據
   tmp = pickle.load(f)              #經過pickle.loads()反序列化
   print(tmp)                        #{'c': 2, 'b': 1, 'a': 0}
#返回:
['a', 'b', 'c']
{'b': 1, 'a': 0, 'c': 2}

shelve模塊
shelve模塊比pickle模塊簡單,只有一個open函數,返回相似字典的對象,可讀可寫:key必須爲字符串,而只能夠是python所支持的數據類型
(1)傳進去:把一個字典放入文本 f={}

import shelve
f = shelve.open(r'xixi')                    #會生成三個文本xixi.bak和xixi,dat和xixi,dir              
f['stu1_info']={'name':'shishi','age':'18'}
f['stu2_info']={'name':'alyaoyao','age':'20'}
f['school_info']={'website':'oldboyedu.com','city':'beijing'}
f.close()                                   #關閉f.close把三個字典{'name':'shishi','age':'18'},{'name':'alyaoyao','age':'20'},{'website':'oldboyedu.com','city':'beijing'}放入文本xixi裏

(2)讀取出來:將一個字典放入文本 f={}

import shelve
f = shelve.open(r'xixi')          
print(f.get('stu1_info')['age'])   #讀取'age':'18'
#讀取結果:
18

json模塊
一.JSON
1.JSON(JavaScript Object Notation,JS對象標記)是一種輕量級的數據交換格式。它基於ECMAScript(w3c指定的JS規範)的一個子集,採用徹底獨立對於編程語言的文本格式來存儲和表示數據
2.JSON的數據類型
-值:雙引號引發來的字符串,數值,true和false,null,對象(object),數組(array),這些都是值。
(1)字符串:由雙引號包圍起來的任意字符的組合,能夠有轉義字符。
(2)數值:有正負,有整數,浮點數
(3)對象:無序的鍵值對的集合
格式:{key 1:value 1,...,keyn:valulen}
key必須是一個字符串,須要雙引號包圍這個字符串。value能夠是任意合法的值
(4)數組:有序的值的集合
格式:[val1,...,valn]
二.json模塊
1.python支持少了內建數據類型到Json類型的轉換。

2.經常使用方法
(1)dumps json編碼
(2)dump json編碼並存入文件
(3)loads json解碼
(4)load json解碼,從文件讀取數據
3.舉例:
(1)把字典類型裏的全部轉換成json類型

import json
d = {'a':123,'b':['abc',{'c':234}],'d':True,'e':False,'f':None}
print('打印字典類型:',d)
print('轉換json類型:',json.dumps(d))
#打印:
打印字典類型: {'e': False, 'd': True, 'a': 123, 'b': ['abc', {'c': 234}], 'f': None}
轉換json類型: {"e": false, "d": true, "a": 123, "b": ["abc", {"c": 234}], "f": null}

(2)經過json.dumps把字典轉換成json字符串寫到文本里

import json
a={'name':'xixi'}
f=open("new_hello","w")

a_str=json.dumps(a)   #把{'name':'xixi'}轉換成json字符串{"name": "xixi"}--->'{"name": "xixi"}'賦值給a_str
f.write(a_str)        #經過f.write把a_str寫到文件new_hello裏
#寫入結果:
{"name": "xixi"}

(3)經過json.loads()反序列化變換成原來的數據讀取出來

import json
f_read=open("new_hello","r")
data=json.loads(f_read.read())   #經過json.loads把{"name": "xixi"}變回成字典
print(data)                      
print(data["name"])print(type(data))
#輸出結果:
{'name': 'xixi'}
xixi
<class 'dict'>

通常json編碼的數據不多落地,數據都是經過網絡傳輸。傳輸的時候。要考慮壓縮它。本質上來講它就是個文本,就是個字符串。
json很簡單,幾乎語言變成都支持Json,全部應用十分普遍
xml模塊
xml是實現不一樣語言或程序程序之間進行數據交換的協議,跟json差很少,但json使用起來更簡單
xml的格式:就是經過<>節點來區別數據結構

#xml文檔(xml_lesson)
<
data> #date是一個根對象,下面三個country是節點對象 <country name="Liechtenstein"> <rank updated="yes">2</rank> <year updated="yes">2010</year> <gdppc>141100</gdppc> <neighbor direction="E" name="Austria" /> <neighbor direction="W" name="Switzerland" /> </country> <country name="Singapore"> <rank updated="yes">5</rank> <year updated="yes">2013</year> <gdppc>59900</gdppc> <neighbor direction="N" name="Malaysia" /> </country> <country name="Panama"> <rank updated="yes">69</rank> <year updated="yes">2013</year> <gdppc>13600</gdppc> <neighbor direction="W" name="Costa Rica" /> <neighbor direction="E" name="Colombia" /> </country> </data>

1.查詢:
(1)查詢跟根對象

import xml.etree.ElementTree as ET  #用ET這個名字代替xml.etree.ElementTree

tree = ET.parse("xml_lesson")       #經過這個模塊下的parse解析方法把xml_lesson數據解析開拿到對象tree
root = tree.getroot()               #拿到根節點就拿到根對象
print(root.tag)                     #經過tag打印根對象標籤名字

查詢結果:date
(2)查詢三個子對象標籤名字

for i in root:     #經過for循環根對象打印三個子對象標籤名字 print(i.tag)   

查詢結果:
country
country
country
(3)查詢三個子對象country裏面的全部標籤名字

for i in root:           #經過雙層for循環打印三個子對象country裏面的全部標籤名字 for j in i:
         print(j.tag)

查詢結果:
rank
year
gdppc
neighbor
neighbor
rank
year
gdppc
neighbor
rank
year
gdppc
neighbor
neighbor
(4)查詢三個子對象的標籤屬性

for i in root:   
     print(i.attrib)

查詢結果:
{'name': 'Liechtenstein'}
{'name': 'Singapore'}
{'name': 'Panama'}
(4)查詢三個子對象裏全部的標籤屬性是什麼

for i in root:
     print(i.attrib)
     for j in i:
         print(j.attrib)

查詢結果:
{'updated': 'yes'}
{'updated': 'yes'}
{}
{'direction': 'E', 'name': 'Austria'}
{'direction': 'W', 'name': 'Switzerland'}
{'updated': 'yes'}
{'updated': 'yes'}
{}
{'direction': 'N', 'name': 'Malaysia'}
{'updated': 'yes'}
{'updated': 'yes'}
{}
{'direction': 'W', 'name': 'Costa Rica'}
{'direction': 'E', 'name': 'Colombia'}
(5)查詢三個子對象裏全部實際內容

for i in root: 
     for j in i:
         print(j.text)

查詢結果:
2
2010
141100
None
None
5
2013
59900
None
69
2013
13600
None
None
(6)遍歷xml文檔查詢三個子對象裏全部實際標籤包括的內容

for child in root:
     for i in child:
         print(i.tag, i.text)

查詢結果:
rank 2
year 2010
gdppc 141100
neighbor None
neighbor None
rank 5
year 2013
gdppc 59900
neighbor None
rank 69
year 2013
gdppc 13600
neighbor None
neighbor None
(7)只遍歷year 節點

for node in root.iter('year'):
     print(node.tag, node.text)

查詢結果:
year 2010
year 2013
year 2013
2.刪除

for country in root.findall('country'):        #直接對country遍歷不用雙重遍歷
     rank = int(country.find('rank').text)     #找到排名的值
     if rank > 50:
         root.remove(country)                  #刪除country整個節點

tree.write('output.xml')

打印刪除後:
<data>
    <country name="Liechtenstein">
        <rank updated="yes">2</rank>
        <year updated="yes">2011</year>
        <gdppc>141100</gdppc>
        <neighbor direction="E" name="Austria" />
        <neighbor direction="W" name="Switzerland" />
    </country>
    <country name="Singapore">
        <rank updated="yes">5</rank>
        <year updated="yes">2014</year>
        <gdppc>59900</gdppc>
        <neighbor direction="N" name="Malaysia" />
    </country>
</data>
3.建立xml文檔:

import xml.etree.ElementTree as ET          #用ET這個名字代替xml.etree.ElementTree

new_xml = ET.Element("namelist")            #建立根節點標籤

name = ET.SubElement(new_xml, "name", attrib={"enrolled": "yes"})  #new_xml要處理的對象,"name"插入的內容標籤,"enrolled": "yes"標籤屬性
age = ET.SubElement(name, "age", attrib={"checked": "no"})
sex = ET.SubElement(name, "sex")
sex.text = '33'

et = ET.ElementTree(new_xml)     #生成文檔對象
et.write("test.xml", encoding="utf-8", xml_declaration=True)

ET.dump(new_xml)                 #打印生成的格式

建立結果:
<?xml version='1.0' encoding='utf-8'?>
<namelist>
    <name enrolled="yes">
          <age checked="no" />
          <sex>33</sex></name>
    <name enrolled="no">
          <age>19</age></name>
</namelist>
re模塊(正則表達式)
一.正則表達式概述
1.概述:正則表達式是文本處理極爲重要的技術,用它能夠對字符串按照某種規則進行檢索,替換。
2.分類:
(1)基本正則表達式(BRE):grep,sed,vi等軟件支持。vim有擴展
(2)擴展正則表達式(ERE):egrep(grep -E),sed -r等
(3)PCRE:幾乎全部高級語言都是PCRE的方言或者變種。python從1.6開始使用SRE正則表達式引擎,能夠認爲是PCRE的子集,見模塊re
二.re模塊概述
就本質而言,正則表達式(或RE)是一種小型的,高度專業化的編程語言,(在python中)它內嵌在python中,並經過re模塊實現。正則表達式模式被編譯成一系列的字節碼,而後由用C編寫的匹配引擎執行
三.re模塊下的字符:字符匹配包括普通字符和元字符
1.普通字符:大多數字符串和字母都會和自身匹配

>>> import re
>>> re.findall("xixi","xixishishixixiyaoyao")
###re.findall匹配:一個參數匹配規則,第二個參數要匹配的內容打印:
['xixi', 'xixi']

2.元字符
(1)通配符:.表明除換行符的任意符號,一個.表明一個符號

import re
>>> re.findall("w..g","thedwangddfegzfe")  #匹配w開頭中間任意倆個字符以g結尾的
####匹配結果:
['wang']

(2)以什麼開頭匹配:^

import re
>>> re.findall("^t..d","thedwangddfegzfe")  
####匹配結果:
['thed']

(3)以什麼結尾匹配:$

import re
>>> re.findall("g..e$","thedwangddfegzfe")  #匹配以e結尾g開頭中間任意倆個字符
####匹配結果:
['gzfe']

(4)或:|

import re
>>> re.findall("wa|ng","sdwagekngc")    #匹配wa或者ng
####匹配結果:
['wa', 'ng']

(5重複匹配:*匹配0到無窮次

import re
>>> re.findall("^d*","dddddddddddddddfdafadfaddddfcaddd") #匹配以d開頭的任意字符
####匹配結果:
['ddddddddddddddd']

(6)重複匹配:+匹配1到無窮次

import re
re.findall("d+","dddddddddddddddfdafadfaddddfcaddd")     #匹配以全部d
####匹配結果:
['ddddddddddddddd', 'd', 'd', 'dddd', 'ddd']

(7)匹配0和1的範圍:?

import re
>>> re.findall("wang?","asdhfawanggg")   #匹配wan後面1個g
####匹配結果:
['wang']

(8)把取的範圍放到大括號裏:{}

import re
>>> re.findall("wang{2}","asdhfawanggg")  #匹配wan後面2個g
####匹配結果:
['wangg']

四.字符之字符集:[ ]
1.第一個功能起到或的做用[ ]

import re
>>> re.findall("w[az]","fdasfafkjdkfwajldfjwz")  #匹配以w開頭,後面跟a或z
###匹配結果:
['wa', 'wz']

2.範圍一個到一個匹配:[-]

import re
>>> re.findall("w[a-z]","wdkedjtksfewz") #匹配第一位w第二位是a-z的任意一個字符
###匹配結果:
['wd', 'wz']

3.非匹配:[^]

import re
>>> re.findall("w[^a-z]","w123213wqdxz")  #匹配第一位w第二位不是a-z的任意字符的一個
###匹配結果:
['w1']

五.元字符之轉義符:\
斜槓後邊跟元字符去除特殊功能
斜槓後邊跟普通字符實現特殊功能
(1)\d匹配任何十進制數;至關於[0-9]
(2)\D匹配任何非數字字符:至關於[^[0-9]]
(3)\s匹配任空白字符:至關於[\t\n\r\f\v]
(4)\S匹配任何非空白字符:至關於[^\t\n\r\f\v]
(5)\w匹配任何字母數字字符:至關於[a-zA-Z0-9_]
(6)\W匹配任何非字母數字字符:至關於[^a-zA-Z0-9_]
(7)\b匹配一個特殊字符邊界,好比空格,&,#等
舉例:

import re
re.findall("I\\b","hello I am LIST")   #匹配單獨的大寫字母I
###匹配結果:詳解:\\b 在python解釋器裏解釋到\b的時候,他直接把\b翻譯成python解釋的轉義,因此前面在加上\把\b翻譯成對應的內容
['I']

六.re模塊下的修飾符
正則表達式能夠包含一些可選標誌修飾符來控制匹配的模式。修飾符被指定爲一個可選的標誌。
修飾符    描述
re.I     使匹配對大小寫不敏感
re.L     作本地化識別(locale-aware)匹配
re.M     多行匹配,影響 ^ 和 $
re.S     使 . 匹配包括換行在內的全部字符
re.U     根據Unicode字符集解析字符。這個標誌影響 \w, \W, \b, \B.
re.X     該標誌經過給予你更靈活的格式以便你將正則表達式寫得更易於理解。
七.re模塊下的經常使用方法
1.編譯
(1)re.compile(pattern,flags=0)
(2)設定flags,編譯模式,返回正則表達式對象regex
(3)pattern就是正則表達式字符串,flags是選項。正則表達式須要被編譯,爲了提升效率,這些編譯後的結果被保存,下次使用一樣的pattern的時候,就不須要再次編譯。
(4)re的其它方法爲了提升效率都調用了編譯方法,就是爲了提速
2.單次匹配(分三種)
第一種(match):從頭向後找到表達式第一次匹配子字符串,就當即返回,返回一個match對象,match裏面包含從哪裏開始到那裏結束
(1)re.match(pattern,string,flags=0)
舉例:沒編譯單行匹配

import re
s = '0123abc'

#沒編譯
matcher = re.match('\d',s)  #匹配0-9
print(type(matcher))        #匹配以後的類型:<class '_sre.SRE_Match'>
print(matcher)              #匹配的match對象:<_sre.SRE_Match object; span=(0, 1), match='0'>
print(matcher.group())      #匹配的內容:0

(2)regex.match(string[,pos[,endpos]]):match匹配從字符串的開頭匹配,regex對象match方法能夠重設定開始位置和結束位置。返回match對象
舉例:編譯單行匹配

import re
s = '0123abc'

#編譯:
regex = re.compile('[ab]')  #匹配從ab開始
#編譯過對象內部記錄編譯過的結果
matcher = regex.match(s,4)  #編譯後的match能夠設置位置,從第4個位置開始找
print(type(matcher))        #<class '_sre.SRE_Match'>
print(matcher)              #匹配的match對象:<_sre.SRE_Match object; span=(4, 5), match='a'>
print(matcher.group())      #匹配的內容:a

(3)編譯未編譯多行匹配舉例

import re
s = '''bottle\nbag\nbig\napple'''

for x in enumerate(s):
    if x[0] % 8 == 0:
        print()
    print(x, end=' ')
print('\n')

#match方法:
print('--match--')
print('未編譯:')
#找到一個就不找了
result = re.match('b',s)
print(1,result)

#沒找到,返回None
result = re.match('a',s)        #找不到,由於match只能從開頭找,離開開頭就找不到
print(2,result)

#沒找到,返回None
result = re.match('^a',s,re.M)  #找不到,依然從開頭找,多行模式沒用
print(3,result)

print('已編譯:')
#編譯:
regex = re.compile('a')
#沒找到,返回None
result = regex.match(s)          #依然從頭開始找
print(1,result)
#把索引15做爲開始找
result = regex.match(s,15)
print(2,result)
##############返回結果: (0, 'b') (1, 'o') (2, 't') (3, 't') (4, 'l') (5, 'e') (6, '\n') (7, 'b') (8, 'a') (9, 'g') (10, '\n') (11, 'b') (12, 'i') (13, 'g') (14, '\n') (15, 'a') (16, 'p') (17, 'p') (18, 'l') (19, 'e') --match-- 未編譯: 1 <_sre.SRE_Match object; span=(0, 1), match='b'> 2 None 3 None 已編譯: 1 None 2 <_sre.SRE_Match object; span=(15, 16), match='a'>

第二種(search):匹配字符串裏面的結果只要找到一個知足的就不在日後面找了
(1)re.search(pattern,string,flags=0)
舉例:沒編譯單行匹配

import re
s = '0123abc'

#沒編譯
matcher = re.search('[ab]',s)  #匹配[ab]
print(type(matcher))           #匹配以後的類型:<class '_sre.SRE_Match'>
print(matcher)                 #匹配的search對象:<_sre.SRE_Match object; span=(4, 5), match='a'>
print(matcher.group())         #匹配的內容:a

(2)regex.search(string[,pos[,endpos]]);從頭搜索直到第一個匹配,regex對象search方法能夠重設定開始位置和結束位置,返回match對象
舉例:編譯單行匹配

import re
s = '0123abc'

#編譯:
regex = re.compile('[ab]')  #匹配從ab開始
#編譯過對象內部記錄編譯過的結果
matcher = regex.search(s)
print(type(matcher))        #<class '_sre.SRE_Match'>
print(matcher)              #匹配的search對象:<_sre.SRE_Match object; span=(4, 5), match='a'>
print(matcher.group())      #匹配的內容:a

(3)編譯未編譯多行匹配舉例

import re
s = '''bottle\nbag\nbig\napple'''

for x in enumerate(s):
    if x[0] % 8 == 0:
        print()
    print(x, end=' ')
print('\n')

#search方法:
print('--search--')
print('未編譯:')
#掃描找到匹配的第一個位置
result = re.search('a',s)  #apple
print(1,result)

print('已編譯:')
#從b開始掃描,繞過第一b
regex = re.compile('b')
result = regex.search(s,1)  #bag
print(1,result)

#從b開頭開始掃描
regex = re.compile('^b',re.M)
result = regex.search(s)   #無論是否是多行,找到就返回
print(2,result)

#從第8位b開始找
regex = re.compile('b')
result = regex.search(s,8)
print(3,result)
########返回結果: (0, 'b') (1, 'o') (2, 't') (3, 't') (4, 'l') (5, 'e') (6, '\n') (7, 'b') (8, 'a') (9, 'g') (10, '\n') (11, 'b') (12, 'i') (13, 'g') (14, '\n') (15, 'a') (16, 'p') (17, 'p') (18, 'l') (19, 'e') --search-- 未編譯: 1 <_sre.SRE_Match object; span=(8, 9), match='a'> 已編譯: 1 <_sre.SRE_Match object; span=(7, 8), match='b'> 2 <_sre.SRE_Match object; span=(0, 1), match='b'> 3 <_sre.SRE_Match object; span=(11, 12), match='b'>

第三種(fullmatch):整個字符串和正則表達式匹配
(1)fe.fullmatch(pattern,string,flags=0)
舉例:沒編譯單行匹配

import re
s = '0123abc'

#沒編譯
matcher = re.fullmatch('\w+',s)    #匹配任何字母數字字符
print(type(matcher))               #匹配以後的類型:<class '_sre.SRE_Match'>
print(matcher)                     #匹配的search對象:<_sre.SRE_Match object; span=(0, 7), match='0123abc'>
print(matcher.group())             #匹配的內容:0123abc

(2)regex.fullmatch(string[,pos[,endpos]])
舉例:編譯單行匹配

import re
s = '0123abc'

#編譯:
regex = re.compile('[ab]')        #匹配從ab開始
#編譯過對象內部記錄編譯過的結果
matcher = regex.fullmatch(s,4,5)   #先作字符串切片,從第4個位置開始找
print(type(matcher))               #<class '_sre.SRE_Match'>
print(matcher)                     #匹配的search對象:<_sre.SRE_Match object; span=(4, 5), match='a'>
print(matcher.group())             #匹配的內容:a

(3)編譯未編譯多行匹配舉例

import re
s = '''bottle\nbag\nbig\napple'''

for x in enumerate(s):
    if x[0] % 8 == 0:
        print()
    print(x, end=' ')
print('\n')

#fullmatch方法:
print('--fullmatch--')
print('未編譯:')
#匹配bag
result = re.fullmatch('bag',s)
print(1,result)

print('已編譯:')
#編譯:
regex = re.compile('bag')
#沒匹配上
result = regex.fullmatch(s)      #匹配bag
print(1,result)

#沒匹配上
result = regex.fullmatch(s,7)    #匹配bag從第七位開始
print(2,result)

#要徹底匹配,多了少了都不行
result = regex.fullmatch(s,7,10)  #匹配bag從第七位開始到第十位
print(3,result)
########返回結果: (0, 'b') (1, 'o') (2, 't') (3, 't') (4, 'l') (5, 'e') (6, '\n') (7, 'b') (8, 'a') (9, 'g') (10, '\n') (11, 'b') (12, 'i') (13, 'g') (14, '\n') (15, 'a') (16, 'p') (17, 'p') (18, 'l') (19, 'e') --fullmatch-- 未編譯: 1 None 已編譯: 1 None 2 None 3 <_sre.SRE_Match object; span=(7, 10), match='bag'>

3.所有匹配(分兩種)
第一種findall:對整個字符串,從左至右匹配,返回全部的匹配項列表
(1)re.findall(pattern,string,flags=0)

import re
s = '0123abc'

#沒編譯
matcher = re.findall('[ab]',s)  #匹配[ab]
print(type(matcher))            #匹配以後的類型:<class 'list'>
print(matcher)                  #匹配的match結果:['a', 'b']

(2)regex.findall(string[,pos[,endpos]])

import re
s = '0123abc'

#編譯:
regex = re.compile('[ab]')
matcher = regex.findall(s)
print(type(matcher))        #匹配以後的類型:<class 'list'>
print(matcher)              #匹配的match結果:['a', 'b']

(3)編譯未編譯多行匹配舉例

import re
s = '''bottle\nbag\nbig\napple'''

for x in enumerate(s):
    if x[0] % 8 == 0:
        print()
    print(x, end=' ')
print('\n')

#findall方法:
print('--findall--')
print('未編譯:')
result = re.findall('b',s)      #匹配全部b
print(1,result)

print('已編譯:')
#編譯:
#只能找到一個bottle,默認狀況\n不會看成行首
regex = re.compile('^b')        #匹配b開頭的全部
result = regex.findall(s)
print(1,result)

#編譯:
regex = re.compile(r'^b\w+',re.M)   #匹配b開頭每一行的行首
result = regex.findall(s,7)
print(2,result)

#編譯:
regex = re.compile(r'^b\w+',re.S)
result = regex.findall(s)
print(3,result)

#編譯:
regex = re.compile(r'^b\w+',re.M)
result = regex.findall(s,7,10)
print(4,result)
########返回結果: (0, 'b') (1, 'o') (2, 't') (3, 't') (4, 'l') (5, 'e') (6, '\n') (7, 'b') (8, 'a') (9, 'g') (10, '\n') (11, 'b') (12, 'i') (13, 'g') (14, '\n') (15, 'a') (16, 'p') (17, 'p') (18, 'l') (19, 'e') --findall-- 未編譯: 1 ['b', 'b', 'b'] 已編譯: 1 ['b'] 2 ['bag', 'big'] 3 ['bottle'] 4 ['bag']

第二種finditer:對整個字符串,從左至右匹配,返回全部匹配項,返回迭代器。
注意:每次迭代返回的是match對象。
(1)re.finditer(pattern,string,flags=0)

import re
s = '0123abc'

#沒編譯
matcher = re.finditer('[ab]',s)  #匹配[ab]
print(type(matcher))             #匹配以後的類型:<class 'list'>
print(matcher)                   #匹配的match對象:<callable_iterator object at 0x00000000011C14A8>
print(next(matcher).group())     #返回結果:a
print(next(matcher).group())     #返回結果:b

(2)regex.finditer(string[,pos[,endpos]])

import re
s = '0123abc'

#編譯:
regex = re.compile('[ab]')
matcher = regex.finditer(s)
print(type(matcher))             #匹配以後的類型:<class 'list'>
print(matcher)                   #匹配的match對象:<callable_iterator object at 0x00000000011C14A8>
print(next(matcher).group())     #返回結果:a
print(next(matcher).group())     #返回結果:b

4.匹配替換
第一種sub:使用pattern對字符串string進行匹配,對匹配項使用repl替換replacement能夠是string,bytes,function
(1)re.sub(pattern,replacement,string,count=0,flags=0)
(2)regex.sub(replacement,string,count=0)
舉例:

import re
s = '''bottle\nbag\nbig\napple'''

for x in enumerate(s):
    if x[0] % 8 == 0:
        print()
    print(x, end=' ')
print('\n')

#編譯:
regex =re.compile('b\wg')       #匹配b中間加一個字符的
#
result = regex.sub('xixi',s)    #替換成xixi
print(1,result)                  #被替換後的字符串
#
result = regex.sub('xixi',s,1)  #替換成xixi只替換一次
print(2,result)
######打印結果 (0, 'b') (1, 'o') (2, 't') (3, 't') (4, 'l') (5, 'e') (6, '\n') (7, 'b') (8, 'a') (9, 'g') (10, '\n') (11, 'b') (12, 'i') (13, 'g') (14, '\n') (15, 'a') (16, 'p') (17, 'p') (18, 'l') (19, 'e') 1 bottle xixi xixi apple 2 bottle xixi big apple

第二種subn:同sub返回一個元祖(new_string[替換後的字符串],number_of_subs_made[替換的次數])
(1)re.subn(pattern,replacement,string,count=0,flags=0)
(2)regex.subn(replacement,string,count=0)
舉例:

import re
s = '''bottle\nbag\nbig\napple'''

for x in enumerate(s):
    if x[0] % 8 == 0:
        print()
    print(x, end=' ')
print('\n')

#編譯:
regex =re.compile('b\wg')       #匹配b中間加一個字符的
#
result = regex.subn('xixi',s)    #替換成xixi
print(1,result)                  #被替換後的字符串
#
result = regex.subn('xixi',s,1)  #替換成xixi只替換一次
print(2,result)

######打印結果
(0, 'b') (1, 'o') (2, 't') (3, 't') (4, 'l') (5, 'e') (6, '\n') (7, 'b')
(8, 'a') (9, 'g') (10, '\n') (11, 'b') (12, 'i') (13, 'g') (14, '\n') (15, 'a')
(16, 'p') (17, 'p') (18, 'l') (19, 'e')

1 ('bottle\nxixi\nxixi\napple', 2)
2 ('bottle\nxixi\nbig\napple', 1)

舉例2

import re
s = '''os.path([path])'''

##編譯:
regex =re.compile('[\.\(\)\[\]]')       #把.和小括號和中括號替換
#
result = regex.subn(' ',s)    #替換成空格
print(result)                 #被替換後的字符串

#######打印結果: ('os path path ', 5)

5.字符串分割
re.split(pattern,string,maxsplit=0,flags=0):
舉例:

import re
s = '''01 bottle
02 bag
03    big1
100     able'''

for x in enumerate(s):
    if x[0] % 8 == 0:
        print()
    print(x, end=' ')
print('\n')

#把每行單詞提取出來
#方式一:
regex = re.compile('^[\s\d]+',re.M)    #匹配任空白字符或0-9開頭
result = regex.split(s)                 #分割
print(result)
#方式二:
regex = re.compile('\s+\d+\s+')      #匹配任空左右兩邊是白字符中間是0-9開頭
result = regex.split(' '+s)           #分割切掉,把01前面加上空格
print(result)
#######打印結果: (0, '0') (1, '1') (2, ' ') (3, 'b') (4, 'o') (5, 't') (6, 't') (7, 'l') (8, 'e') (9, '\n') (10, '0') (11, '2') (12, ' ') (13, 'b') (14, 'a') (15, 'g') (16, '\n') (17, '0') (18, '3') (19, ' ') (20, ' ') (21, ' ') (22, ' ') (23, 'b') (24, 'i') (25, 'g') (26, '1') (27, '\n') (28, '1') (29, '0') (30, '0') (31, ' ') (32, ' ') (33, ' ') (34, ' ') (35, ' ') (36, 'a') (37, 'b') (38, 'l') (39, 'e') ['', 'bottle\n', 'bag\n', 'big1\n', 'able'] ['', 'bottle', 'bag', 'big1', 'able']

6.分組
使用小括號的pattern捕獲的數據被放到了組group中
match,search函數能夠返回match對象;findall返回字符串列表;finditer返回一個個match對象
若是pattern中使用了分組,若是有匹配的結果,會在match對象中
(1)使用group(N)方式返回對應分組,1-N是對應的分組,0返回整個匹配的字符串
(2)若是使用了命名分組,可使用group('name')的方式取分組
(3)也可使用groups()返回全部組
(4)使用groupdict()返回全部命名的分組
舉例:

import re
s = '''bottle\nbag\nbig\napple'''

#search方式分組
print('--search分組--')
regex = re.compile('b(\w+)(e)')  #匹配b開頭e結尾中間是字母
matcher = regex.search(s)         #把中間字母和結尾e分兩組
print(matcher.groups())           #返回全部分組元祖打印:('ottl', 'e')
print(matcher.group(0))           #全長匹配mtch對象打印:bottle
print(matcher.group(1))           #打印第一個分組:ottl
print(matcher.group(2))           #打印第二個分組:e

#finditer方式分組
print('--finditer分組--')
regex = re.compile('b(\w+)(e)')  #匹配b開頭e結尾中間是字母
matchers = regex.finditer(s)      #把中間字母和結尾e分兩組
for matcher in matchers:
    #分組元祖打印
    print(matcher.groups())       #返回全部分組元祖打印:('ottl', 'e')
    print(matcher.group(0))       #全長匹配mtch對象打印:bottle
    print(matcher.group(1))       #打印第一個分組:ottl
    print(matcher.group(2))       #打印第二個分組:e

#finditer方式命名分組
print('--finditer命名分組--')
regex = re.compile('b(?P<body>\w+)(?P<tail>e)')  #匹配b開頭e結尾中間是字母,把開頭b命名爲body,把結尾e命名爲tail
matchers = regex.finditer(s)                      #把中間字母和結尾e分兩組
for matcher in matchers:
    #分組名字字典方式打印
    print(matcher.groupdict())                    #打印分組名字:{'tail': 'e', 'body': 'ottl'}

logging模塊(日誌模塊)
1.日誌級別(CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET)

 日誌級別     數值
CRITICAL     50
ERROR        40
WARNING      30(默認級別)
INFO         20
DEBUG        10
NOTSET       0

日誌級別指的是生產日誌的事件的嚴重程度。設置一個級別後,嚴重程度低於設置值的日誌消息將被忽略
2.格式字符串:

      屬性名                    格式                                        描述
    日誌名字                %(name)s:            logger的名字
    日誌消息內容:           %(message)s           The logged message,computed as msg % args.當調用Formatter.format()時設置
    asctime                %(asctime)s          字符串形式的當前時間。默認格式是"2018-01-01 11:11:11,11"。逗號後面的是毫秒
    created                %(created)f          當前時間,用UNIX標準的表示時間的浮點數表示
    輸出日誌信息             %(relativeCreated)d  輸出日誌信息時的,自Logger建立以來的毫秒數
    函數名                  %(funcName)s         調用日誌輸出函數的函數名
    日誌級別名稱             %(levelname)s        文本形式的日誌級別
    日記級別數值             %(levelno)s          數字形式的日誌級別
    行號                   %(lineno)d            調用日誌輸出函數的語句所在的代碼行
    模塊                   %(module)s            調用日子輸出函數的模塊名
    模塊的完整路徑名         %(pathname)s          調用日誌輸出函數的模塊的完整路徑名
    模塊文件名              %(filename)s          調用日誌輸出函數的模塊文件名
    進程ID                 %(process)d           進程ID
    線程ID                 %(thread)d            線程ID
    進程名                 %(processName)s       進程名
    線程名                 %(threadName)s        線程名

3.可用參數:
(1)level設置rootlogger的日誌級別(默認大於等於warning級別)
(2)filename:用指定的文件名建立,這樣日誌會被存儲在指定的文件中
(3)filemode:文件打開方式,在指定文件時使用這個參數,默認值爲"a",還可指定爲"w"
(4)datefmt:指定日期時間格式
(5)stream:是指定的stream建立StreamHandler,若同時出現filename和stream倆個參數,stream則被忽略
(6)format:指定handler(處理的日誌)使用的日誌顯示格式   
<1>默認級別

import logging
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')

####打印結果:默認的級別是warning,只會把warning以上的都打印出來
WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message

<2>修改日期格式

import logging

#指定日誌打印的格式
FORMAT = "%(asctime)s %(thread)d %(message)s"
#datefmt="%Y-%m-%d-%H:%M:%S"修改日期格式
logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt="%Y-%m-%d-%H:%M:%S")
logging.info('info message')                          #打印結果:2019-10-24-17:08:28 77460 info message

<3>構建消息兩種風格(C語言風格和format函數風格)

import logging

#指定日誌打印的格式必須是C語言風格
FORMAT = "%(asctime)s %(thread)d %(message)s"

logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt="%Y-%m-%d-%H:%M:%S")

def add(x,y):
    #INFO
    #風格一:C語言風格把("%s %s",x,y)放到message裏
    logging.info("%s %s", x, y)

    #WARNING
    #風格二:format函數合成一個字符串放到message裏
    logging.warning("{} {}".format(threading.enumerate(),x+y))

add(4,5)
###返回結果:
2019-10-24-15:31:07 76444 4 5
2019-10-24-15:31:07 76444 [<_MainThread(MainThread, started 76444)>] 9

總結:上例是基本使用方法,大多數時候,使用的是info,正常運行信息的輸出
<4>自定義格式字符串擴展

import logging

#指定日誌打印的格式必須是C語言風格(%(age)s是額外本身定義的信息)
FORMAT = "%(asctime)s %(thread)d %(message)s %(age)s"
logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt="%Y-%m-%d-%H:%M:%S")

#必須把額外的信息放到字典裏
d = {'age' : '18'}

def add(x,y):
    #WARNING
    #經過extra把這個字典調出來
    logging.warning("{} {}".format(threading.enumerate(),x+y) , extra=d)

add(4,5)

##打印結果:
2019-10-24-15:47:13 67708 [<_MainThread(MainThread, started 67708)>] 9 18

<5>filename輸入到文件

import logging

#指定日誌打印的格式必須是C語言風格
FORMAT = "%(asctime)s %(thread)d %(message)s"
#(寫入文件filename=E:/aaa/logger.log)
logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt="%Y-%m-%d-%H:%M:%S",filename='E:/aaa/logger.log')

def add(x,y):
    #WARNING
    #經過extra把這個字典調出來
    logging.warning("{} {}".format(threading.enumerate(),x+y))

add(4,5)
##查看E:/aaa/logger.log文件內容
2019-10-24-15:52:29 71712 [<_MainThread(MainThread, started 71712)>] 9

4.Logger類
(1)構造:使用工廠方法返回一個Logger實例
語法:logging.getLogger([name=None])
①指定name,返回一個名稱爲name的Logger實例。若是再次使用相同的名字,是實例化一個對象。未指定name,返回Logger實例,名稱是root,即根Logger。
②Logger是層次結構的,使用.點號分割,如'a','a.b'或'a.b.c.d',a是a.b的父parent,a.b是a的子child。對於foo來講,名字爲foo.bar,foo.bar.baz,foo.bam都是foo的後代
層級關係:

import logging

#指定日誌打印的格式必須是C語言風格
FORMAT = "%(asctime)s %(thread)d %(message)s"
#WARNING
logging.basicConfig(level=logging.WARNING,format=FORMAT,datefmt="%Y-%m-%d-%H:%M:%S")

#父親(根logger)
root = logging.getLogger()
print(root.name,root, id(root))
root.warning('my root')

#root的子(__name__模塊級的)
loga = logging.getLogger('__name__')
print(loga.name,loga, id(loga),id(loga.parent))
loga.warning('my loga')

#loga的子(__name__,模塊下的某個函數'echo'。或某個類產生的日誌)
logab = logging.getLogger("{}.{}".format(__name__,'echo'))
print(logab.name,logab,id(logab),id(logab.parent))
logab.warning('my logab')
###打印結果:
2019-10-24-16:42:40 75980 my root
root <logging.RootLogger object at 0x0000000000E2C240> 14860864
2019-10-24-16:42:40 75980 my loga
__name__ <logging.Logger object at 0x0000000000E05550> 14701904 14860864
2019-10-24-16:42:40 75980 my logab
__main__.echo <logging.Logger object at 0x0000000000E2C400> 14861312 14860864

5.級別設置setLevel

import logging

FORMAT = "%(asctime)s %(thread)d %(message)s"
#INFO
logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt="%Y-%m-%d-%H:%M:%S")
#根的一個子logger
logger = logging.getLogger('__name__')
#日誌級別繼承根
print(logger.getEffectiveLevel())        #打印結果:20
#打印info級別的日誌
logger.info('hello1')                   #打印結果:2019-10-24-16:53:55 71648 hello1
#修改日誌級別
logger.setLevel(28)
#打印當前日誌級別
print(logger.getEffectiveLevel())        #打印結果:28
#修改後打印info級別的日誌就打印不出來了
logger.info('hello2')

6.Handler:控制日誌信息的輸出目的地,能夠是控制檯,文
①能夠單獨設置level
②能夠單獨設置格式
③能夠單獨設置過濾器

● Handler
    ○ StreamHandler        #不指定使用sys.stderr
        ■ FileHandler      #文件
        ■ _StderrHandler   #標準輸出
    ○ NullHandler          #什麼都不作

舉例:logger實例級別(level)繼承(沒有設置任何的handler,leverl)

import logging

FORMAT = "%(asctime)s %(thread)d %(message)s"
#基本設置INFO
logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt="%Y-%m-%d-%H:%M:%S")

#拿到一個root
root = logging.getLogger()

##子
#使用工廠方法返回一個Logger實例
log1 = logging.getLogger('s')
#繼承祖先info級別的日誌
log1.info('hello1')                   #打印結果:2019-10-24-17:42:01 73348 hello1
#修改日誌級別ERROR
log1.setLevel(logging.ERROR)
print(log1.getEffectiveLevel())        #打印結果:40

##孫(沒有設置任何的handler,leverl)
log2 = logging.getLogger('s.s1')
#log2繼承最進的祖先有效級別log1的ERROR打印
print(log2.getEffectiveLevel())        #打印結果:40
#因此warning打印不出來
log2.warning('log2 warning')

總結:logger實例,若是設置了level,就用它和信息的級別比較,不然,繼承最近的祖先level。
(1)能夠單獨設置level

import logging

#指定日誌打印的格式必須是C語言風格
FORMAT = "%(asctime)s %(thread)d %(message)s"
#INFO
logging.basicConfig(format=FORMAT,datefmt="%Y-%m-%d-%H:%M:%S",level=logging.INFO)

##############################################################
###子
#使用工廠方法返回一個Logger實例
log1 = logging.getLogger('s')
#修改日誌級別WARNING
log1.setLevel(logging.ERROR)

##給log1加一個Handler寫入文件
hdlr = logging.FileHandler('E:/wangshiyao/aaa/m/log1hdlr.log')
#Handler日誌級別WARNING
hdlr.setLevel(logging.WARNING)
#在log1裏填進去一個Handler,同時這個Handler的級別(WARNING)跟本身級別(ERROR)不同
log1.addHandler(hdlr)               #接收log3(孫子)的級別判斷是否大於等於log2(父)給Handler處理把log3寫入到文件裏
#打印log1的handlers
print('log1',log1.handlers)        #打印結果:
#################################################################
###孫(設置handler)
log2 = logging.getLogger('s.s1')
#修改日誌級別CRITICAL
log1.setLevel(logging.CRITICAL)

##給log2加一個Handler標準輸出
hdlr2 = logging.StreamHandler()
#Handler日誌級別WARNING
hdlr2.setLevel(logging.WARNING)
#在log2裏填進去一個Handler,同時這個Handler的級別(WARNING)跟本身級別(CRITICAL)不同
log2.addHandler(hdlr2)               #接收log3(子)的級別判斷是否大於等於log2(父)給Handler處理打印輸出:log3
#打印log2的handlers
print('log2',log2.handlers)         #打印結果:
#################################################################
###重孫
log3 = logging.getLogger('s.s1.s2')
#設置log3的有效級別爲INFO
log3.setLevel((logging.INFO))
#打印log3的有效級別
print(log3.getEffectiveLevel())      #打印結果:20
#log3定義的級別INFO低於warning
log3.warning('log3')                #返回結果:2019-10-28-17:26:23 10524 log3
#打印log3的handlers
print('log3',log3.handlers)         #打印結果:log3 []

總結:
①每個Logger實例的level如同入口,讓水溜進來,若是這個門檻過高,信息就進不來。例如log3.warning(log3),若是定義的級別(INFO)高於於warning,就不會有信息經過log3
②若是level沒有設置,就用父的logger的,若是父親logger的level沒有設置,繼續找父親的父親,最終能夠找到root上,若是root設置了就用它的,若是root沒有設置就用默認的WARNING
③在某個logger上產生某種級別的消息,首先和logger的level檢查,若是消息level低於logger的EffectiveLevel有效級別,消息丟棄。若是經過(大於等於)檢查後,消息交給logger全部的handler處理,每一個handler須要和本身level比較來決定是否處理。若是沒有一個handler,或者消息已經被handler處理過了,則須要經過本logger的propagate屬性是不是True,True則把這個消息會繼續發送給父logger的全部handler處理,若是propagate屬性是True,當前logger的父logger成爲當前logger,它的全部handler處理消息。
④logger實例初始的propagate屬性爲True,即容許向父logger傳遞消息
⑤logging.basicConfig若是root沒有handler,就默認建立一個StreamHandler,若是設置了filename,就建立一個FileHandler。若是設置了format參數,就會用它生成了一個formatter對象,並把這個formatter加入到剛纔建立的handler上,而後把這些handler加入到root.handlers列表上。level是設置給root logger的。若是root.handlers列表不爲空,logging.basicConfig的調用什麼都不作
(2)Formatter能夠單獨設置格式:loggingd的Formatter類,它容許指定某個格式的字符串。若是提供None,那麼'%(message)s'將會做爲默認值。

import logging

#指定日誌打印的格式必須是C語言風格
FORMAT = "%(asctime)s %(thread)d %(message)s"
#INFO
logging.basicConfig(level=logging.ERROR,format=FORMAT,datefmt="%Y-%m-%d-%H:%M:%S")

###子
#使用工廠方法返回一個Logger實例
log1 = logging.getLogger('s')
#修改日誌級別WARNING
log1.setLevel(logging.WARNING)
#打印log1的有效級別
print(log1.getEffectiveLevel())        #打印結果:30

#給log1加一個Handler寫入文件
hdlr = logging.FileHandler('E:/wangshiyao/aaa/m/log1hdlr.log')
#Handler日誌級別INFO
hdlr.setLevel(logging.INFO)
#定一個Formatter指定格式
fmt1 = logging.Formatter('log1-h %(asctime)s %(thread)d %(threadName)s %(message)s')
#給Handler加一個Formatter
hdlr.setFormatter(fmt1)
#在log1裏填進去一個Handler,同時這個Handler的級別(WARNING)跟本身級別(INFO)不同
log1.addHandler(hdlr)               #接收log2(子)的級別消息大於log1(父)給Handler處理把Formatter指定的格式信息log1-h 2019-10-28 14:31:37,300 10556 MainThread log2.error寫入到文件裏

###孫
log2 = logging.getLogger('s.s1')
#打印log2的有效級別繼承父(log1)的級別WARNING
print(log2.getEffectiveLevel())      #打印結果:30

#給log2加一個Handler標準輸出
hdlr2 = logging.StreamHandler()
#Handler日誌級別ERROR
hdlr2.setLevel(logging.ERROR)
#定一個Formatter指定格式
fmt2 = logging.Formatter('log2-h %(asctime)s %(thread)d %(threadName)s %(message)s')
#給Handler加一個Formatter
hdlr2.setFormatter(fmt2)
#在log2裏填進去一個Handler,同時這個Handler的級別(ERROR)跟本身級別(WARNING)不同
log2.addHandler(hdlr2)              #log2的log2.error級別消息大於等於本身的級別Formatter指定的格式信息標準輸出:log2-h 2019-10-28 14:32:54,945 11120 MainThread log2.error
#打印log2.warning不能夠打印出來
log2.info('log2 warning')         #打印結果:無
#打印log2.error能夠打印出來
log2.error('log2.error')          #打印結果:2019-10-28-12:18:44 11240 log2.error

(3)Filter能夠單獨設置過濾器:能夠爲handler增長過濾器,因此過濾器隻影響某一個handler,不會影響整個處理流程

import logging

#指定日誌打印的格式必須是C語言風格
FORMAT = "%(asctime)s %(thread)d %(message)s"
#INFO
logging.basicConfig(level=logging.ERROR,format=FORMAT,datefmt="%Y-%m-%d-%H:%M:%S")

###子
#使用工廠方法返回一個Logger實例
log1 = logging.getLogger('s')
#修改日誌級別WARNING
log1.setLevel(logging.WARNING)
#打印log1的有效級別
print(log1.getEffectiveLevel())        #打印結果:30

#給log1加一個Handler寫入文件
hdlr = logging.FileHandler('E:/wangshiyao/aaa/m/log1hdlr.log')
#Handler日誌級別INFO
hdlr.setLevel(logging.INFO)
#在log1裏填進去一個Handler,同時這個Handler的級別(WARNING)跟本身級別(INFO)不同
log1.addHandler(hdlr)               #接收log2(子)的級別消息大於log1(父)給Handler處理把Formatter指定的格式信息log1-h 2019-10-28 14:31:37,300 10556 MainThread log2.error寫入到文件裏
#設置Filter過濾s
f1 = logging.Filter('s')           #s或s.s1是能夠過濾的到的,因此正常寫入文件
#把Filter加到Handler
hdlr.addFilter(f1)

###孫
log2 = logging.getLogger('s.s1')
#打印log2的有效級別繼承父(log1)的級別WARNING
print(log2.getEffectiveLevel())      #打印結果:30

#給log2加一個Handler標準輸出
hdlr2 = logging.StreamHandler()
#Handler日誌級別ERROR
hdlr2.setLevel(logging.ERROR)
#過濾器s.s2不符合s和s.s1因此
f2 = logging.Filter('s.s2')
hdlr2.addFilter(f2)
#在log2裏填進去一個Handler,同時這個Handler的級別(ERROR)跟本身級別(WARNING)不同
log2.addHandler(hdlr2)              #過濾器s.s2不符合s.s1或s因此沒有標準顯示輸出
#打印log2.warning不能夠打印出來
log2.info('log2 warning')         #打印結果:無
#打印log2.error能夠打印出來
log2.error('log2.error')          #打印結果:2019-10-28-12:18:44 11240 log2.error

configparser模塊(配置文件操做)
一.讀方法:
1.read(filenames,encoding=None):讀取ini文件,能夠是單個文件,也能夠是文件列表。能夠指定文件編碼。
(1)sections()返回section列表。缺省section不包括在內。
(2)add_section(section_name)增長一個section。
(3)has_section(section_name)判斷section是否存在
(4)options(section)返回section的全部option
(5)has_option(section,option)判斷section是否存在這個option
2.get(section,option,*raw=False,vars=None[,fallback]):從指定的段的選項上取值,若是找到返回,若是沒有找到就去找 DEFAULT段有沒有
(1)getint(section,option,,raw=False,vars=None[,fallback])
(2)getfoat(section,option,raw=False,vars=None[,fallback])
(3)getboolean(section,option,*,raw=False,vars=None[,fallback])
上面3個方法和get同樣,返回指定類型數據
舉例:讀取配置文件,用get和getint方式分別讀取sections裏的值
<1>E:/wangshiyao/aaa/mysql.ini配置文件:

[DEFAULT]
a = test

[mysql]
default-character-set = utf8

[mysqld]
datadir = /dbserver/data
port = 3306
charcter-set-server = utf8
sql_mode = NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

[test]
test1 = 123
test2 = abc

<2>代碼:

from configparser import ConfigParser

#打開閱讀這個文件
cfg = ConfigParser()
cfg.read('E:/wangshiyao/aaa/mysql.ini')
print(cfg.sections())                         #看有哪些sections:['mysql', 'mysqld', 'test']

#讀取test名字的sections的其中一條test對應的值不作強制類型轉換
a = cfg.get('test','test1')
print(a,type(a))                              #123 <class 'str'>

#讀取test名字的sections的其中一條test對應的值作強制類型轉換成int能夠直接作運算
b = cfg.getint('test','test1')
print(b,type(b))                              #123 <class 'int'>

#讀取test名字的sections若是test沒有對應的a值,讀取[DEFAULT]裏a的值([DEFAULT]必須有a)
c = cfg.get('test','a')
print(c,type(c))                              #test <class 'str'>
#打印:
['mysql', 'mysqld', 'test']
123 <class 'str'>
123 <class 'int'>
test <class 'str'>

3.items(section,raw=False,vars=None):沒有section,則返回全部section名字及其對象;若是指定section,則返回這個section的鍵值對組成二元組
二.寫方法:
1.set(section,option,value):section存在的狀況下,寫入option=value,要求option,value必須是字符串
舉例:讀取配置文件,打印出全部的sections對應的option,增長一個sections爲test,並給test添加兩條數據
<1>E:/wangshiyao/aaa/mysql.ini配置文件:
[

DEFAULT]
a = test

[mysql]
default-character-set = utf8

[mysqld]
datadir = /dbserver/data
port = 3306
charcter-set-server = utf8
sql_mode = NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

<2>代碼:

from configparser import ConfigParser

#打開閱讀這個文件
cfg = ConfigParser()
cfg.read('E:/wangshiyao/aaa/mysql.ini')
print(cfg.sections())                         #看有哪些sections:['mysql', 'mysqld']

#迭代cfg.sections()拿到全部sections
for section in cfg.sections():
    #迭代全部sections獲取對應的option
    for k,v in cfg.items(section):
        print(k,v)

#建立一個sections
if not cfg.has_section('test'):        #判斷若是有沒有test名字的sections
    cfg.add_section('test')             #建立一個test名字的sections

#給test名字的sections增長兩條值
cfg.set('test','test1','123')
cfg.set('test','test2','abc')

#把值寫入到文件
with open('E:/wangshiyao/aaa/mysql.ini','w') as f:
    cfg.write(f)
###打印輸出: ['mysql', 'mysqld', 'test'] a test default-character-set utf8 a test datadir /dbserver/data port 3306 charcter-set-server utf8 sql_mode NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES a test

<3>E:/wangshiyao/aaa/mysql.ini最新配置文件:

[DEFAULT]
a = test

[mysql]
default-character-set = utf8

[mysqld]
datadir = /dbserver/data
port = 3306
charcter-set-server = utf8
sql_mode = NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

[test]
test1 = 123
test2 = abc

三.刪除方法:
1.remove_section(section):移除section及其全部option
2.remove_option(section,option):移除section下的option
舉例:
<1>E:/wangshiyao/aaa/mysql.ini最新配置文件:

[DEFAULT]
a = test

[mysql]
default-character-set = utf8

[mysqld]
datadir = /dbserver/data
port = 3306
charcter-set-server = utf8
sql_mode = NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

[test]
test1 = 123
test2 = abc

<2>代碼:

from configparser import ConfigParser

#打開閱讀這個文件
cfg = ConfigParser()
cfg.read('E:/wangshiyao/aaa/mysql.ini')
#print(cfg.sections())                         #看有哪些sections:['mysql', 'mysqld', 'test']

#打印test名字的sections的其中test1
print(cfg.getint('test','test1'))

#刪給test名字的sections的其中test1(若是沒有報錯)
cfg.remove_option('test','test1')

#把修改結果寫入到文件
with open('E:/wangshiyao/aaa/mysql.ini','w') as f:
   cfg.write(f)
#返回:
123

四.拷貝方法:
1.write(fileobject,space_around_delimiters=True):將當前config的全部內容寫入fileobject中,通常open函數使用w模式
舉例:將配置文件mysql.ini拷貝一份到mysql_new.ini

from configparser import ConfigParser

#打開閱讀這個文件
cfg = ConfigParser()
cfg.read('E:/wangshiyao/aaa/mysql.ini')

with open('E:/wangshiyao/aaa/mysql_new.ini','w') as f:
    cfg.write(f)

hashlib模塊(摘要算法)
把一個不定長的字符串轉成定長的密文的內容
用hashlib的md5算法加密數據
(1)普通加密:

import hashlib
obj=hashlib.md5()                     #
obj.update("hello".encode("utf8"))    
print(obj.hexdigest())                md5對象,md5不能反解,可是加密是固定的,就是關係是一一對應,因此有缺陷,能夠被對撞出來#要對哪一個字符串進行加密,就放這裏#拿到加密字符串

加密輸出:
5d41402abc4b2a76b9719d911017c592
(2)加密加鹽:

import hashlib
obj=hashlib.md5("xixi".encode('utf8'))  #在原先加密的基礎上再加密一層"xixi",這樣的話參數"xixi"只有本身知道,防止被撞庫,由於別人永遠拿不到這個參數
obj.update("hello".encode("utf8"))
print(obj.hexdigest())

加鹽加密輸出:7beec303f0442fd5cf2961a56c277d96

相關文章
相關標籤/搜索