python模塊與包的導入


模塊:

  一個模塊就是一個包含了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
test.py(module) 
import test         #導入模塊,導入就是在執行導入的文件
                     #導入模塊后,就是通過import定義一個模塊名,並且這個模塊下的所以名字都因此在test名字的后面
print(test.money)   #這樣才能取到test模塊下面的各種變量
use_test.py(use module)

 

 請看下圖

要想取出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()
# #解壓
tarfile解壓與壓縮

 

 

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保存那些不重要的數據,不能成功地反序列化也沒關系

 

 

后續的一些其它重要模塊會慢慢補上。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM