Python數(shù)據(jù)分析必備的第三方庫:

創(chuàng)新互聯(lián)建站是一家專業(yè)提供婺城企業(yè)網(wǎng)站建設,專注與成都網(wǎng)站建設、成都做網(wǎng)站、H5高端網(wǎng)站建設、小程序制作等業(yè)務。10年已為婺城眾多企業(yè)、政府機構等服務。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站制作公司優(yōu)惠進行中。
1、Pandas
Pandas是Python強大、靈活的數(shù)據(jù)分析和探索工具,包含Serise、DataFrame等高級數(shù)據(jù)結構和工具,安裝Pandas可使Python中處理數(shù)據(jù)非常快速和簡單。
Pandas是Python的一個數(shù)據(jù)分析包,Pandas最初使用用作金融數(shù)據(jù)分析工具而開發(fā)出來,因此Pandas為時間序列分析提供了很好的支持。
Pandas是為了解決數(shù)據(jù)分析任務而創(chuàng)建的,Pandas納入了大量的庫和一些標準的數(shù)據(jù)模型,提供了高效的操作大型數(shù)據(jù)集所需要的工具。Pandas提供了大量是我們快速便捷的處理數(shù)據(jù)的函數(shù)和方法。Pandas包含了高級數(shù)據(jù)結構,以及讓數(shù)據(jù)分析變得快速、簡單的工具。
2、Numpy
Numpy可以提供數(shù)組支持以及相應的高效處理函數(shù),是Python數(shù)據(jù)分析的基礎,也是Scipy、Pandas等數(shù)據(jù)處理和科學計算庫最基本的函數(shù)功能庫,且其數(shù)據(jù)類型對Python數(shù)據(jù)分析十分有用。
Numpy提供了兩種基本的對象:ndarray和ufunc。ndarray是存儲單一數(shù)據(jù)類型的多維數(shù)組,而ufunc是能夠對數(shù)組進行處理的函數(shù)。
3、Matplotlib
Matplotlib是強大的數(shù)據(jù)可視化工具和作圖庫,是主要用于繪制數(shù)據(jù)圖表的Python庫,提供了繪制各類可視化圖形的命令字庫、簡單的接口,可以方便用戶輕松掌握圖形的格式,繪制各類可視化圖形。
Matplotlib是Python的一個可視化模塊,他能方便的只做線條圖、餅圖、柱狀圖以及其他專業(yè)圖形。
Matplotlib是基于Numpy的一套Python包,這個包提供了豐富的數(shù)據(jù)繪圖工具,主要用于繪制一些統(tǒng)計圖形。
4、SciPy
SciPy是一組專門解決科學計算中各種標準問題域的包的集合,包含的功能有最優(yōu)化、線性代數(shù)、積分、插值、擬合、特殊函數(shù)、快速傅里葉變換、信號處理和圖像處理、常微分方程求解和其他科學與工程中常用的計算等,這些對數(shù)據(jù)分析和挖掘十分有用。
SciPy是一款方便、易于使用、專門為科學和工程設計的Python包,它包括統(tǒng)計、優(yōu)化、整合、線性代數(shù)模塊、傅里葉變換、信號和圖像處理、常微分方程求解器等。Scipy依賴于Numpy,并提供許多對用戶友好的和有效的數(shù)值例程,如數(shù)值積分和優(yōu)化。
5、Keras
Keras是深度學習庫,人工神經網(wǎng)絡和深度學習模型,基于Theano之上,依賴于Numpy和Scipy,利用它可以搭建普通的神經網(wǎng)絡和各種深度學習模型,如語言處理、圖像識別、自編碼器、循環(huán)神經網(wǎng)絡、遞歸審計網(wǎng)絡、卷積神經網(wǎng)絡等。
6、Scrapy
Scrapy是專門為爬蟲而生的工具,具有URL讀取、HTML解析、存儲數(shù)據(jù)等功能,可以使用Twisted異步網(wǎng)絡庫來處理網(wǎng)絡通訊,架構清晰,且包含了各種中間件接口,可以靈活的完成各種需求。
7、Gensim
Gensim是用來做文本主題模型的庫,常用于處理語言方面的任務,支持TF-IDF、LSA、LDA和Word2Vec在內的多種主題模型算法,支持流式訓練,并提供了諸如相似度計算、信息檢索等一些常用任務的API接口。
5個常用的Python標準庫:
1、os:提供了不少與操作系統(tǒng)相關聯(lián)的函數(shù)庫
os包是Python與操作系統(tǒng)的接口。我們可以用os包來實現(xiàn)操作系統(tǒng)的許多功能,比如管理系統(tǒng)進程,改變當前路徑,改變文件權限等。但要注意,os包是建立在操作系統(tǒng)的平臺上的,許多功能在Windows系統(tǒng)上是無法實現(xiàn)的。另外,在使用os包中,要注意其中的有些功能已經被其他的包取代。
我們通過文件系統(tǒng)來管理磁盤上儲存的文件。查找、刪除、復制文件以及列出文件列表等都是常見的文件操作。這些功能通常可以在操作系統(tǒng)中看到,但現(xiàn)在可以通過Python標準庫中的glob包、shutil包、os.path包以及os包的一些函數(shù)等,在Python內部實現(xiàn)。
2、sys:通常用于命令行參數(shù)的庫
sys包被用于管理Python自身的運行環(huán)境。Python是一個解釋器,也是一個運行在操作系統(tǒng)上的程序。我們可以用sys包來控制這一程序運行的許多參數(shù),比如說Python運行所能占據(jù)的內存和CPU,Python所要掃描的路徑等。另一個重要功能是和Python自己的命令行互動,從命令行讀取命令和參數(shù)。
3、random:用于生成隨機數(shù)的庫
Python標準庫中的random函數(shù),可以生成隨機浮點數(shù)、整數(shù)、字符串,甚至幫助你隨機選擇列表序列中的一個元素,打亂一組數(shù)據(jù)等。
4、math:提供了數(shù)學常數(shù)和數(shù)學函數(shù)
標準庫中,Python定義了一些新的數(shù)字類型,以彌補之前的數(shù)字類型可能的不足。標準庫還包含了random包,用于處理隨機數(shù)相關的功能。math包補充了一些重要的數(shù)學常數(shù)和數(shù)學函數(shù),比如pi、三角函數(shù)等等。
5、datetime:日期和時間的操作庫
日期和時間的管理并不復雜,但容易犯錯。Python的標準庫中對日期和時間的管理頗為完善,你不僅可以進行日期時間的查詢和變換,還可以對日期時間進行運算。通過這些標準庫,還可以根據(jù)需要控制日期時間輸出的文本格式。
除此之外,Python還有很多第三方庫,了解更多可移步:oldboyedu
本文Python 操作 MySQL 數(shù)據(jù)庫需要是使用到 PyMySQL 驅動
Python 操作 MySQL 前提是要安裝好 MySQL 數(shù)據(jù)庫并能正常連接使用,安裝步驟詳見下文。
注意: 安裝過程我們需要通過開啟管理員權限來安裝,否則會由于權限不足導致無法安裝。
首先需要先下載 MySQL 安裝包, 官網(wǎng)下載地址 下載對應版本即可,或直接在網(wǎng)上拉取并安裝:
權限設置:
初始化 MySQL:
啟動 MySQL:
查看 MySQL 運行狀態(tài):
Mysql安裝成功后,默認的root用戶密碼為空,你可以使用以下命令來創(chuàng)建root用戶的密碼:
登陸:
創(chuàng)建數(shù)據(jù)庫:
查看數(shù)據(jù)庫:
PyMySQL 模塊使用 pip命令進行安裝:
假如系統(tǒng)不支持 pip 命令,可以使用以下方式安裝:
pymysql .connect 函數(shù):連接上數(shù)據(jù)庫
輸出結果顯示如下:表面數(shù)據(jù)庫連接成功
使用 pymysql 的 connect() 方法連接數(shù)據(jù)庫,connect 參數(shù)解釋如下:
conn.cursor():獲取游標
如果要操作數(shù)據(jù)庫,光連接數(shù)據(jù)是不夠的,咱們必須拿到操作數(shù)據(jù)庫的游標,才能進行后續(xù)的操作,游標的主要作用是用來接收數(shù)據(jù)庫操作后的返回結果,比如讀取數(shù)據(jù)、添加數(shù)據(jù)。通過獲取到的數(shù)據(jù)庫連接實例 conn 下的 cursor() 方法來創(chuàng)建游標,實例如下:
輸出結果為:
cursor 返回一個游標實例對象,其中包含了很多操作數(shù)據(jù)的方法,如執(zhí)行sql語句,sql 執(zhí)行命令: execute() 和 executemany()
execute(query,args=None):
executemany(query,args=None):
其他游標對象如下表:
完整數(shù)據(jù)庫連接操作實例如下:
以上結果輸出為:
創(chuàng)建表代碼如下:
如下所示數(shù)據(jù)庫表創(chuàng)建成功:
插入數(shù)據(jù)實現(xiàn)代碼:
插入數(shù)據(jù)結果:
Python查詢Mysql使用 fetchone() 方法獲取單條數(shù)據(jù), 使用fetchall() 方法獲取多條數(shù)據(jù)。
查詢數(shù)據(jù)代碼如下:
輸出結果:
DB API中定義了一些數(shù)據(jù)庫操作的錯誤及異常,下表列出了這些錯誤和異常:
本文給大家介紹 Python 如何連接 Mysql 進行數(shù)據(jù)的增刪改查操作,文章通過簡潔的代碼方式進行示例演示,給使用 Python 操作 Mysql 的工程師提供支撐。
對大多數(shù)軟件開發(fā)者而言,術語數(shù)據(jù)庫通常是指RDBMS(關系數(shù)據(jù)庫管理系統(tǒng)), 這些系統(tǒng)使用表格(類似于電子表格的網(wǎng)格),其中行表示記錄,列表示記錄的字段。表格及其中存放的數(shù)據(jù)是使用SQL (結構化査詢語言)編寫的語句來創(chuàng)建并操縱的。Python提供了用于操縱SQL數(shù)據(jù)庫的API(應用程序接口),通常與作為標準的SQLite 3數(shù)據(jù)庫一起發(fā)布。
另一種數(shù)據(jù)庫是DBM (數(shù)據(jù)庫管理器),其中存放任意數(shù)量的鍵-值項。Python 的標準庫提供了幾種DBM的接口,包括某些特定于UNIX平臺的。DBM的工作方式 與Python中的字典類似,區(qū)別在于DBM通常存放于磁盤上而不是內存中,并且其鍵與值總是bytes對象,并可能受到長度限制。本章第一節(jié)中講解的shelve模塊提供了方便的DBM接口,允許我們使用字符串作為鍵,使用任意(picklable)對象作為值。
如果可用的 DBM 與 SQLite 數(shù)據(jù)庫不夠充分,Python Package Index, pypi.python.org/pypi中提供了大量數(shù)據(jù)庫相關的包,包括bsddb DBM ("Berkeley DB"),對象-關系映射器,比如SQLAlchemy (),以及流行的客戶端/服務器數(shù)據(jù)的接口,比如 DB2、Informix、Ingres、MySQL、ODBC 以及 PostgreSQL。
本章中,我們將實現(xiàn)某程序的兩個版本,該程序用于維護一個DVD列表,并追蹤每個DVD的標題、發(fā)行年份、時間長度以及發(fā)行者。該程序的第一版使用DBM (通過shelve模塊)存放其數(shù)據(jù),第二版則使用SQLite數(shù)據(jù)庫。兩個程序都可以加載與保存簡單的XML格式,這使得從某個程序導出DVD數(shù)據(jù)并將其導入到其他程序成為可能。與DBM版相比,基于SQL的程序提供了更多一些的功能,并且其數(shù)據(jù)設計也稍干凈一些。
12.1 DBM數(shù)據(jù)庫
shelve模塊為DBM提供了一個wrapper,借助于此,我們在與DBM交互時,可以將其看做一個字典,這里是假定我們只使用字符串鍵與picklable值,實際處理時, shelve模塊會將鍵與值轉換為bytes對象(或者反過來)。
由于shelve模塊使用的是底層的DBM,因此,如果其他計算機上沒有同樣的DBM,那么在某臺計算機上保存的DBM文件在其他機器上無法讀取是可能的。為解決這一問題,常見的解決方案是對那些必須在機器之間可傳輸?shù)奈募峁ML導入與導出功能,這也是我們在本節(jié)的DVD程序dvds-dbm.py中所做的。
對鍵,我們使用DVD的標題;對值,則使用元組,其中存放發(fā)行者、發(fā)行年份以及時間。借助于shelve模塊,我們不需要進行任何數(shù)據(jù)轉換,并可以把DBM對象當做一個字典進行處理。
程序在結構上類似于我們前面看到的那種菜單驅動型的程序,因此,這里主要展示的是與DBM程序設計相關的那部分。下面給出的是程序main()函數(shù)中的一部分, 忽略了其中菜單處理的部分代碼。
db = None
try:
db = shelve.open(filename, protocol=pickle.HIGHEST_PROTOCOL)
finally:
if db is not None:
db.dose()
這里我們已打開(如果不存在就創(chuàng)建)指定的DBM文件,以便于對其進行讀寫操作。每一項的值使用指定的pickle協(xié)議保存為一個pickle,現(xiàn)有的項可以被讀取, 即便是使用更底層的協(xié)議保存的,因為Python可以計算出用于讀取pickle的正確協(xié)議。最后,DBM被關閉——其作用是清除DBM的內部緩存,并確保磁盤文件可以反映出已作的任何改變,此外,文件也需要關閉。
該程序提供了用于添加、編輯、列出、移除、導入、導出DVD數(shù)據(jù)的相應選項。除添加外,我們將忽略大部分用戶接口代碼,同樣是因為已經在其他上下文中進行了展示。
def add_dvd(db):
title = Console.get_string("Title", "title")
if not title:
return
director = Console.get_string("Director", "director")
if not director:
return
year = Console.get_integer("Year", "year",minimum=1896,
maximum=datetime,date.today().year)
duration = Console.get_integer("Duration (minutes)", "minutes“, minimum=0, maximum=60*48)
db[title] = (director, year, duration)
db.sync()
像程序菜單調用的所有函數(shù)一樣,這一函數(shù)也以DBM對象(db)作為其唯一參數(shù)。該函數(shù)的大部分工作都是獲取DVD的詳細資料,在倒數(shù)第二行,我們將鍵-值項存儲在DBM文件中,DVD的標題作為鍵,發(fā)行者、年份以及時間(由shelve模塊pickled在一起)作為值。
為與Python通常的一致性同步,DBM提供了與字典一樣的API,因此,除了 shelve.open() 函數(shù)(前面已展示)與shelve.Shelf.sync()方法(該方法用于清除shelve的內部緩存,并對磁盤上文件的數(shù)據(jù)與所做的改變進行同步——這里就是添加一個新項),我們不需要學習任何新語法。
def edit_dvd(db):
old_title = find_dvd(db, "edit")
if old_title is None:
return
title = Console.get.string("Title", "title", old_title)
if not title:
return
director, year, duration = db[old_title]
...
db[title]= (director, year, duration)
if title != old_title:
del db[old_title]
db.sync()
為對某個DVD進行編輯,用戶必須首先選擇要操作的DVD,也就是獲取DVD 的標題,因為標題用作鍵,值則用于存放其他相關數(shù)據(jù)。由于必要的功能在其他場合 (比如移除DVD)也需要使用,因此我們將其實現(xiàn)在一個單獨的find_dvd()函數(shù)中,稍后將査看該函數(shù)。如果找到了該DVD,我們就獲取用戶所做的改變,并使用現(xiàn)有值作為默認值,以便提高交互的速度。(對于這一函數(shù),我們忽略了大部分用戶接口代碼, 因為其與添加DVD時幾乎是相同的。)最后,我們保存數(shù)據(jù),就像添加時所做的一樣。如果標題未作改變,就重寫相關聯(lián)的值;如果標題已改變,就創(chuàng)建一個新的鍵-值對, 并且需要刪除原始項。
def find_dvd(db, message):
message = "(Start of) title to " + message
while True:
matches =[]
start = Console.get_string(message, "title")
if not start:
return None
for title in db:
if title.lower().startswith(start.lower()):
matches.append(title)
if len(matches) == 0:
print("There are no dvds starting with", start)
continue
elif len(matches) == 1:
return matches[0]
elif len(matches) DISPLAY_LIMIT:
print("Too many dvds start with {0}; try entering more of the title".format(start)
continue
else:
matches = sorted(matches, key=str.lower)
for i, match in enumerate(matches):
print("{0}: {1}".format(i+1, match))
which = Console.get_integer("Number (or 0 to cancel)",
"number", minimum=1, maximum=len(matches))
return matches[which - 1] if which != 0 else None
為盡可能快而容易地發(fā)現(xiàn)某個DVD,我們需要用戶只輸入其標題的一個或頭幾個字符。在具備了標題的起始字符后,我們在DBM中迭代并創(chuàng)建一個匹配列表。如果只有一個匹配項,就返回該項;如果有幾個匹配項(但少于DISPLAY_LIMIT, 一個在程序中其他地方設置的整數(shù)),就以大小寫不敏感的順序展示所有這些匹配項,并為每一項設置一個編號,以便用戶可以只輸入編號就可以選擇某個標題。(Console.get_integer()函數(shù)可以接受0,即便最小值大于0,以便0可以用作一個刪除值。通過使用參數(shù)allow_zero=False, 可以禁止這種行為。我們不能使用Enter鍵,也就是說,沒有什么意味著取消,因為什么也不輸入意味著接受默認值。)
def list_dvds(db):
start =”"
if len(db) DISPLAY.LIMIT:
start = Console.get_string(“List those starting with [Enter=all]”, "start”)
print()
for title in sorted(db, key=str.lower):
if not start or title.Iower().startswith(start.lower()):
director, year, duration = db[title]
print("{title} ({year}) {duration} minute{0}, by "
"{director}".format(Util.s(duration),**locals()))
列出所有DVD (或者那些標題以某個子字符串引導)就是對DBM的所有項進行迭代。
Util.s()函數(shù)就是簡單的s = lambda x: "" if x == 1 else "s",因此,如果時間長度不是1分鐘,就返回"s"。
def remove_dvd(db):
title = find_dvd(db, "remove")
if title is None:
return
ans = Console.get_bool("Remove {0}?".format(title), "no")
if ans:
del db[title]
db.sync()
要移除一個DVD,首先需要找到用戶要移除的DVD,并請求確認,獲取后從DBM中刪除該項即可。
到這里,我們展示了如何使用shelve模塊打開(或創(chuàng)建)一個DBM文件,以及如何向其中添加項、編輯項、對其項進行迭代以及移除某個項。
遺憾的是,在我們的數(shù)據(jù)設計中存在一個瑕疵。發(fā)行者名稱是重復的,這很容易導致不一致性,比如,發(fā)行者Danny DeVito可能被輸入為"Danny De Vito",用于 一個電影;也可以輸入為“Danny deVito",用于另一個。為解決這一問題,可以使用兩個DBM文件,主DVD文件使用標題鍵與(年份,時間長度,發(fā)行者ID)值; 發(fā)行者文件使用發(fā)行者ID (整數(shù))鍵與發(fā)行者名稱值。下一節(jié)展示的SQL數(shù)據(jù)庫 版程序將避免這一瑕疵,這是通過使用兩個表格實現(xiàn)的,一個用于DVD,另一個用于發(fā)行者。
12.2 SQL數(shù)據(jù)庫
大多數(shù)流行的SQL數(shù)據(jù)庫的接口在第三方模塊中是可用的,Python帶有sqlite3 模塊(以及SQLite 3數(shù)據(jù)庫),因此,在Python中,可以直接開始數(shù)據(jù)庫程序設計。SQLite是一個輕量級的SQL數(shù)據(jù)庫,缺少很多諸如PostgreSQL這種數(shù)據(jù)庫的功能, 但非常便于構造原型系統(tǒng),并且在很多情況下也是夠用的。
為使后臺數(shù)據(jù)庫之間的切換盡可能容易,PEP 249 (Python Database API Specification v2.0)提供了稱為DB-API 2.0的API規(guī)范。數(shù)據(jù)庫接口應該遵循這一規(guī)范,比如sqlite3模塊就遵循這一規(guī)范,但不是所有第三方模塊都遵循。API規(guī)范中指定了兩種主要的對象,即連接對象與游標對象。表12-1與表12-2中分別列出了這兩種對象必須支持的API。在sqlite3模塊中,除DB-API 2.0規(guī)范必需的之外,其連接對象與游標對象都提供了很多附加的屬性與方法。
DVD程序的SQL版本為dvds.sql.py,該程序將發(fā)行者與DVD數(shù)據(jù)分開存儲,以 避免重復,并提供一個新菜單,以供用戶列出發(fā)行者。該程序使用的兩個表格在圖12-1
def connect(filename):
create= not os.path.exists(filename)
db = sqlite3.connect(filename)
if create:
cursor = db.cursor()
cursor.execute("CREATE TABLE directors ("
"id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, "
"name TEXT UNIQUE NOT NULL)")
cursor.execute("CREATE TABLE dvds ("
"id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, "
"title TEXT NOT NULL, "
"year INTEGER NOT NULL,"
"duration INTEGER NOT NULL, "
"director_id INTEGER NOT NULL, ”
"FOREIGN KEY (director_id) REFERENCES directors)")
db.commit()
return db
sqlite3.connect()函數(shù)會返回一個數(shù)據(jù)庫對象,并打開其指定的數(shù)據(jù)庫文件。如果該文件不存在,就創(chuàng)建一個空的數(shù)據(jù)庫文件。鑒于此,在調用sqlite3.connect()之前,我們要注意數(shù)據(jù)庫是否是準備從頭開始創(chuàng)建,如果是,就必須創(chuàng)建該程序要使用的表格。所有査詢都是通過一個數(shù)據(jù)庫游標完成的,可以從數(shù)據(jù)庫對象的cursor()方法獲取。
注意,兩個表格都是使用一個ID字段創(chuàng)建的,ID字段有一個AUTOINCREMENT 約束——這意味著SQLite會自動為ID字段賦予唯一性的數(shù)值,因此,在插入新記錄時,我們可以將這些字段留給SQLite處理。
SQLite支持有限的數(shù)據(jù)類型——實際上就是布爾型、數(shù)值型與字符串——但使用數(shù)據(jù)'‘適配器”可以對其進行擴展,或者是擴展到預定義的數(shù)據(jù)類型(比如那些用于日期與datetimes的類型),或者是用于表示任意數(shù)據(jù)類型的自定義類型。DVD程序并不需要這一功能,如果需要,sqlite3模塊的文檔提供了很多詳細解釋。我們使用的外部鍵語法可能與用于其他數(shù)據(jù)庫的語法不同,并且在任何情況下,只是記錄我們的意圖,因為SQLite不像很多其他數(shù)據(jù)庫那樣需要強制關系完整性,sqlite3另一點與眾不同的地方在于其默認行為是支持隱式的事務處理,因此,沒有提供顯式的“開始事務” 方法。
def add_dvd(db):
title = Console.get_string("Title", "title")
if not title:
return
director = Console.get_string("Director", "director")
if not director:
return
year = Console.get_integer("Year", "year”, minimum=1896,
maximum=datetime.date.today().year)
duration = Console.get_integer("Duration (minutes)", "minutes",
minimum=0,maximum=60*48)
director_id = get_and_set_director(db, director)
cursor = db.cursor()
cursor.execute("INSERT INTO dvds ”
"(title, year, duration, director_id)"
"VALUES (?, ?, ?, ?)",
(title, year, duration, director_id))
db.commit()
這一函數(shù)的開始代碼與dvds-dbm.py程序中的對應函數(shù)一樣,但在完成數(shù)據(jù)的收集后,與原來的函數(shù)有很大的差別。用戶輸入的發(fā)行者可能在也可能不在directors表格中,因此,我們有一個get_and_set_director()函數(shù),在數(shù)據(jù)庫中尚無某個發(fā)行者時, 該函數(shù)就將其插入到其中,無論哪種情況都返回就緒的發(fā)行者ID,以便在需要的時候插入到dvds表。在所有數(shù)據(jù)都可用后,我們執(zhí)行一條SQL INSERT語句。我們不需要指定記錄ID,因為SQLite會自動為我們提供。
在査詢中,我們使用問號(?)作為占位符,每個?都由包含SQL語句的字符串后面的序列中的值替代。命名的占位符也可以使用,后面在編輯記錄時我們將看到。盡管避免使用占位符(而只是簡單地使用嵌入到其中的數(shù)據(jù)來格式化SQL字符串)也是可能的,我們建議總是使用占位符,并將數(shù)據(jù)項正確編碼與轉義的工作留給數(shù)據(jù)庫模塊來完成。使用占位符的另一個好處是可以提高安全性,因為這可以防止任意的SQL 被惡意地插入到一個査詢中。
def get_and_set_director(db, director):
director_id = get_director_id(db, director)
if directorjd is not None:
return director_id
cursor = db.cursor()
cursor.execute("lNSERT INTO directors (name) VALUES (?)”,(director,))
db.commit()
return get_director_id(db, director)
這一函數(shù)返回給定發(fā)行者的ID,并在必要的時候插入新的發(fā)行者記錄。如果某個記錄被插入,我們首先嘗試使用get_director_id()函數(shù)取回其ID。
def get_director_id(db, director):
cursor = db.cursor()
cursor.execute("SELECT id FROM directors WHERE name=?",(director,))
fields = cursor.fetchone()
return fields[0] if fields is not None else None
get_director_id()函數(shù)返回給定發(fā)行者的ID,如果數(shù)據(jù)庫中沒有指定的發(fā)行者,就返回None。我們使用fetchone()方法,因為或者有一個匹配的記錄,或者沒有。(我們知道,不會有重復的發(fā)行者,因為directors表格的名稱字段有一個UNIQUE約束,在任何情況下,在添加一個新的發(fā)行者之前,我們總是先檢査其是否存在。)這種取回方法總是返回一個字段序列(如果沒有更多的記錄,就返回None)。即便如此,這里我們只是請求返回一個單獨的字段。
def edit_dvd(db):
title, identity = find_dvd(db, "edit")
if title is None:
return
title = Console.get_string("Title","title", title)
if not title:
return
cursor = db.cursor()
cursor.execute("SELECT dvds.year, dvds.duration, directors.name"
“FROM dvds, directors "
"WHERE dvds.director_id = directors.id AND "
"dvds.id=:id", dict(id=identity))
year, duration, director = cursor.fetchone()
director = Console.get_string("Director", "director", director)
if not director:
return
year = Console,get_integer("Year","year", year, 1896,datetime.date.today().year)
duration = Console.get_integer("Duration (minutes)", "minutes",
duration, minimum=0, maximum=60*48)
director_id = get_and_set_director(db, director)
cursor.execute("UPDATE dvds SET title=:title, year=:year,"
"duration=:duration, director_id=:directorjd "
"WHERE id=:identity", locals())
db.commit()
要編輯DVD記錄,我們必須首先找到用戶需要操縱的記錄。如果找到了某個記錄,我們就給用戶修改其標題的機會,之后取回該記錄的其他字段,以便將現(xiàn)有值作為默認值,將用戶的輸入工作最小化,用戶只需要按Enter鍵就可以接受默認值。這里,我們使用了命名的占位符(形式為:name),并且必須使用映射來提供相應的值。對SELECT語句,我們使用一個新創(chuàng)建的字典;對UPDATE語句,我們使用的是由 locals()返回的字典。
我們可以同時為這兩個語句都使用新字典,這種情況下,對UPDATE語句,我們可以傳遞 dict(title=title, year=year, duration=duration, director_id=director_id, id=identity)),而非 locals()。
在具備所有字段并且用戶已經輸入了需要做的改變之后,我們取回相應的發(fā)行者ID (如果必要就插入新的發(fā)行者記錄),之后使用新數(shù)據(jù)對數(shù)據(jù)庫進行更新。我們采用了一種簡化的方法,對記錄的所有字段進行更新,而不僅僅是那些做了修改的字段。
在使用DBM文件時,DVD標題被用作鍵,因此,如果標題進行了修改,我們就需要創(chuàng)建一個新的鍵-值項,并刪除原始項。不過,這里每個DVD記錄都有一個唯一性的ID,該ID是記錄初次插入時創(chuàng)建的,因此,我們只需要改變任何其他字段的值, 而不需要其他操作。
def find_dvd(db, message):
message = "(Start of) title to " + message
cursor = db.cursor()
while True: .
start = Console.get_stnng(message, "title")
if not start:
return (None, None)
cursor.execute("SELECT title, id FROM dvds "
"WHERE title LIKE ? ORDER BY title”,
(start +"%",))
records = cursor.fetchall()
if len(records) == 0:
print("There are no dvds starting with", start)
continue
elif len(records) == 1:
return records[0]
elif len(records) DISPLAY_LIMIT:
print("Too many dvds ({0}) start with {1}; try entering "
"more of the title".format(len(records),start))
continue
else:
for i, record in enumerate(records):
print("{0}:{1}".format(i + 1, record[0]))
which = Console.get_integer("Number (or 0 to cancel)",
"number", minimum=1, maximum=len(records))
return records[which -1] if which != 0 else (None, None)
這一函數(shù)的功能與dvdsdbm.py程序中的find_dvd()函數(shù)相同,并返回一個二元組 (DVD標題,DVD ID)或(None, None),具體依賴于是否找到了某個記錄。這里并不需要在所有數(shù)據(jù)上進行迭代,而是使用SQL通配符(%),因此只取回相關的記錄。
由于我們希望匹配的記錄數(shù)較小,因此我們一次性將其都取回到序列的序列中。如果有不止一個匹配的記錄,但數(shù)量上又少到可以顯示,我們就打印記錄,并將每條記錄附帶一個數(shù)字編號,以便用戶可以選擇需要的記錄,其方式與在dvds-dbm.py程序中所做的類似:
def list_dvds(db):
cursor = db.cursor()
sql = ("SELECT dvds.title, dvds.year, dvds.duration, "
"directors.name FROM dvds, directors "
"WHERE dvds.director_id = directors.id")
start = None
if dvd_count(db) DISPLAY_LIMIT:
start = Console.get_string("List those starting with [Enter=all]", "start")
sql += " AND dvds.title LIKE ?"
sql += ” ORDER BY dvds.title"
print()
if start is None:
cursor.execute(sql)
else:
cursor.execute(sql, (start +"%",))
for record in cursor:
print("{0[0]} ({0[1]}) {0[2]} minutes, by {0[3]}".format(record))
要列出每個DVD的詳細資料,我們執(zhí)行一個SELECT査詢。該査詢連接兩個表,如果記錄(由dvd_count()函數(shù)返回)數(shù)量超過了顯示限制值,就將第2個元素添加到WHERE 分支,之后執(zhí)行該査詢,并在結果上進行迭代。每個記錄都是一個序列,其字段是與 SELECT査詢相匹配的。
def dvd_count(db):
cursor = db.cursor()
cursor.execute("SELECT COUNT(*) FROM dvds")
return cursor.fetchone()[0]
我們將這幾行代碼放置在一個單獨的函數(shù)中,因為我們在幾個不同的函數(shù)中都需要使用這幾行代碼。
我們忽略了 list_directors()函數(shù)的代碼,因為該函數(shù)在結構上與list_dvds()函數(shù)非常類似,只不過更簡單一些,因為本函數(shù)只列出一個字段(name)。
def remove_dvd(db):
title, identity = find_dvd(db, "remove")
if title is None:
return
ans = Console.get_bool("Remove {0}?".format(title), "no")
if ans:
cursor = db.cursor()
cursor.execute("DELETE FROM dvds WHERE id=?", (identity,))
db.commit()
在用戶需要刪除一個記錄時,將調用本函數(shù),并且本函數(shù)與dvds-dbm.py程序中 相應的函數(shù)是非常類似的。
到此,我們完全查閱了 dvds-sql.py程序,并且了解了如何創(chuàng)建數(shù)據(jù)庫表格、選取 記錄、在選定的記錄上進行迭代以及插入、更新與刪除記錄。使用execute()方法,我們可以執(zhí)行底層數(shù)據(jù)庫所支持的任意SQL語句。
SQLite提供了比我們這里使用的多得多的功能,包括自動提交模式(以及任意其他類型的事務控制),以及創(chuàng)建可以在SQL查詢內執(zhí)行的函數(shù)的能力。提供一個工廠函數(shù)并用于控制對每個取回的記錄返回什么(比如,一個字典或自定義類型,而不是字段序列)也是可能的。此外,通過傳遞“:memory:”作為文件名,創(chuàng)建內存中的SQLite 數(shù)據(jù)庫也是可能的。
以上內容部分摘自視頻課程05后端編程Python22 數(shù)據(jù)庫編程,更多實操示例請參照視頻講解。跟著張員外講編程,學習更輕松,不花錢還能學習真本領。
網(wǎng)站欄目:python函數(shù)數(shù)據(jù)庫 python+數(shù)據(jù)庫
網(wǎng)站網(wǎng)址:http://chinadenli.net/article42/dojhdhc.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站維護、企業(yè)網(wǎng)站制作、建站公司、做網(wǎng)站、移動網(wǎng)站建設、網(wǎng)站策劃
聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)