使用簡(jiǎn)單的純文本方式只能實(shí)現(xiàn)有限的功能牲芋,不能進(jìn)行快速查詢,只有把數(shù)據(jù)全部讀到內(nèi)存中才能自己遍歷捺球。不過(guò)在實(shí)際應(yīng)用中缸浦,我們操作的數(shù)據(jù)大小經(jīng)常遠(yuǎn)遠(yuǎn)超過(guò)內(nèi)存,根本無(wú)法全部讀入內(nèi)存氮兵。
為了便于程序保存和讀取數(shù)據(jù)裂逐,并直接通過(guò)條件快速查詢指定的數(shù)據(jù),于是出現(xiàn)了數(shù)據(jù)庫(kù)(Database)這種專門(mén)用于集中存儲(chǔ)和查詢的軟件泣栈。
這里將介紹在Python 3.5中使用PyMySQL連接數(shù)據(jù)庫(kù)絮姆,并實(shí)現(xiàn)簡(jiǎn)單的增、刪秩霍、改、查蚁阳。
數(shù)據(jù)庫(kù)介紹
數(shù)據(jù)庫(kù)歷史非常久遠(yuǎn)铃绒,早在1950年就誕生了。經(jīng)歷了網(wǎng)狀數(shù)據(jù)庫(kù)螺捐、層次數(shù)據(jù)庫(kù)颠悬,我們現(xiàn)在廣泛使用的關(guān)系數(shù)據(jù)庫(kù)是20世紀(jì)70年代在關(guān)系模型的基礎(chǔ)上誕生的。
目前定血,廣泛使用的關(guān)系數(shù)據(jù)庫(kù)分為付費(fèi)型和免費(fèi)型赔癌。付費(fèi)型數(shù)據(jù)庫(kù)主要有以下幾種:
(1)Oracle,典型的“高富帥”澜沟,收費(fèi)昂貴灾票,產(chǎn)品確實(shí)好,當(dāng)前很多大型公司仍然使用它茫虽。
(2)SQL Server刊苍,微軟自家產(chǎn)品,Windows定制尡粑觯款正什。
(3)DB2,IBM的產(chǎn)品婴氮。
(4)Sybase,曾經(jīng)跟微軟關(guān)系非常親密,后來(lái)關(guān)系破裂主经,使用的人比較少了荣暮,已逐漸淡出大家的視野。
這些數(shù)據(jù)庫(kù)都是不開(kāi)源而且付費(fèi)的旨怠,最大的好處是出了問(wèn)題可以找廠家解決渠驼。不過(guò)在Web的世界里,通常需要部署成千上萬(wàn)數(shù)據(jù)庫(kù)服務(wù)器鉴腻,如果使用付費(fèi)型數(shù)據(jù)庫(kù)迷扇,賺的錢(qián)都會(huì)被拿去買(mǎi)服務(wù)器了。所以爽哎,無(wú)論是Google蜓席、Facebook,還是國(guó)內(nèi)的BAT课锌,無(wú)一例外都選擇免費(fèi)的開(kāi)源數(shù)據(jù)庫(kù)厨内。當(dāng)前流行的免費(fèi)數(shù)據(jù)庫(kù)有以下幾種:
(1)MySQL,當(dāng)前使用最為廣泛的開(kāi)源數(shù)據(jù)庫(kù)渺贤。
(2)PostgreSQL雏胃,學(xué)術(shù)氣息有點(diǎn)重,其實(shí)挺不錯(cuò)志鞍,不過(guò)知名度沒(méi)有MySQL高瞭亮。
(3)SQLite,嵌入式數(shù)據(jù)庫(kù)固棚,適合桌面和移動(dòng)應(yīng)用统翩。
作為Python開(kāi)發(fā)工程師,選擇哪款免費(fèi)數(shù)據(jù)庫(kù)呢此洲?當(dāng)然是MySQL厂汗。因?yàn)镸ySQL普及率最高,出了錯(cuò)可以很容易找到解決方法呜师,而且圍繞MySQL有一大堆監(jiān)控和運(yùn)維工具娶桦,安裝和使用很方便。
為了繼續(xù)后面的學(xué)習(xí)汁汗,你需要從MySQL官方網(wǎng)站(http://www.mysql.com)下載并安裝MySQL Community Server趟紊。
你也許還聽(tīng)說(shuō)過(guò)NoSQL數(shù)據(jù)庫(kù),很多NoSQL宣傳速度和規(guī)模遠(yuǎn)遠(yuǎn)超過(guò)關(guān)系數(shù)據(jù)庫(kù)碰酝,是否有很多同學(xué)覺(jué)得有了NoSQL就不需要SQL了呢霎匈?這樣的想法是錯(cuò)誤的,在搞明白NoSQL之前送爸,還需要先明白SQL铛嘱,在SQL的基礎(chǔ)上學(xué)習(xí)NoSQL很容易暖释,反過(guò)來(lái)就不行了。
本章主要介紹Python如何操作數(shù)據(jù)庫(kù)墨吓,并不是單純介紹數(shù)據(jù)庫(kù)球匕,如果你想從零學(xué)習(xí)關(guān)系數(shù)據(jù)庫(kù)和基本的SQL語(yǔ)句,還需查看相關(guān)資料帖烘。
Python數(shù)據(jù)庫(kù)API
Python數(shù)據(jù)庫(kù)API是為方便統(tǒng)一操作數(shù)據(jù)庫(kù)而提出的一個(gè)標(biāo)準(zhǔn)接口(API)亮曹,也稱為DB-API。
在沒(méi)有Python DB-API之前秘症,各數(shù)據(jù)庫(kù)之間的應(yīng)用接口非痴肇裕混亂,實(shí)現(xiàn)各不相同乡摹。如果項(xiàng)目需要更換數(shù)據(jù)庫(kù)役耕,就需要進(jìn)行大量修改,非常不便聪廉。Python DB-API的出現(xiàn)就是為了解決這些問(wèn)題瞬痘。
Python所有數(shù)據(jù)庫(kù)接口程序都在一定程度上遵守Python DB-API規(guī)范。DB-API定義了一系列必需的對(duì)象和數(shù)據(jù)庫(kù)存取方式板熊,以便為各種各樣的底層數(shù)據(jù)庫(kù)系統(tǒng)和數(shù)據(jù)庫(kù)接口程序提供一致的訪問(wèn)接口框全。由于DB-API為不同數(shù)據(jù)庫(kù)提供了一致的訪問(wèn)接口,因此在不同的數(shù)據(jù)庫(kù)之間移植代碼成為一件輕松的事情干签。
DB-API規(guī)范包括全局變量津辩、異常、連接筒严、游標(biāo)和類型等基本概念,下面我們逐一進(jìn)行介紹情萤。
1 全局變量
DB-API規(guī)范規(guī)定數(shù)據(jù)庫(kù)接口模塊必須實(shí)現(xiàn)一些全局屬性以保證兼容性鸭蛙。Python提供了3個(gè)描述數(shù)據(jù)庫(kù)模塊特性的全局變量,如表1所示筋岛。
apilevel指的是API級(jí)別娶视,是一個(gè)字符串常量,表示這個(gè)DB-API模塊所兼容的DB-API最高版本號(hào)睁宰。例如肪获,版本號(hào)是1.0、2.0柒傻,如果未定義孝赫,就默認(rèn)是1.0。
線程安全等級(jí)Threadsafety是一個(gè)整數(shù),取值范圍如下:
0表示不支持線程安全红符,多個(gè)線程不能共享此模塊青柄。
1表示初級(jí)線程安全支持伐债,線程可以共享模塊,但不能共享連接致开。
2表示中級(jí)線程安全支持峰锁,線程可以共享模塊和連接,但不能共享游標(biāo)双戳。
3表示完全線程安全支持虹蒋,線程可以共享模塊、連接及游標(biāo)飒货。
參數(shù)風(fēng)格(paramstyle)表示執(zhí)行多次類似查詢時(shí)魄衅,參數(shù)如何被拼接到SQL查詢中。值format表示標(biāo)準(zhǔn)字符串格式化(使用基本的格式代碼)膏斤,可以在參數(shù)中進(jìn)行拼接的地方插入%s徐绑。值pyformt表示擴(kuò)展的格式代碼,用于字典拼接莫辨,如%(foo)傲茄。除了Python風(fēng)格之外,還有3種接合方式:qmark的意思是使用問(wèn)號(hào)沮榜,numeric表示使用:1或:2格式的字段(數(shù)字表示參數(shù)的序號(hào))盘榨,而named表示:foobar這樣的字段。其中蟆融,foobar為參數(shù)名草巡。
16.2.2 異常
為了能盡可能準(zhǔn)確地處理錯(cuò)誤,DB-API中定義了一些異常型酥。這些異常被定義在層次結(jié)構(gòu)中山憨,可以通過(guò)一個(gè)except塊捕捉多種異常。
異常的層次如表2所示弥喉。
3 連接和游標(biāo)
為了使用基礎(chǔ)數(shù)據(jù)庫(kù)系統(tǒng)郁竟,首先必須連接它。連接數(shù)據(jù)庫(kù)需要使用具有恰當(dāng)名稱的connect函數(shù)由境。該函數(shù)有多個(gè)參數(shù)棚亩,具體使用哪個(gè)參數(shù)需要根據(jù)數(shù)據(jù)庫(kù)類型進(jìn)行選擇。DB-API定義了表3所示的參數(shù)作為準(zhǔn)則(建議將這些參數(shù)按表中給定的順序傳遞)虏杰。參數(shù)類型為字符串類型讥蟆。
connect函數(shù)返回連接對(duì)象,這個(gè)連接對(duì)象表示目前和數(shù)據(jù)庫(kù)的會(huì)話纺阔。連接對(duì)象支持的方法如表4所示瘸彤。
rollback方法可能不可用,因?yàn)椴皇撬袛?shù)據(jù)庫(kù)都支持事務(wù)笛钝。
commit方法總是可用的钧栖,不過(guò)如果數(shù)據(jù)庫(kù)不支持事務(wù)低零,它就沒(méi)有任何作用。
cursor方法指游標(biāo)對(duì)象拯杠。通過(guò)游標(biāo)執(zhí)行SQL查詢并檢查結(jié)果掏婶。游標(biāo)比連接支持更多方法,而且在程序中更好用潭陪。表5是游標(biāo)方法的概述雄妥,表6是游標(biāo)特性的概述。
游標(biāo)對(duì)象最重要的屬性是
execute*()
和fetch*()
方法依溯。所有對(duì)數(shù)據(jù)庫(kù)服務(wù)器的請(qǐng)求都由這兩個(gè)方法完成老厌。對(duì)fetchmany()
方法來(lái)說(shuō),設(shè)置一個(gè)合理的arraysize
屬性很有用黎炉。當(dāng)然枝秤,在不需要時(shí)最好關(guān)掉游標(biāo)對(duì)象。
4 類型
每一個(gè)插入數(shù)據(jù)庫(kù)中的數(shù)據(jù)都對(duì)應(yīng)一個(gè)數(shù)據(jù)類型慷嗜,每一列數(shù)據(jù)對(duì)應(yīng)同一個(gè)數(shù)據(jù)類型淀弹,不同列對(duì)應(yīng)不同的數(shù)據(jù)類型。在數(shù)據(jù)庫(kù)操作的過(guò)程中庆械,為了能夠正確與基礎(chǔ)SQL數(shù)據(jù)庫(kù)進(jìn)行數(shù)據(jù)交互操作薇溃,DB-API定義了用于特殊類型和值的構(gòu)造函數(shù)及常量,所有模塊都要求實(shí)現(xiàn)表7所示的構(gòu)造函數(shù)和特殊值缭乘。
注:新紀(jì)元指1970-01-01 00:00:01 utc時(shí)間
數(shù)據(jù)庫(kù)操作
前面我們介紹了數(shù)據(jù)庫(kù)的基本概念沐序,本節(jié)具體介紹數(shù)據(jù)庫(kù)的連接及增、刪堕绩、改策幼、查、操作奴紧。
下面的示例以數(shù)據(jù)庫(kù)為T(mén)EST特姐,表名為employee,employee表字段為FIRST_NAME绰寞、LAST_NAME到逊、AGE铣口、SEX滤钱、INCOME和CREATE_TIME。
連接數(shù)據(jù)庫(kù)TEST使用的用戶名為root脑题,密碼為root件缸。
在系統(tǒng)上已經(jīng)安裝了Python PyMySQ模塊。若不知道怎么安裝叔遂,則可查閱相關(guān)資料他炊。
如果對(duì)SQL語(yǔ)句不熟悉争剿,就要先了解數(shù)據(jù)庫(kù)的一些基本操作,以方便更好理解接下來(lái)的內(nèi)容痊末。
1 數(shù)據(jù)庫(kù)連接
下面是連接MySQL TEST數(shù)據(jù)庫(kù)的實(shí)例。
#! /usr/bin/python
# -*-coding:UTF-8-*-
import pymysql
def db_connect():
# 打開(kāi)數(shù)據(jù)庫(kù)連接
db = pymysql.connect("localhost", "root", "root", "test")
# 使用cursor()方法創(chuàng)建一個(gè)游標(biāo)對(duì)象cursor
cursor = db.cursor()
# 使用execute()方法執(zhí)行SQL查詢
cursor.execute("SELECT VERSION()")
# 使用 fetchone() 方法獲取單條數(shù)據(jù)
data = cursor.fetchone()
print ("Database version : %s " % data)
# 關(guān)閉數(shù)據(jù)庫(kù)連接
db.close()
def main():
db_connect()
if __name__ == "__main__":
main()
執(zhí)行結(jié)果如下:
Database version : 5.5.28
2 創(chuàng)建數(shù)據(jù)庫(kù)表
如果數(shù)據(jù)庫(kù)連接存在凿叠,我們就可以使用execute()方法為數(shù)據(jù)庫(kù)創(chuàng)建表涩笤。創(chuàng)建表EMPLOYEE的代碼如下:
#! /usr/bin/python
# -*-coding:UTF-8-*-
import pymysql
def create_table():
db = pymysql.connect("localhost", "root", "root", "test")
# 使用 cursor() 方法創(chuàng)建一個(gè)游標(biāo)對(duì)象cursor
cursor = db.cursor()
# 使用 execute() 方法執(zhí)行 SQL,如果表存在就刪除
cursor.execute("DROP TABLE IF EXISTS EMPLOYEE")
# 使用預(yù)處理語(yǔ)句創(chuàng)建表
sql = """CREATE TABLE EMPLOYEE (
FIRST_NAME CHAR(20) NOT NULL,
LAST_NAME CHAR(20),
AGE INT,
SEX CHAR(1),
INCOME FLOAT,
CREATE_TIME DATETIME)"""
try:
cursor.execute(sql)
print("CREATE TABLE SUCCESS.")
except Exception as e:
print("CREATE TABLE FAILED,CASE:%s" % e)
finally:
# 關(guān)閉數(shù)據(jù)庫(kù)連接
db.close()
def main():
create_table()
if __name__ == "__main__":
main()
執(zhí)行結(jié)果如下:
從MySQL客戶端查看表結(jié)構(gòu)盒件,如圖1所示蹬碧。CREATE TABLE SUCCESS.
3 數(shù)據(jù)庫(kù)插入
下面使用SQL INSERT語(yǔ)句向表EMPLOYEE插入記錄(注意使用了datetime模塊)。
#! /usr/bin/python
# -*-coding:UTF-8-*-
import pymysql
import datetime
def insert_record():
db = pymysql.connect("localhost", "root", "root", "test")
# 使用cursor()方法獲取操作游標(biāo)
cursor = db.cursor()
# SQL 插入語(yǔ)句
sql = "INSERT INTO EMPLOYEE(FIRST_NAME,LAST_NAME, AGE, SEX, INCOME," \
" CREATE_TIME) VALUES('%s', '%s', %d, '%c', %d, '%s')" \
% ('xiao', 'zhi', 22, 'M', 30000, datetime.datetime.now())
try:
# 執(zhí)行sql語(yǔ)句
cursor.execute(sql)
# 提交到數(shù)據(jù)庫(kù)執(zhí)行
db.commit()
print("INSERT SUCCESS.")
except Exception as e:
print('INSERT INTO MySQL table failed.Case:%s' % e)
# 如果發(fā)生錯(cuò)誤就回滾
db.rollback()
finally:
# 關(guān)閉數(shù)據(jù)庫(kù)連接
db.close()
def main():
insert_record()
if __name__ == "__main__":
main()
執(zhí)行結(jié)果如下:
INSERT SUCCESS.
從MySQL客戶端查看表插入結(jié)果炒刁,如圖16-2所示恩沽。
4 數(shù)據(jù)庫(kù)查詢
Python查詢MySQL使用fetchone()方法獲取單條數(shù)據(jù),使用fetchall()方法獲取多條數(shù)據(jù)翔始。
- fetchone():該方法獲取下一個(gè)查詢結(jié)果集罗心。結(jié)果集是一個(gè)對(duì)象。
- fetchall():接收全部返回結(jié)果行绽昏。
- Rowcount:這是一個(gè)只讀屬性协屡,返回執(zhí)行execute()方法后影響的行數(shù)。
下面的示例用于查詢EMPLOYEE表中salary(工資)字段大于10000的所有數(shù)據(jù)全谤。
#! /usr/bin/python
# -*-coding:UTF-8-*-
import pymysql
def query_data():
# 打開(kāi)數(shù)據(jù)庫(kù)連接
db = pymysql.connect("localhost", "root", "root", "test")
# 使用cursor()方法獲取操作游標(biāo)
cursor = db.cursor()
# SQL 查詢語(yǔ)句
sql = "SELECT * FROM EMPLOYEE WHERE INCOME > %d" % 10000
try:
# 執(zhí)行SQL語(yǔ)句
cursor.execute(sql)
# 獲取所有記錄列表
results = cursor.fetchall()
for row in results:
fname = row[0]
lname = row[1]
age = row[2]
sex = row[3]
income = row[4]
create_time = row[5]
# 輸出結(jié)果
print("first_name=%s,last_name=%s,age=%d,\n"
"sex=%s,income=%d,create_time=%s" %
(first_name, last_name, age, sex, income, create_time))
except Exception as e:
print("Error: unable to fecth data.Error info:%s" % e)
finally:
# 關(guān)閉數(shù)據(jù)庫(kù)連接
db.close()
def main():
query_data()
if __name__ == "__main__":
main()
執(zhí)行結(jié)果如下:
first_name=xiao,last_name=zhi,age=22,
sex=M,income=30000,create_time=2016-10-05 22:29:37
5 數(shù)據(jù)庫(kù)更新
下面的示例將EMPLOYEE表中SEX字段值為'M'的記錄的AGE字段值增加1:
#! /usr/bin/python
# -*-coding:UTF-8-*-
import pymysql
def update_table():
# 打開(kāi)數(shù)據(jù)庫(kù)連接
db = pymysql.connect("localhost", "root", "root", "test")
# 使用cursor()方法獲取操作游標(biāo)
cursor = db.cursor()
# SQL 更新語(yǔ)句
sql = "UPDATE EMPLOYEE SET AGE = AGE + 1 WHERE SEX = '%s'" % 'M'
try:
# 執(zhí)行SQL語(yǔ)句
cursor.execute(sql)
# 提交到數(shù)據(jù)庫(kù)執(zhí)行
db.commit()
print("UPDATE SUCCESS.")
except Exception as e:
print('UPDATE MySQL table failed.Case:%s' % e)
# 發(fā)生錯(cuò)誤時(shí)回滾
db.rollback()
finally:
# 關(guān)閉數(shù)據(jù)庫(kù)連接
db.close()
def main():
update_table()
if __name__ == "__main__":
main()
執(zhí)行結(jié)果如下:
UPDATE SUCCESS.
從MySQL客戶端查看更新結(jié)果肤晓,如圖3所示∪先唬可以發(fā)現(xiàn)补憾,AGE變?yōu)?3了。
6 數(shù)據(jù)庫(kù)刪除
刪除操作用于刪除數(shù)據(jù)表中對(duì)應(yīng)的數(shù)據(jù)卷员。
下面演示刪除數(shù)據(jù)表EMPLOYEE中AGE大于22的所有數(shù)據(jù)盈匾。
#! /usr/bin/python
# -*-coding:UTF-8-*-
import pymysql
def delete_record():
# 打開(kāi)數(shù)據(jù)庫(kù)連接
db = pymysql.connect("localhost", "root", "root", "test")
# 使用cursor()方法獲取操作游標(biāo)
cursor = db.cursor()
# SQL 刪除語(yǔ)句
sql = "DELETE FROM EMPLOYEE WHERE AGE > %d" % 22
try:
# 執(zhí)行SQL語(yǔ)句
cursor.execute(sql)
# 提交修改
db.commit()
print("DELETE SUCCESS.")
except Exception as e:
print("DELETE RECORD FAILED.Case:%s" % e)
# 發(fā)生錯(cuò)誤時(shí)回滾
db.rollback()
finally:
# 關(guān)閉連接
db.close()
def main():
delete_record()
if __name__ == "__main__":
main()
行結(jié)果如下:
DELETE SUCCESS.
從MySQL客戶端查看刪除結(jié)果,如圖4所示毕骡∠鞫可以看到,之前插入的一條數(shù)據(jù)被刪除了未巫。
事務(wù)
事務(wù)機(jī)制可以確保數(shù)據(jù)的一致性窿撬。
事務(wù)具有4個(gè)屬性:原子性、一致性叙凡、隔離性劈伴、持久性,這4個(gè)屬性通常稱為ACID特性握爷。
- 原子性(Atomicity):一個(gè)事務(wù)是一個(gè)不可分割的工作單位跛璧,事務(wù)中的所有操作要么都做严里,要么都不做。
- 一致性(Consistency):事務(wù)必須使數(shù)據(jù)庫(kù)從一個(gè)一致性狀態(tài)變?yōu)榱硪粋€(gè)一致性狀態(tài)追城。一致性與原子性是密切相關(guān)的刹碾。
- 隔離性(Isolation):一個(gè)事務(wù)的執(zhí)行不能被其他事務(wù)干擾。也就是一個(gè)事務(wù)內(nèi)部的操作及使用的數(shù)據(jù)對(duì)并發(fā)的其他事務(wù)是隔離的座柱,并發(fā)執(zhí)行的各個(gè)事務(wù)之間不能互相干擾教硫。
- 持久性(Durability):持續(xù)性也稱永久性(Permanence),指一個(gè)事務(wù)一旦提交辆布,它對(duì)數(shù)據(jù)庫(kù)中數(shù)據(jù)的改變就應(yīng)該是永久性的瞬矩。接下來(lái)其他操作或故障不應(yīng)該對(duì)其有任何影響。
Python DB-API 2.0的事務(wù)提供了兩個(gè)方法锋玲,即commit和rollback景用。前面刪除方法中的一段代碼就使用了事務(wù)(前面的插入、更新都使用了事務(wù)):
# SQL刪除記錄語(yǔ)句
ql = "DELETE FROM EMPLOYEE WHERE AGE > %d" % 22
try:
# 執(zhí)行SQL語(yǔ)句
cursor.execute(sql)
# 提交修改
db.commit()
print("DELETE SUCCESS.")
except Exception as e:
print("DELETE RECORD FAILED.Case:%s" % e)
# 發(fā)生錯(cuò)誤時(shí)回滾
db.rollback()
finally:
# 關(guān)閉連接
db.close()
在Python數(shù)據(jù)庫(kù)編程中惭蹂,支持事務(wù)的數(shù)據(jù)庫(kù)在游標(biāo)建立時(shí)會(huì)自動(dòng)開(kāi)始一個(gè)隱形數(shù)據(jù)庫(kù)事務(wù)伞插。
commit()
方法提交所有更新操作,rollback()
方法回滾當(dāng)前游標(biāo)的所有操作盾碗。每一個(gè)方法都開(kāi)啟一個(gè)新事務(wù)媚污。
調(diào)試
初學(xué)者跟數(shù)據(jù)庫(kù)打交道時(shí)很容易碰到形形色色的問(wèn)題,可能一個(gè)非常簡(jiǎn)單的問(wèn)題也會(huì)導(dǎo)致你無(wú)法找到問(wèn)題所在廷雅。此時(shí)我們需要處理以下幾個(gè)問(wèn)題:
(1)程序中有沒(méi)有我們期望去做卻沒(méi)有實(shí)現(xiàn)的功能耗美?找到運(yùn)行該功能的代碼,并確保這段代碼如你所期望地運(yùn)行了航缀。
(2)程序中有沒(méi)有運(yùn)行某種不該出現(xiàn)的功能的代碼商架?
(3)有沒(méi)有一段代碼產(chǎn)生的效果和你所期望的不一致?確保你完全明白這段代碼芥玉,特別是牽涉對(duì)其他Python模塊的函數(shù)或方法調(diào)用時(shí)蛇摸。閱讀調(diào)用到的函數(shù)的文檔。使用簡(jiǎn)單的測(cè)試用例測(cè)試它們并檢查結(jié)果灿巧。
為了能夠編程赶袄,我們需要對(duì)程序如何工作有一個(gè)思維模型。如果編寫(xiě)了一段和你預(yù)料不同的代碼抠藕,常常問(wèn)題在于你的思維模型饿肺。
修正思維模型的最佳方法是將程序劃分成不同部分(通常是函數(shù)和方法),并獨(dú)立測(cè)試每一個(gè)部分幢痘。一旦找到模型和真實(shí)世界的偏差唬格,就能夠解決問(wèn)題家破。
在開(kāi)發(fā)過(guò)程中應(yīng)當(dāng)分組件進(jìn)行構(gòu)建和測(cè)試颜说。當(dāng)發(fā)現(xiàn)一個(gè)問(wèn)題時(shí)购岗,只需要檢查一小部分不確認(rèn)是否正確的代碼即可。