模塊:
一個模塊就是一個包含了python定義和聲明的文件,文件名就是模塊名字加上.py的后綴(模塊名不能定義成中文)
為何要使用模塊:
因為退出python解釋器然后在進入python解釋器,那么你之前定義的函數或者變量都將丟失,因此我們通常都將程序寫到文件中便永久保存下來,需要時就通過python *.py方式去運行,此時的*.py被稱為腳本script。
站在開發效率來講,隨着程序的發展,功能越來越多,為了方便管理,我們通常將程序分成一個個的文件,這樣做程序的結構更清晰,方便管理。這是我們不僅僅可以把這些文件當做腳本去執行,還可以把他們當做模塊來導入到其他模塊中,實現了功能的重復利用
那么如何使用模塊呢?
import
#test.py print('from the test.py') money=1000 def read1(): print('spam->read1->money',1000) def read2(): print('spam->read2 calling read') read1() def change(): global money money=0
import test #導入模塊,導入就是在執行導入的文件 #導入模塊后,就是通過import定義一個模塊名,並且這個模塊下的所以名字都因此在test名字的后面 print(test.money) #這樣才能取到test模塊下面的各種變量
請看下圖

要想取出test下的money變量的值,需要通過test這個'門牌號'來取 就是print(test.money)
如果在當前文件中又定義了一個新的money變量。再次執行print(test.money)的結果還是原來的值。因為即使當前目錄下定義了相同的變量,但是它們的內存地址並不一樣。不管怎么寫,只要是通過模塊名去調用模塊下面的代碼,那么執行的結果一定是原來的東西
導入模塊最倡導的方式就是'模塊名.調用名'
import test #import只會在第一次導入時才會執行,后面的導入都是在引用之前創建好的名字。不會再把文件內容執行 import test import test import test #即使導入多次也是執行一次效果 #import過程就是要執行文件里面的代碼,是文件就要有路徑,所以import是一個找文件的過程。為什么能在當前目錄下導入直接導入模塊,因為調用與被調用模塊都在同一個目錄下,所以直接就能找到,調用。並且impor導入多次t不能每次都找,那樣速度會慢。
我們可以使用sys.module找到當前已經加載的模塊,sys.module是一個字典,內部包含模塊名與模塊對象的映射,該字典決定了導入模塊時是否需要重新導入
import test as te print(te.money) #為模塊起別名 ,適用於那種模塊名很長,或者以沖突的模塊名 #起別名還有一個好處就是擴展性強 #比如說兩個模塊都可以處理相同的問題 那么可以把這兩個定義成一個別名,在調用的時候會很方便 if file_format == 'xml': import xmlreader as reader elif file_format == 'csv': import csvreader as reader data=reader.read_date('filename')
import os,sys,time,test #一行導入多個模塊
from ... import ...
相對於import test來說,它會將源文件的名稱空間'test'帶入到當前名稱空間中,使用時必須是test.名字的方式,而from語句相當於import,也會創建新的名稱空間,但是將test中的名字直接導入到當前名稱空間中,在當前名稱空間中,使用名字可以直接調用
from test import read1,read2 #注意 調用名字標紅並不是報錯,只是系統不識別自己定義的模塊 read1() read2()
PS:但是如果當前導入的模塊里有跟當前名稱空間相沖突的名字,那么下面的名字就會覆蓋上面
這種方法就是不需要進行test.最為前綴去調用,但是它的執行仍然跟test.執行一樣,仍然要回到之前的名稱空間中去運行
強烈不建議用from ... import 方法
也可以支持起別名
也支持多行導入
from test import * #導入所有,不推薦 #但是在某些情況下還得使用,各自體會吧
如果我在模塊中,將一個名字以下划線(_)開頭,那么import將無法導入
#但是可以通過用下面方法還是可以執行的 from test import _money
__all__
__all__=['money','read1'] #如果使用了__all__參數那么后面要跟一個列表,然后里面以字符串的方式寫入,代表着如果里面寫入了一些名字,那么誰在通過import test from *調用,只會調用__all__里面的名字,read2將不會調用
將模塊當做腳運行
在模塊中,最下方輸入print(__name__),然后倒入模塊后,會執行模塊的內容,並且輸入模塊名,這個模塊名就是print(__name__)執行的
但是模塊只能被導入么?答案是否定的,模塊也能單獨當一個腳本執行。如果單獨執行那么print(__name__)的輸出就是__main__

所以通過__name__可以標識一種狀態,文件此刻被已一種什么樣的方式去使用。如果是__main__那么就當做腳本去執行,如果是文件名本身那么就是被調用。
通過 if __name__ =='__main__' 來控制文件在不同的場景下有不同執行效果。
模塊搜索路徑
導入模塊:首先會從內存中找內建模塊;如果不存在,然后會去系統的環境變量里找;如果不在當前目錄,那么需要將要導入模塊的路徑添加到sys.path中,使用sys.path.append('路徑');
在Python中導入代碼會在Python中__pycache__目錄下產生一個文件如(test.cpython-33.pyc)這個里面的test就是被導入的模塊,而這個文件就是為了提高模塊的導入速度。
導入包
包:就是一個目錄,在Python中,一個文件夾中有__init__.py的文件
無論是import形式還是from...import形式,凡是在導入語句中(而不是在使用時)遇到帶點的,都要第一時間提高警覺:這是關於包才有的導入語法
包A與包B下有相同的模塊也不會沖突,如A.a與B.a這是來自兩個命名空間
包結構
glance/ #Top-level package ├── __init__.py #Initialize the glance package ├── api #Subpackage for api │ ├── __init__.py │ ├── policy.py │ └── versions.py ├── cmd #Subpackage for cmd │ ├── __init__.py │ └── manage.py └── db #Subpackage for db ├── __init__.py └── models.py
文件中代碼
#文件內容 #policy.py def get(): print('from policy.py') #versions.py def create_resource(conf): print('from version.py: ',conf) #manage.py def main(): print('from manage.py') #models.py def register_models(engine): print('from models.py: ',engine)
注意事項
1.關於包相關的導入語句也分為import和from...import...兩種,但是無論哪種,無論什么位置,在導入時都必須遵循一個原則:凡事在導入時帶點的,點的左邊必須是一個包,否則非法。可以帶有一連串的點,如item.subitem,subsubitem.但是都必須遵循這個原則
2.對於導入后,在使用時就沒有這種限制了,點的左邊可以是包,模塊,函數類(他們都可以用點的方式調用自己的屬性)
3.對比import item 和from item import name的應用場景:
如果我們想直接使用name,那么必須使用后者
import sys
import glance.api.policy as g1 print(sys.path) g1.get()
from...import...
需要注意的是from...import導入的模塊,import后面必須是導一個具體的目標,錯誤語法(from a import b.c)正確語法(from a.b.c import d)
import后面不需要寫點,后面不需要再進行找包的過程,找包的過程都是在from a.b.c 來完成的
from glance.api.policy import get get()
#或者
from glance.api import policy
policy.get()
導入包時做了什么事?
導入文件的時候,會執行文件,那么導入包呢? 在每個包中都會有一個__init__文件,那么在導入的時候會首先執行init文件,然后會在當前位置產生一個名字,這個名字來引用一個名稱空間。
#如果直接導入glance包並且調用glance.api.policy下面的get方法需要怎么做? import glance glance.get()
如果如上述方法肯定會報錯。因為你已經知道導入包就是執行包下面的__init__文件,那么可以用glacne下__init__文件來導入glance下的包,在通過其他文件來導入glance這個大包。
#在__init__中導入這個policy包, from glance.api.policy import get #然后再導入文件中導入glance包。 import glance glance.get() #那么只要一調用glance包就會執行__init__,而__init__就會執行from glance.api.policy import get 得到get功能。那么就可以直接用glance.get調用了
注意,在__init__中導入的包不是隨便寫的,導包就是一個找包的過程,還記得之前說的找包首先按照內存找,然后在sys.path中找,最后如果找不到需要將路徑添加到sys.path中,所有在__init__中導入包要有一個參照物,那么這個參照物就sys.path中的路徑。
因為上面的glance包與導入包文件都是在同級目錄,如果在不同級目錄的話,比如(a/glance)那么在導入就會報錯,因為在內存中和sys.path中並沒有這個路徑,所以需要將a這個路徑添加到sys.path中
import sys sys.path.append(r'C:\Users\Administrator\PycharmProjects\untitled\模塊\a') import glance
這樣在導入就可以了
絕對導入與相對導入
在開發一個包的時候不需要考慮別人如何調用
絕對導入:
特別需要注意的是:可以用import導入內置或者第三方模塊,但是要絕對避免使用import來導入自定義包的子模塊,應該使用from... import ...的絕對或者相對導入,且包的相對導入只能用from的形式。
導入系統模塊
hashlib模塊
hashlib提供了常見的摘要算法如,MD5,SHA1等
這里先闡述一個加密與摘要的區別:
首先MD5並不是一個加密算法,而是一個摘要算法。加密算法是雙向的,能加密,必然能通過加密后的值進行逆推。而摘要算法屬於單向的,通過算法得出的值無法進行逆推。摘要算法又稱為哈希算法,散列算法。它通過一個函數,把任意長度的數據轉換成定長的數據串
摘要算法的作用在於防篡改。
例如,網上有一篇博客,內如是(hello world,jack),並且它的摘要算法值是"291250459873666ed73be15305ac5c17" 如果在下載的時候有人將博客的內容篡改了,那么再次校驗的值是與之前的值是不同的
hashlib提供的函數還是比較簡單的
導入hashlib模塊
import hashlib obj=hashlib.md5() #創建一個對象
#對字符進行加密操作
obj.update('hello'.encode('utf-8')) #執行后沒有任何輸出
#查看摘要值,這個結果是一個32位的二進制值
print(obj.hexdigest()) #16進制值
print(obj.digest())
如果一個字符串很長的話 可以進行拆分加密 加密后的結果與之前是一樣的
import hashlib obj=hashlib.md5() # obj.update("hello".encode("utf-8")) # obj.update("world".encode("utf-8")) # fc5e038d38a57032085441e7fe7010b0 # b'\xfc^\x03\x8d8\xa5p2\x08TA\xe7\xfep\x10\xb0'
obj.update("helloworld".encode("utf-8")) print(obj.hexdigest()) print(obj.digest())
除了md5還有其他的算法如,SHA算法
SHA算法里面包含了很多算法,常見的如SHA1,SHA256,SHA512
像md5,SHA1,SHA256,SHA512它們之間算法的加密等級是不一樣的,越復雜的算法效率等級越慢。這個主要還是看需求來定。目前用的比較多的是SHA256
注意用法與md5一樣
import hashlib sha1= hashlib.sha1() #hashlib.sha256() hashlib.sha512()
sha1.update('hello'.encode('utf-8')) print(sha1.hexdigest())
摘要算法的應用:
主要用於登錄注冊是進行加密。數據庫中像這樣的表,肯定是不可能明文進行存儲。都是進行加密后的。
比如這樣的 username | password ---------+--------------------------------- jack | e10adc3949ba59abbe56e057f20f883e lily | 878ef96e86145580c38c87f0410ad153 tom | 99b1c2188db85afee403b1536010c2c9
但是會有這么一種人,他在注冊的時候設置的密碼過於簡單比如’123456‘,’admin‘等等。這樣就容易讓他人撞庫。那么如何預防這種事情發生呢?
我們可以在服務器端進行'加鹽'操作
import hashlib obj=hashlib.md5("salt".encode('utf-8')) obj.update("hello".encode("utf-8")) obj.update("world".encode("utf-8")) # fc5e038d38a57032085441e7fe7010b0 # b'\xfc^\x03\x8d8\xa5p2\x08TA\xe7\xfep\x10\xb0'
print(obj.hexdigest()) print(obj.digest()) #這樣在輸出的結果就與之前的結果不同了
logging模塊
在沒有使用這個模塊之前,我們想要將日志按照不同等級輸入到文件中,通過文件操作with open 也可以,但是這樣一來會很麻煩。來回的打開關閉文件。接下來學的這個模塊就會大大的方便我們對日志的操作
首先導入這個名叫logging的模塊 import logging 大家都知道日志中有不同的等級,比如debug info error等。所以在這個模塊中也有不同的6種等級 logging.debug("debug") logging.info("debug") logging.warning("debug") logging.error("debug") logging.caitical("debug") #執行,查看結果
ERROR:root:debug CRITICAL:root:debug WARNING:root:debug
只輸出了三行,在logging模塊中,默認的輸出等級是warning,只有等於或高於warning才會輸出。他們之間的等級關系是CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET
有的人可能會說,這樣的輸出格式看着不太習慣或者明顯,可否自己定義格式。沒問題,可以通過一個函數來設定,"basicConfig"
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s %(lineno)d %(message)s", datefmt='%a, %d %b %Y %H:%M:%S', filename='test.log', filemode='w') logging.debug("debug") logging.info("debug") logging.error("debug") logging.critical("debug") logging.warning("debug")
首先咱們來看,level是設定輸出等級,默認是warning,我們修改為debug。
format參數就是修改打印樣式,后面的格式都是固定的,通過的是%()s或者%()d來設定。
format參數中可能用到的格式化串: %(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用戶輸出的消息
前面的asctime輸出的時間精確到毫秒,看着很麻煩,所以我們可以通過datefmt關鍵字來進行時間格式化操作
filename是文件存放路徑。
filemode對文件的操作。默認是是追加的形式,因為日志么,都是通過append的格式寫入進文件,如果不想寫入也可以通過filemode=w 關鍵字進行覆蓋更改
上面的輸出可以滿足了我們一般的需求了,但是我要想一邊在屏幕輸出,一邊保存到文件中,怎么做呢。基於上面的basicConfig只能二選一。所以出現了下面這個函數
logger對象
import logging 首先定義一個logger對象 logger = logging.getLogger() 定義兩個輸出終端 fh = logging.FileHandler('test.log') # 創建一個handler,用於寫入日志文件,給一個路徑
ch = logging.StreamHandler() # 再創建一個handler,用於輸出到控制台,不需要路徑 #叫什么都無所謂
#流文件,是要輸出到終端,還是要輸出到文件中,只要將上面的ch或者fh添加到括號里就可以
logger.addHandler(ch) logger.addHandler(fh) 兩種模式全部輸出。這樣就可以輸出,但是並沒有樣式。 logger.debug("debug") logger.warning("debug") logger.info("debug") logger.error("debug") logger.critical("debug")
格式化輸出,設定日志等級
import logging logger = logging.getLogger() fh = logging.FileHandler('test.log') ch = logging.StreamHandler() 設置formatter對象 formatter=logging.Formatter("%(asctiem)s---%(lineno)d---%(message)s") formatter2=logging.Formatter("%(asctiem)s---%(message)s") 將設置后的樣式添加進去 fh.setFormatter(formtter) ch.setFormatter(formtter2) logger.addHandler(ch) logger.addHandler(fh) 現在的輸出就是具有格式的輸出。 最后設定輸出等級 調整logger logger.setLevel('DEBUG') logger.debug("debug") logger.warning("debug") logger.info("debug") logger.error("debug") logger.critical("debug")
上面的過程用一個圖來表示就是這樣
re模塊
re或正則表達式是一種小型的,高度專業化的編程語言
相對於正則來說,它實現的功能非常明確,就是對於在字符串的模糊匹配。首先它操作的對象一定是字符串
例: "hello world" 如何將hello world字符串中的world字符替換成jack。通過我們之前學過的字符串操作可以用replace "hello world".replace("world","jack")
但是可以發現我們替換的都是已知的字符串。如果我想替換以w開頭以d結尾的字符呢?這種模糊替換怎么辦。就需要用到我們的re模塊了
re模塊里面的方法不是特別多,非常簡單
re.findall("","") #第一個引號里面寫規則(匹配規則),第二個引號里面寫要匹配的內容
#模糊匹配 >>> import re >>> re.findall("world","hello world") ['world'] >>> re.findall("w.*d","hello world") ['world'] >>>
元字符:. ^ $ * + ? { } [ ] | ( ) \
'.':匹配任意一個值(換行符無法匹配\n) '^':匹配以什么開頭 '$':匹配以什么結尾 '*':匹配任意多個字符(0到無窮) >>> re.findall("a\d*b","hello ab") ['ab'] >>> re.findall("a\d*b","hello a123456b") ['a123456b'] '+':匹配任意多個字符(1到無窮) >>> re.findall("a\d+b","hello ab") [] >>> re.findall("a\d+b","hello a123456b") ['a123456b'] '?':匹配0到1個字符 >>> re.findall("a\d?b","hello a1b") ['a1b'] >>> re.findall("a\d?b","hello ab") ['ab'] '{}': >>> re.findall("\d{4}","hello ab1234") ['1234'] >>> re.findall("\d{4,}","hello ab1234") ['1234'] >>> re.findall("\d{4,}","hello ab1231231232313") ['1231231232313'] >>> re.findall("\d{1,4}","hel3lo a12.5b1231231232313") ['3', '12', '5', '1231', '2312', '3231', '3'] >>> re.findall("\d{1,}","hel3lo a12.5b1231231232313") ['3', '12', '5', '1231231232313'] '[]':字符集,在中括號中的任何元字符都失去其意義(^,\,-除外) >>> re.findall("a[bc]d","abdsdjfjacd") ['abd', 'acd'] >>> re.findall("a[b*]","abba*") ['ab', 'a*'] >>> re.findall("[0-9]","abba1234567") ['1', '2', '3', '4', '5', '6', '7'] >>> re.findall("[0-9]*","abba1234567") ['', '', '', '', '1234567', ''] >>> re.findall("[0-9]+","abba1234567") ['1234567'] >>> re.findall("[^0-9]+","abba1234567") ['abba'] >>> re.findall("[\d]+","ab123ba1234567") ['123', '1234567'] '|': 或者意思 >>> re.findall("www.(?:baidu|google).com","www.baidu.com") ['www.baidu.com'] '()':分組 >>> re.findall(r"(?:a\d)+","fsda1a2a3a6") ['a1a2a3a6'] #這個分組的包含了一個優先級的問題。findall會先找分組里面的字符串然后進行匹配。匹配成功了。則返回分組里面的匹配值。所以要想輸出匹配的字符串要加上'?:'來取消優先級
轉移反斜杠
'\':將有意義的特殊字符轉義成無意義。將無意義字符轉換成有意義
>>> re.findall("[\w]+","ab123ba1234567") ['ab123ba1234567'] >>> re.findall("[\d]+","ab123ba1234567") ['123', '1234567'] >>> re.findall(".","ab123ba1234567") ['a', 'b', '1', '2', '3', 'b', 'a', '1', '2', '3', '4', '5', '6', '7'] >>> re.findall("I\b","I am FINE") [] >>> re.findall(r"I\b","I am FINE") ['I'] 為什么加上r就可以了呢?請看下面的例子 >>> re.findall("c\d","abc\d") [] >>> re.findall("c\\d","abc\d") [] >>> re.findall("c\\\\d","abc\d") ['c\\d'] >>> re.findall(r"c\\d","abc\d") ['c\\d'] #從上面的例子中也可看出如果要匹配帶有\的字符,如果只輸入一個\\轉義符那么輸出並沒有結果。只有輸出4個轉義符或者在前面加一個r。
#因為加兩個\\是只滿足了re模塊的需求。但是我們是在python解釋器中執行,所以如果要在python解釋器中執行,那么就要在加兩個。但是為什么要再加兩個轉義符?因為在python中'\'也是有特殊意義的。所以也要將它進行轉義。
#加r后為什么兩個\\反斜杠就可以呢?因為這個r稱為原生字符串。目的告訴python解釋器,這兩個字符串是原生的。沒有任何意義

search方法
#這個方法只會匹配第一個值。而且得到的結果不會直接輸入到列表中。而是得到一個對象通過group()來讀出結果
>>> re.search("\d+","he123llo a123456b") <_sre.SRE_Match object; span=(2, 5), match='123'>
>>> re.search("\d+","he123llo a123456b").group() '123'
match方法
#跟search方法一樣,都是拿到一個結果。與search不一樣的是必須在字符串開頭位置進行匹配
>>> re.match(r"\d","fsdf123ab456") >>> re.match(r"\d","34fsdf123ab456") <_sre.SRE_Match object; span=(0, 1), match='3'>
>>> re.match(r"\d+","34fsdf123ab456") <_sre.SRE_Match object; span=(0, 2), match='34'>
#match只找第一個。找不到就返回空
常見轉義符
\d 匹配任何十進制數;它相當於類 [0-9]。 \D 匹配任何非數字字符;它相當於類 [^0-9]。 \s 匹配任何空白字符;它相當於類 [ \t\n\r\f\v]。 \S 匹配任何非空白字符;它相當於類 [^ \t\n\r\f\v]。 \w 匹配任何字母數字字符;它相當於類 [a-zA-Z0-9_]。 \W 匹配任何非字母數字字符;它相當於類 [^a-zA-Z0-9_] \b 匹配一個特殊字符邊界,比如空格 ,&,#等
其他方法:
#re.split()分割
>>> re.split("\d+","asdahd1231sdad123a") ['asdahd', 'sdad', 'a'] >>> re.split("[ab]","abcd") ['', '', 'cd'] #re.sub()替換
>>> re.sub("\d","*","l1h2c3") 'l*h*c*'
>>> re.sub("\d","*","l1h2c3",1) 'l*h2c3'
#后面的1代表替換幾個。
>>> re.subn("\d","*","l1h2c3",2) ('l*h*c3', 2) >>> re.subn("\d","*","l1h2c3") ('l*h*c*', 3) #同理re.subn就是代表將替換的后的結果和要替換的個數組成一個元組的形式
#re.compile()編譯
>>> obj=re.compile("\d+") >>> obj.findall("asdasd1231") ['1231'] >>> obj.findall("asd234asdasd1231") ['234', '1231'] #就是將規則先定義好然后在進行調用。將一步分成兩步來執行 #減少代碼重復性。如果就調用一次的話,不推薦用
time模塊
在python中,常用通用有這幾種方式來表示時間:
時間戳(timestamp):通常來說,時間戳表示從1970年1月1日00:00:00開始按秒計算的偏移量。我們運行“type(time.time())”,返回類型是float類型
格式化的時間字符串(Format String)
結構化的時間(struct_time):struct_time元組共有九個元素(年,月,日,時,分,秒,一年中第幾周,一年中第幾天,夏令時)
import time print (time.time()) #時間戳
print(time.strftime("%Y-%m-%d %X")) #格式化時間
print(time.localtime()) #本地時間
print(time.gmtime()) #國際時間
x=(time.localtime())#將本地時間賦予變量x
print(x.tm_year) #通過x.的方式取出年月日
print(x.tm_mon) print(x.tm_mday) print(time.gmtime())#跟上面的用法一樣。不一樣的是小時。我們中國屬於東八區
其中計算機認識的時間只能是時間戳的格式,而程序員可以處理為人類可以看懂的時間。格式化的時間字符串。結構化的時間,於是就有了下圖的轉換關系

圖片來源:點擊這里
import time print(time.localtime(123456)) #使用time.localtime可以將時間戳轉換為結構化時間
print(time.localtime(time.time()))#同上,獲取當前時間戳,轉換成本地結構化時間
print(time.gmtime(time.time()))#同上,轉換成國際結構化時間
print(time.mktime(time.localtime()))#將本地結構化時間轉換成時間戳
print(time.mktime(time.gmtime()))#將國際結構化時間轉換成時間戳
print(time.strftime("%Y-%m-%d %X",time.localtime()))#將本地結構化時間轉換成格式化時間
print(time.strftime("%Y-%m-%d %X",time.gmtime()))#將國際結構化時間轉換成格式化時間
print(time.strptime('2017-04-11 00:00:00',"%Y-%m-%d %X"))#將格式化時間轉換成結構化時間
還有另外一種格式化時間請看圖二

圖片來源:點擊這里
import time print(time.asctime())#默認不加參數輸出結果像linux系統上輸出的結果,添加的參數為結構化時間time.localtime
print(time.ctime()) #同上,將時間戳的轉換結果輸出,添加參數必須為時間戳
time.sleep(10) print('--->') #sleep睡幾秒
random模塊
隨機模塊
import random print(random.random())#大於0且小於1之間的小數,每次都是小數,不能指定范圍
print(random.uniform(1, 3))#同上,可以指定范圍
print(random.randint(1, 3))#[1,3] 大於等於1且小於等於3之間的整數
print(random.randrange(1, 3))#[1,3)大於等於1且小於3之間的整數
print(random.choice([1, '23', [4, 5]]))#自己定義一個列表,隨機取出列表里的元素1或者23或者[4,5]
print(random.sample([1, '23',3,4,5,6,[4, 5]], 3))#自定義列表,隨機出去列表元素任意2個組合,逗號后面跟幾就是每次隨機取幾個
item = [1, 3, 5, 7, 9] random.shuffle(item) # 打亂item的順序,相當於"洗牌"
print(item)
import random def get_code(): res=''
for i in range(6): num=random.randint(0,9) num=str(num) zimu=chr(random.randint(97,122)) #數字對應字母
res +=random.choice([num,zimu]) return res X=get_code() print(X)
OS模塊
os模塊是與操作系統交互的一個接口
os.getcwd() 獲取當前工作目錄,即當前python腳本工作的目錄路徑 os.chdir("dirname") 改變當前腳本工作目錄;相當於shell下cd os.curdir 返回當前目錄: ('.') os.pardir 獲取當前目錄的父目錄字符串名:('..') os.makedirs('dirname1/dirname2') 可生成多層遞歸目錄 os.removedirs('dirname1') 若目錄為空,則刪除,並遞歸到上一級目錄,如若也為空,則刪除,依此類推 os.mkdir('dirname') 生成單級目錄;相當於shell中mkdir dirname os.rmdir('dirname') 刪除單級空目錄,若目錄不為空則無法刪除,報錯;相當於shell中rmdir dirname os.listdir('dirname') 列出指定目錄下的所有文件和子目錄,包括隱藏文件,並以列表方式打印 os.remove() 刪除一個文件 os.rename("oldname","newname") 重命名文件/目錄 os.stat('path/filename') 獲取文件/目錄信息 os.sep 輸出操作系統特定的路徑分隔符,win下為"\\",Linux下為"/" os.linesep 輸出當前平台使用的行終止符,win下為"\t\n",Linux下為"\n" os.pathsep 輸出用於分割文件路徑的字符串 win下為;,Linux下為: os.name 輸出字符串指示當前使用平台。win->'nt'; Linux->'posix' os.system("bash command") 運行shell命令,直接顯示 os.environ 獲取系統環境變量 os.path.abspath(path) 返回path規范化的絕對路徑 os.path.split(path) 將path分割成目錄和文件名二元組返回 os.path.dirname(path) 返回path的目錄。其實就是os.path.split(path)的第一個元素 os.path.basename(path) 返回path最后的文件名。如何path以/或\結尾,那么就會返回空值。即os.path.split(path)的第二個元素 os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False os.path.isabs(path) 如果path是絕對路徑,返回True os.path.isfile(path) 如果path是一個存在的文件,返回True。否則返回False os.path.isdir(path) 如果path是一個存在的目錄,則返回True。否則返回False os.path.join(path1[, path2[, ...]]) 將多個路徑組合后返回,第一個絕對路徑之前的參數將被忽略 os.path.getatime(path) 返回path所指向的文件或者目錄的最后存取時間 os.path.getmtime(path) 返回path所指向的文件或者目錄的最后修改時間 os.path.getsize(path) 返回path的大小
print(os.path.split('/a/b/c/d.txt'))#將路徑一分為二
print(os.path.dirname(os.path.abspath(__file__)))#取出當前絕對路徑
print(os.path.basename(os.path.abspath(__file__)))#取出當前文件名
dir1=(os.path.split(os.path.abspath(__file__))) #通過切割來取出路徑或者文件
print(dir1[1])
import os #在Linux和Mac平台上,該函數會原樣返回path,在windows平台上會將路徑中所有字符轉換為小寫,並將所有斜杠轉換為飯斜杠。
print(os.path.normcase('C:/windows\\system32\\'))#在linux上沒有任何效果
print(os.path.normpath('c://windows\\System32\\../Temp/'))#同上,'..'返回上一級,
路徑處理 import os,sys #方法一
BASE_DIR=(os.path.dirname(os.path.dirname((os.path.abspath(__file__))))) 方法二 BASE_DIR2= os.path.normpath(os.path.join( os.path.abspath(__file__), os.pardir, os.pardir, ))
sys模塊
sys.argv 命令行參數List,第一個元素是程序本身路徑
sys.exit(n) 退出程序,正常退出時exit(0)
sys.version 獲取Python解釋程序的版本信息
sys.maxint 最大的Int值
sys.path 返回模塊的搜索路徑,初始化時使用PYTHONPATH環境變量的值
sys.platform 返回操作系統平台名稱
import sys,time for i in range(50): sys.stdout.write('%s\r ' %('#'*i)) sys.stdout.flush() time.sleep(0.1)
shutil模塊
高級的文件,文件夾,壓縮包處理模塊
import shutil # shutil.copyfileobj(open('old','r'),open('new','w')) ##將文件內容拷貝到另一個文件中
# shutil.copyfile('old','old2') ##拷貝文件
# shutil.copymode('old','new') # #拷貝權限,內容,組,用戶均不變
# shutil.copystat('old','new') ## 拷貝狀態信息,包括:mode bits,atime,mtime,flags
# shutil.copy('new','old2') ##拷貝文件和權限
# shutil.copy2('new','old1') #拷貝文件和狀態信息
# shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) #目標目錄不能存在,注意對folder2目錄父級目錄要有可寫權限,ignore的意思是排除,硬鏈接 # shutil.copytree('f1', 'f2', symlinks=True, ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) ##同上,軟連接
# shutil.rmtree('/a/b/c') # #遞歸刪除目錄或文件
# shutil.move('/a/b/c','/d/c/b') #遞歸去移動文件,類似於mv
import shutil # ret=shutil.make_archive('old','gztar',root_dir='/data') #壓縮並指定目錄,默認為當前目錄 import zipfile # z = zipfile.ZipFile('test.zip', 'w') # z.write('old') # z.write('new') # z.close() # 壓縮 # z = zipfile.ZipFile('test.zip','r') # z.extractall(path='.') # z.close() #解壓
import tarfile # t=tarfile.open('test.tar','w') # t.add('new',arcname='new.bak') # t.add('old',arcname='old.bak') # t.close() # # 壓縮 # t=tarfile.open('test.tar','r') # t.extractall('.') # t.close() # #解壓
json與pickle模塊
之前我們學習過用eval內置方法可以將一個字符串轉成python對象,不過,eval方法是有局限性的,對於普通的數據類型,json.loads和eval都能用,但遇到特殊類型的時候,eval就不管用了,所以eval的重點還是通常用來執行一個字符串表達式,並返回表達式的值。
import json x="[null,true,false,1]"
print(eval(x)) #報錯,無法解析null類型,而json就可以
print(json.loads(x))
什么是序列化?
我們把對象(變量)從內存中變成可存儲或傳輸的過程稱之為序列化,在Python中叫pickling,在其他語言中也被稱之為serialization,marshalling,flattening等等,都是一個意思。
為什么要有序列化
1:持久保存狀態
要知道一個程序或者軟件的執行,就是在處理一系列狀態的變化,在編程語言中,‘狀態’會以各種各樣有結構的的數據類型的形式被保存在內存中
內存是無法永久保存數據的,當程序運行了一段時間,我們斷電或者重啟程序,內存中關於這個程序的之前一段時間的數據(有結構)都被清空了。
在斷電或重啟程序之前將程序當前內存中所有的數據都保存下來(保存到文件中),以便於下次程序執行能夠從文件中載入之前的數據,然后繼續執行,這就是序列化。
具體的來說,你玩使命召喚闖到了第13關,你保存游戲狀態,關機走人,下次再玩,還能從上次的位置開始繼續闖關。或如,虛擬機狀態的掛起等。
2:跨平台數據交互
序列化之后,不僅可以把序列化后的內容寫入磁盤,還可以通過網絡傳輸到其他機器上,如果收發的雙方約定好使用一種序列化的格式,那么便打破了平台/語言差異帶來的限制,實現了跨平台數據交互
反過來,把變量內容從序列化的對象重新讀到內存里稱之為反序列化,即unpickling。
如何使用json和pickle:


圖片來源:點擊這里
import json dic={'name':'jack','age':'18','sex':'man'} # print(type(dic)) #沒序列化之前是字典格式 # # j=json.dumps(dic) # print(type(j)) #序列化后就是字符串格式
# f=open('dict.txt','w') # f.write(j) # f.close() #將序列化文件存放到文件中
# f=open('dict.txt','r') # date=json.loads(f.read()) # print(type(date)) #反序列化
json.dump(dic,open('db.json','w')) #第二種方法
date=json.load(open('db.json','r')) print(date['hoppy'][0])
pickle方法

圖片來源:點擊這里
import pickle dic={'name':'jack','age':'18','sex':'man','hoppy':['eat','drink','play']} j=pickle.dumps(dic) print(type(j)) #序列化后為bytes類型
with open('db.pickle','wb') as f: f.write(j) #寫入文件的時候也要用wb方式。
with open('db.pickle','rb') as F: date_pk=F.read() date=pickle.loads(date_pk) print(date) #pickle反序列化
#第二種方法
import pickle dic={'name':'jack','age':'18','sex':'man','hoppy':['eat','drink','play']} pickle.dump(dic,open('db.pk','wb')) #序列化
date=pickle.load(open('db.pk','rb')) print(date) #反序列化
Pickle的問題和所有其他編程語言特有的序列化問題一樣,就是它只能用於Python,並且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的數據,不能成功地反序列化也沒關系
后續的一些其它重要模塊會慢慢補上。
