python模塊
用一砣代碼實現了某個功能的代碼集合。 類似於函數式編程和面向過程編程,函數式編程則完成一個功能,其他代碼用來調用即可,提供了代碼的重用性和代碼間的耦合。而對於一個復雜的功能來,可能需要多個函數才能完成(函數又可以在不同的.py文件中),n個 .py 文件組成的代碼集合就稱為模塊。模塊分為內建模塊、自定義的模塊、安裝的第三方的模塊
導入模塊
Python之所以應用越來越廣泛,在一定程度上也依賴於其為程序員提供了大量的模塊以供使用,如果想要使用模塊,則需要導入。導入模塊有一下幾種方法:
import module from module.xx.xx import xx from module.xx.xx import xx as rename from module.xx.xx import *
導入模塊其實就是告訴Python解釋器去解釋那個py文件
- 導入一個py文件,解釋器解釋該py文件
- 導入一個包,解釋器解釋該包下的 __init__.py 文件
那么問題來了,導入模塊時是根據那個路徑作為基准來進行的呢?即:sys.path
>>> import sys >>> print(sys.path) ['', '/home/tomcat/.pyenv/versions/3.5.1/lib/python35.zip', '/home/tomcat/.pyenv/versions/3.5.1/lib/python3.5', '/home/tomcat/.pyenv/versions/3.5.1/lib/python3.5/plat-linux', '/home/tomcat/.pyenv/versions/3.5.1/lib/python3.5/lib-dynload', '/home/tomcat/.pyenv/versions/3.5.1/lib/python3.5/site-packages']
如果sys.path路徑列表沒有你想要的路徑,可以通過 sys.path.append('路徑') 添加。
import sys import os project_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(project_path)
常用內置模塊
內置模塊是Python自帶的功能,在使用內置模塊相應的功能時,需要【先導入】再【使用】
一、sys
用於提供對Python解釋器相關的操作:
sys.argv 命令行參數List,第一個元素是程序本身路徑 sys.exit(n) 退出程序,正常退出時exit(0) sys.version 獲取Python解釋程序的版本信息 sys.maxint 最大的Int值 sys.path 返回模塊的搜索路徑,初始化時使用PYTHONPATH環境變量的值 sys.platform 返回操作系統平台名稱 sys.stdin 輸入相關 sys.stdout 輸出相關 sys.stderror 錯誤相關
進度條示例:
import sys
import time def view_bar(num,total): rate = num / total rate_num = int(rate * 100) r = '\r%s%d%%' % (">"*num,rate_num) sys.stdout.write(r) sys.stdout.flush() if __name__ == '__main__': for i in range(0, 100): time.sleep(0.1) view_bar(i, 100)
二、os
用於提供系統級別的操作:
os.getcwd() 獲取當前工作目錄,即當前python腳本工作的目錄路徑
os.chdir("dirname") 改變當前腳本工作目錄;相當於shell下cd
os.curdir 返回當前目錄: ('.')
os.pardir 獲取當前目錄的父目錄字符串名:('..')
os.makedirs('dir1/dir2') 可生成多層遞歸目錄
os.removedirs('dirname1') 若目錄為空,則刪除,並遞歸到上一級目錄,如若也為空,則刪除,依此類推
os.mkdir('dirname') 生成單級目錄;相當於shell中mkdir dirname
os.rmdir('dirname') 刪除單級空目錄,若目錄不為空則無法刪除,報錯;相當於shell中rmdir dirname
os.listdir('dirname') 列出指定目錄下的所有文件和子目錄,包括隱藏文件,並以列表方式打印
os.remove() 刪除一個文件
os.rename("oldname","new") 重命名文件/目錄
os.stat('path/filename') 獲取文件/目錄信息
os.sep 操作系統特定的路徑分隔符,win下為"\\",Linux下為"/"
os.linesep 當前平台使用的行終止符,win下為"\t\n",Linux下為"\n"
os.pathsep 用於分割文件路徑的字符串
os.name 字符串指示當前使用平台。win->'nt'; Linux->'posix'
os.system("bash command") 運行shell命令,直接顯示,不能保存執行結果
os.popen("bash command").read() 運行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所指向的文件或者目錄的最后修改時間
三、hashlib
用於加密相關的操作,代替了md5模塊和sha模塊,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法
import hashlib
# ######## md5 ########
hash = hashlib.md5()
# help(hash.update)
hash.update(bytes('admin', encoding='utf-8'))
print(hash.hexdigest())
print(hash.digest())
######## sha1 ########
hash = hashlib.sha1()
hash.update(bytes('admin', encoding='utf-8'))
print(hash.hexdigest())
# ######## sha256 ########
hash = hashlib.sha256()
hash.update(bytes('admin', encoding='utf-8'))
print(hash.hexdigest())
# ######## sha384 ########
hash = hashlib.sha384()
hash.update(bytes('admin', encoding='utf-8'))
print(hash.hexdigest())
# ######## sha512 ########
hash = hashlib.sha512()
hash.update(bytes('admin', encoding='utf-8'))
print(hash.hexdigest())
以上加密算法雖然依然非常厲害,但時候存在缺陷,即:通過撞庫可以反解。所以,有必要對加密算法中添加自定義key再來做加密。
import hashlib
# ######## md5 ########
hash = hashlib.md5(bytes('898oaFs09f',encoding="utf-8"))
hash.update(bytes('admin',encoding="utf-8"))
print(hash.hexdigest())
四、random
import random print(random.random()) # 生成0-1之間的隨機小數 print(random.randint(1, 20)) #生成1到20的整數包括20 print random.uniform(10, 20) #生成10到20之間的浮點數 print(random.randrange(1, 10)) #生成1到10的證書不包括10,第3個參數可以指定步長 print(random.choice(["JGood", "is", "a", "handsome", "boy"])) # 從序列中隨機選一個數 # 每次對序列隨機排序 p = ["Python", "is", "powerful", "simple"] random.shuffle(p) print(p)
隨機驗證碼
import random
li = [] for i in range(6): r = random.randint(0, 4) if r == 2 or r == 4: num = random.randrange(0, 10) li.append(str(num)) else: temp = random.randrange(65,91) c = chr(temp) li.append(c) result = "".join(li) print(result)
一些例子
五、time&datetime
時間相關的操作,時間有三種表示方式:
- 時間戳 1970年1月1日之后的秒,即:time.time()
- 格式化的字符串 2014-11-11 11:11, 即:time.strftime('%Y-%m-%d')
- 結構化時間 元組包含了:年、日、星期等... time.struct_time 即:time.localtime()
time
import time print(time.clock()) #返回處理器時間,3.3開始已廢棄 print(time.process_time()) #返回處理器時間,3.3開始已廢棄
print(time.time()) #返回當前系統時間戳輸出:1471161757.5214906 print(time.ctime()) #輸出字符串格式時間:Sun Aug 14 16:04:02 2016 ,當前系統時間 print(time.ctime(time.time()-86640)) #將時間戳轉為字符串格式
print(time.gmtime()) #獲取結構化時間 print(time.gmtime(time.time()-86640)) #將時間戳轉換成struct_time格式 print(time.localtime(time.time()-86640)) #將時間戳轉換成struct_time格式,但返回的本地時間 print(time.mktime(time.localtime())) #與time.localtime()功能相反,將struct_time格式轉回成時間戳格式 time.sleep(4) #睡上4秒 print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()) ) #將struct_time格式轉成指定的字符串格式 print(time.strptime("2016-01-28","%Y-%m-%d") ) #將字符串格式轉換成struct_time格式
datetime
import datetime
print(datetime.date.today()) #輸出格式 2016-01-26
print(datetime.date.fromtimestamp(time.time()-864400) ) #2016-01-16 將時間戳轉成日期格式
current_time = datetime.datetime.now() #
print(current_time) #輸出2016-01-26 19:04:30.335935
print(current_time.timetuple()) #返回struct_time格式
#datetime.replace([year[, month[, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]]]])
print(current_time.replace(2014,9,12)) #輸出2014-09-12 19:06:24.074900,返回當前時間,但指定的值將被替換
str_to_date = datetime.datetime.strptime("21/11/06 16:30", "%d/%m/%y %H:%M") #將字符串轉換成日期格式
new_date = datetime.datetime.now() + datetime.timedelta(days=10) #比現在加10天
new_date = datetime.datetime.now() + datetime.timedelta(days=-10) #比現在減10天
new_date = datetime.datetime.now() + datetime.timedelta(hours=-10) #比現在減10小時
new_date = datetime.datetime.now() + datetime.timedelta(seconds=120) #比現在+120s
print(new_date)
View Code
六、logging模塊
很多程序都有記錄日志的需求,並且日志中包含的信息即有正常的程序訪問日志,還可能有錯誤、警告等信息輸出,python的logging模塊提供了標准的日志接口,你可以通過它存儲各種格式的日志,logging的日志可以分為 debug(), info(), warning(), error() and critical() 5個級別,下面我們看一下怎么用。
日志級別對應的數字:
CRITICAL = 50 ERROR = 40 WARNING = 30 INFO = 20 DEBUG = 10 NOTSET = 0
日志記錄格式:
%(name)s Logger的名字
%(levelno)s 數字形式的日志級別
%(levelname)s 文本形式的日志級別
%(pathname)s 調用日志輸出函數的模塊的完整路徑名,可能沒有
%(filename)s 調用日志輸出函數的模塊的文件名
%(module)s 調用日志輸出函數的模塊名
%(funcName)s 調用日志輸出函數的函數名
%(lineno)d 調用日志輸出函數的語句所在的代碼行
%(created)f 當前時間,用UNIX標准的表示時間的浮 點數表示
%(relativeCreated)d 輸出日志信息時的,自Logger創建以 來的毫秒數
%(asctime)s 字符串形式的當前時間。默認格式是 “2003-07-08 16:49:45,896”。逗號后面的是毫秒
%(thread)d 線程ID。可能沒有
%(threadName)s 線程名。可能沒有
%(process)d 進程ID。可能沒有
%(message)s用戶輸出的消息
1、單文件日志
import logging
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
filename='test.log',
filemode='w')
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
2、多文件日志
對於上述記錄日志的功能,只能將日志記錄在單文件中,如果想要設置多個日志文件,logging.basicConfig將無法完成,需要自定義文件和日志操作對象。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import logging
#獲取日志器對象
logger = logging.getLogger('TEST-LOG') # 返回一個logger對象,沒有指定的話默認是root logger
logger.setLevel(logging.DEBUG) #設置全局日志級別
#定義屏幕控制器把日志輸出屏幕
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG) # 輸出屏幕的日志級別
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter) # 給輸出屏幕的日志設置日志格式
logger.addHandler(ch) # 將設定好的控制器添加到日志器中
#定義文件控制器把日志輸出文件
fh = logging.FileHandler("access.log")
fh.setLevel(logging.WARNING) #設置輸出文件的日志級別
formatter1 = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter1) # 給輸出文件的日志設置日志格式
logger.addHandler(fh) # 將設定好的控制器添加到日志器中
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')
注意:局部日志級別只有大於全局日志級別才會記錄
七、subprocess模塊
可以執行shell命令的相關模塊和函數有:
- os.system() 直接使用shell命令,不能保存運行的結果
- os.spawn*
- os.popen().read() 直接使用shell命令,可以保存運行的結果
- commands.* python3.x已經廢除
- subprocess
1、os.system()
>>> import os
>>> os.system('ls')
a.py b.py Desktop myenv35 PycharmProjects workplace
a.txt b.txt myenv27 pass.py scripts
0
2、os.popen().read()
>>> import os
>>> fi = os.popen('ls').read()
>>> print(fi)
a.py
a.txt
b.py
b.txt
3、commands(在python2.x中執行)
>>> import commands
>>> result = commands.getoutput('ls')
>>> print(result)
a.py
a.txt
b.py
b.txt
>>> result1 = commands.getstatusoutput('ls')
>>> print(result1)
(0, 'a.py\na.txt\nb.py\nb.txt\nDesktop\nmyenv27\nmyenv35\npass.py\nPycharmProjects\nscripts\nworkplace')
4、subprocess
subprocess.call() 執行命令,返回狀態碼,shell=False,第一個參數必須是列表,shell=True,第一個參數就直接輸入命令即可
>>> ret = subprocess.call(["ls", "-l"], shell=False)
或: >>> ret = subprocess.call("ls -l", shell=True)
subprocess.check_call() 執行命令,如果執行狀態碼是 0 ,則返回0,否則拋異常
>>> ret = subprocess.check_call(["ls", "-l"],shell=False)
>>> print(ret) >>> ret = subprocess.check_call("exit 1", shell=True)
>>> print(ret)
subprocess.check_output() 執行命令,如果狀態碼是 0 ,則返回執行結果,否則拋異常,注意這里返回的是字節類型,需要轉換
>>> ret = subprocess.check_output(["echo", "Hello World!"],shell=False)
>>> print(str(ret,encoding='utf-8'))
或 >>> ret = subprocess.check_output("exit 1", shell=True)
>>> print(str(ret,encoding='utf-8'))
subprocess.run() python3.5新加的功能,代替os.system,os.spawn
>>> import subprocess >>> subprocess.run(["ls", "-l"]) total 56 -rw-rw-r-- 1 tomcat tomcat 61 8月 11 23:27 a.py -rw-rw-r-- 1 tomcat tomcat 12929 8月 8 18:03 a.txt CompletedProcess(args=['ls', '-l'], returncode=0) >>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE) CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0, stdout=b'crw-rw-rw- 1 root root 1, 3 8\xe6\x9c\x88 11 09:27 /dev/null\n')
subprocess.Popen() 用於執行復雜的系統命令,是上面方法的底層實現
調用subprocess.run(...)是推薦的常用方法,在大多數情況下能滿足需求,但如果你可能需要進行一些復雜的與系統的交互的話,你還可以用subprocess.Popen(),語法如下:
p = subprocess.Popen("find ~/ -size +1000 -exec ls -shl {} \;",shell=True,stdout=subprocess.PIPE)
print(p.stdout.read())
參數:
- args:shell命令,可以是字符串或者序列類型(如:list,元組)
- bufsize:指定緩沖。0 無緩沖,1 行緩沖,其他 緩沖區大小,負值 系統緩沖
- stdin, stdout, stderr:分別表示程序的標准輸入、輸出、錯誤句柄
- preexec_fn:只在Unix平台下有效,用於指定一個可執行對象(callable object),它將在子進程運行之前被調用
- close_sfs:在windows平台下,如果close_fds被設置為True,則新創建的子進程將不會繼承父進程的輸入、輸出、錯誤管道。
- 所以不能將close_fds設置為True同時重定向子進程的標准輸入、輸出與錯誤(stdin, stdout, stderr)。
- shell:同上
- cwd:用於設置子進程的當前目錄,相當於shell中cd進入當前目錄
- env:用於指定子進程的環境變量。如果env = None,子進程的環境變量將從父進程中繼承。
- universal_newlines:不同系統的換行符不同,True -> 同意使用 \n
- startupinfo與createionflags只在windows下有效
- 將被傳遞給底層的CreateProcess()函數,用於設置子進程的一些屬性,如:主窗口的外觀,進程的優先級等等
終端輸入的命令分為兩種:
- 輸入即可得到輸出,如:ifconfig
- 輸入進行某環境,依賴再輸入,如:python
(1)輸入即可得到輸出
import subprocess
obj = subprocess.Popen(["mkdir","test"],cwd='/tmp/',)
或者
obj1 = subprocess.Popen("mkdir test1", shell=True, cwd='/tmp/',)
(2)輸入進行某環境,依賴再輸入,通過輸入,輸出,錯誤管道,輸入數據,獲取數據
import subprocess
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)")
obj.stdin.close()
cmd_out = obj.stdout.read()
obj.stdout.close()
cmd_error = obj.stderr.read()
obj.stderr.close()
print(cmd_out)
print(cmd_error)
或者
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)")
out_error_list = obj.communicate()
print(out_error_list)
或者
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
out_error_list = obj.communicate('print("hello")')
print(out_error_list)
