23 Python操作數(shù)據(jù)庫(kù)

使用簡(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所示筋岛。

1 Python DB-API模塊特性全局變量

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所示弥喉。

2 DB-API常見(jiàn)異常

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ù)類型為字符串類型讥蟆。

3 connect函數(shù)常用參數(shù)

connect函數(shù)返回連接對(duì)象,這個(gè)連接對(duì)象表示目前和數(shù)據(jù)庫(kù)的會(huì)話纺阔。連接對(duì)象支持的方法如表4所示瘸彤。

4 連接對(duì)象方法

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)特性的概述。

5 游標(biāo)對(duì)象方法
6 游標(biāo)對(duì)象特性

游標(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ù)和特殊值缭乘。


7 DB-API構(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é)果如下:

CREATE TABLE SUCCESS.

從MySQL客戶端查看表結(jié)構(gòu)盒件,如圖1所示蹬碧。
1 employee表結(jié)構(gòu)

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所示恩沽。


2 插入數(shù)據(jù)結(jié)果

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了。


3 表更新結(jié)果

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ù)被刪除了未巫。

4 記錄刪除

事務(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)是否正確的代碼即可。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末门粪,一起剝皮案震驚了整個(gè)濱河市喊积,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌玄妈,老刑警劉巖乾吻,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異拟蜻,居然都是意外死亡绎签,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)酝锅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)诡必,“玉大人,你說(shuō)我怎么就攤上這事搔扁“质妫” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵稿蹲,是天一觀的道長(zhǎng)扭勉。 經(jīng)常有香客問(wèn)我,道長(zhǎng)苛聘,這世上最難降的妖魔是什么涂炎? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮设哗,結(jié)果婚禮上璧尸,老公的妹妹穿的比我還像新娘。我一直安慰自己熬拒,他們只是感情好爷光,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著澎粟,像睡著了一般蛀序。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上活烙,一...
    開(kāi)封第一講書(shū)人閱讀 52,158評(píng)論 1 308
  • 那天徐裸,我揣著相機(jī)與錄音,去河邊找鬼啸盏。 笑死重贺,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播气笙,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼次企,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了潜圃?” 一聲冷哼從身側(cè)響起缸棵,我...
    開(kāi)封第一講書(shū)人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎谭期,沒(méi)想到半個(gè)月后堵第,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡隧出,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年踏志,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胀瞪。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡狰贯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出赏廓,到底是詐尸還是另有隱情涵紊,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布幔摸,位于F島的核電站摸柄,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏既忆。R本人自食惡果不足惜驱负,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望患雇。 院中可真熱鬧跃脊,春花似錦、人聲如沸苛吱。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)翠储。三九已至绘雁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間援所,已是汗流浹背庐舟。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留住拭,地道東北人挪略。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓历帚,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親杠娱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子挽牢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容