Python學(xué)習(xí)筆記-第9天:項(xiàng)目實(shí)戰(zhàn)練習(xí)(4)+數(shù)據(jù)庫編程

第九天 項(xiàng)目實(shí)戰(zhàn)練習(xí)(4)+數(shù)據(jù)庫編程

今天計(jì)劃繼續(xù)坦克大戰(zhàn)練習(xí)虫给,學(xué)習(xí)項(xiàng)目及練習(xí)源碼地址:
GitHub源碼

坦克大戰(zhàn)繼續(xù)

碰撞檢測(cè)

在游戲開發(fā)中,通常把顯示圖像的對(duì)象叫做精靈Spire精靈需要有兩個(gè)屬性 image要顯示的圖像,rect圖像要顯示在屏幕的位置咖刃。
在Pygame框架中使用pygame.sprite模塊中的內(nèi)置函數(shù)可以實(shí)現(xiàn)碰撞檢測(cè)化漆。

pygame.sprite.collide_rect(first, second) #返回布爾值

pygame.sprite.Sprite是pygame精靈的基類,一般來說殊轴,總是需要寫一個(gè)自己的精靈類繼承pygame.sprite.Sprite衰倦。讓坦克類、子彈類都繼承編寫的精靈類梳凛。

音效處理

music是pygame中控制流音頻的pygame模塊耿币,音樂模塊與pygame.mixer緊密相連, pygame.mixer是一個(gè)用來處理聲音的模塊韧拒,其含義為“混音器”淹接。游戲中對(duì)聲音的處理一般包括制造聲音和播放聲音兩部分。使用pygame.mixer.music.load()加載一個(gè)播放音樂的文件pygame.mixer.music.play()開始播放音樂流叛溢。

小結(jié)

總算完成了塑悼,留有一點(diǎn)遺憾,就是敵方坦克在初始化的時(shí)候可能重疊坐標(biāo)楷掉,這樣會(huì)導(dǎo)致其無法移動(dòng)(穿墻限制)厢蒜,應(yīng)該很好處理,只是練習(xí)就愉快的跳過去了,我讓敵方坦克可以穿透任意坦克斑鸦,就行了愕贡,感覺這樣挺有意思:)。需要看源代碼的請(qǐng)?jiān)谏弦惶斓哪夸浝锩嬲业刂废镉欤揖筒毁N出來了固以。

花絮

想發(fā)布自己的小程序怎么辦?前面講過如何打包嘱巾,但是像游戲這樣的有資源文件憨琳,Pyinstaller如何將資源文件一起打包到一個(gè)app中呢?
基本原理:Pyinstaller 可以將資源文件一起bundle到exe中旬昭,當(dāng)exe在運(yùn)行時(shí)篙螟,會(huì)生成一個(gè)臨時(shí)文件夾,程序可通過sys._MEIPASS訪問臨時(shí)文件夾中的資源

官方說明:文檔

測(cè)試案例功能描述问拘,訪問資源文件夾res/a.txt遍略,并打印其內(nèi)容。實(shí)現(xiàn)方法如下:

源碼如下场梆,比較簡(jiǎn)單墅冷,resource_path方法說明了如何使用sys._MEIPASS變量來訪問臨時(shí)文件夾中的資源

#coding:utf-8
import sys
import os
#生成資源文件目錄訪問路徑
def resource_path(relative_path):
    if getattr(sys, 'frozen', False): #是否Bundle Resource
        base_path = sys._MEIPASS
    else:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)

#訪問res文件夾下a.txt的內(nèi)容
filename = resource_path(os.path.join("res","a.txt"))
print(filename)
with open(filename) as f:
    lines = f.readlines()
    print(lines)
    f.close()

結(jié)下來介紹如何生成可執(zhí)行文件:

首先需要生成spec文件,pyi-makespec -F test.py (如果要添加Icon等可以在這里就使用pyi-makespec --icon abc.jpg -F test.py語句生成spec文件)或油。編輯spec文件寞忿,在datas選項(xiàng)中說明需要將哪些文件加入exe,在零時(shí)文件夾中命名成什么即可。

然后:pyinstaller -F test.spec

數(shù)據(jù)庫編程

數(shù)據(jù)庫的重要性不言而喻顶岸!
Python支持多種數(shù)據(jù)庫腔彰,從Python3.x版本開始,在標(biāo)準(zhǔn)庫中已經(jīng)內(nèi)置了SQLlite3模塊辖佣,它可以支持SQLite3數(shù)據(jù)庫的訪問和相關(guān)的數(shù)據(jù)庫操作霹抛。在需要操作SQLite3數(shù)據(jù)庫數(shù)據(jù)時(shí),只須在程序中導(dǎo)入SQLite3模塊即可卷谈。雖然SQLlite3用的比較廣泛杯拐,但實(shí)際遇到更多的還是Mysql,MongoDB,Redis等

SQLite3

Python語言操作SQLite3數(shù)據(jù)庫的基本流程如下所示世蔗。

  • 導(dǎo)入相關(guān)庫或模塊(SQLite3)端逼。
  • 使用connect()連接數(shù)據(jù)庫并獲取數(shù)據(jù)庫連接對(duì)象。它提供了以下方法:
    1. .cursor() 方法來創(chuàng)建一個(gè)游標(biāo)對(duì)象
    2. .commit() 方法來處理事務(wù)提交
    3. .rollback() 方法來處理事務(wù)回滾
    4. .close() 方法來關(guān)閉一個(gè)數(shù)據(jù)庫連接
  • 使用con.cursor()獲取游標(biāo)對(duì)象污淋。
  • 使用游標(biāo)對(duì)象的方法(execute()顶滩、executemany()、fetchall()等)來操作數(shù)據(jù)庫寸爆,實(shí)現(xiàn)插入礁鲁、修改和刪除操作盐欺,并查詢獲取顯示相關(guān)的記錄。

在Python程序中仅醇,連接函數(shù)sqlite3.connect()有如下兩個(gè)常用參數(shù)冗美。

  1. database:表示要訪問的數(shù)據(jù)庫名。
  2. timeout:表示訪問數(shù)據(jù)的超時(shí)設(shè)定着憨。
  • 使用close()關(guān)閉游標(biāo)對(duì)象和數(shù)據(jù)庫連接墩衙。數(shù)據(jù)庫操作完成之后,必須及時(shí)調(diào)用其close()方法關(guān)閉數(shù)據(jù)庫連接甲抖,這樣做的目的是減輕數(shù)據(jù)庫服務(wù)器的壓力。

一個(gè)樣例代碼: 示例

Mysql

在Python3中大家用的比較多的還是pymysql模塊

安裝

pip3 install pymysql

基本使用

# coding:utf-8
import pymysql

#關(guān)于中文問題
#1. mysql命令行創(chuàng)建數(shù)據(jù)庫心铃,設(shè)置編碼為gbk:create databse demo2 character set utf8; 
#2. python代碼中連接時(shí)設(shè)置charset="gbk"
#3. 創(chuàng)建表格時(shí)設(shè)置default charset=utf8

#連接數(shù)據(jù)庫
#charset和mysql服務(wù)端設(shè)置格式一樣(還可設(shè)置為gbk, gb2312)
conn = pymysql.connect(host="localhost", user="root", passwd="", db='test', charset='utf8', port=3306)  

#創(chuàng)建游標(biāo)
cursor = conn.cursor()
try:
    #執(zhí)行sql語句
    cursor.execute("""create table if not exists t_sales(
                    id int primary key auto_increment not null,
                    nickName varchar(128) not null,
                    color varchar(128) not null,
                    size varchar(128) not null, 
                    comment text not null,
                    saledate varchar(128) not null)engine=InnoDB default charset=utf8;""")
                    
    # cursor.execute("""insert into t_sales(nickName,color,size,comment,saledate) 
                    # values('%s','%s','%s','%s','%s');""" % ("zack", "黑色", "L", "大小合適", "2019-04-20"))
                    
    cursor.execute("""insert into t_sales(nickName,color,size,comment,saledate) 
                    values(%s,%s,%s,%s,%s);""" , ("zack", "黑色", "L", "大小合適", "2019-04-20"))
    #提交
    conn.commit()


    ### 插入數(shù)據(jù)
    insert_sql = "insert into t_sales(nickName,color,size,comment,saledate) values(%s,%s,%s,%s,%s);"
    #返回受影響的行數(shù)
    row1 = cursor.execute(insert_sql,("Bob", "黑色", "XL", "便宜實(shí)惠", "2019-04-20"))

    update_sql = "update t_sales set color='白色' where id=%s;"
    #返回受影響的行數(shù)
    row2 = cursor.execute(update_sql,(1,))

    select_sql = "select * from t_sales where id>%s;"
    #返回受影響的行數(shù)
    row3 = cursor.execute(select_sql,(1,))

    delete_sql = "delete from t_sales where id=%s;"
    #返回受影響的行數(shù)
    row4 = cursor.execute(delete_sql,(4,))

    #提交准谚,不然無法保存新建或者修改的數(shù)據(jù)(增刪改得提交)
    conn.commit()


    ### 批量插入
    insert_sql = "insert into t_sales(nickName,color,size,comment,saledate) values(%s,%s,%s,%s,%s);"
    data = [("Bob", "黑色", "XL", "便宜實(shí)惠", "2019-04-20"),("Ted", "黃色", "M", "便宜實(shí)惠", "2019-04-20"),("Gary", "黑色", "M", "穿著舒服", "2019-04-20")]
    row1 = cursor.executemany(insert_sql, data)
    conn.commit()

    ## 查詢數(shù)據(jù)
   
    select_sql = "select id,nickname,size from t_sales where id>%s;"
    cursor.execute(select_sql, (3,))

    row1 = cursor.fetchone()      #獲取第一條數(shù)據(jù),獲取后游標(biāo)會(huì)向下移動(dòng)一行
    row_n = cursor.fetchmany(3)  #獲取前n條數(shù)據(jù)去扣,獲取后游標(biāo)會(huì)向下移動(dòng)n行
    row_all = cursor.fetchall()  #獲取所有數(shù)據(jù)柱衔,獲取后游標(biāo)會(huì)向下移動(dòng)到末尾
    print(row1)
    print(row_n)
    print(row_all)
    # fetch獲取的數(shù)據(jù)默認(rèn)為元組格式,還可以獲取字典類型的愉棱,需要修改cursor如下如下:
    # cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

#conn.commit()
except BaseException as e:
    print(e)
finally:
    #關(guān)閉游標(biāo)
    cursor.close()
    #關(guān)閉連接
    conn.close()

注意execute執(zhí)行sql語句參數(shù)的兩種情況:

execute("insert into t_sales(nickName, size)  values('%s','%s');" % ("zack","L") )   
#此時(shí)的%s為字符竄拼接占位符唆铐,需要引號(hào)加'%s' (有sql注入風(fēng)險(xiǎn))

execute("insert into t_sales(nickName, size)  values(%s,%s);" , ("zack","L")) 
#此時(shí)的%s為sql語句占位符,不需要引號(hào)%s

多線程操控pymysql - 加鎖

對(duì)于pymysql模塊奔滑,通過多線程操控?cái)?shù)據(jù)庫容易出錯(cuò)艾岂,得加鎖串行執(zhí)行。進(jìn)行并發(fā)時(shí)朋其,可以利用DBUtils模塊來維護(hù)數(shù)據(jù)庫連接池王浴。

import pymysql
import threadind

#**************************無連接池*******************************    
# 每個(gè)線程都要?jiǎng)?chuàng)立一次連接,線程并發(fā)操作間可能有問題梅猿?
def func():
    conn = pymysql.connect(host="127.0.0.1",port=3306,db="test",user="root",passwd="",charset="utf8")
    cursor = conn.cursor()
    cursor.execute("select * from user where nid>1;")
    result = cursor.fetchone()
    print(result)
    cursor.close()
    conn.close()
    
if __name__=="__main__":
    for i in range(5):
        t = threading.Thread(target=func,name="thread-%s"%i)
        t.start()
#**************************無連接池*******************************
#創(chuàng)建一個(gè)連接氓辣,加鎖串行執(zhí)行
from threading import Lock
import pymysql
import threading
conn = pymysql.connect(host="127.0.0.1",port=3306,db="test",user="root",passwd="",charset="utf8")    


lock = Lock()    
def func():
    with lock:
        cursor = conn.cursor()
        cursor.execute("select * from user where nid>1;")
        result = cursor.fetchone()
        print(result)
        cursor.close()
        
        #conn.close()不能在線程中關(guān)閉連接,否則其他線程不可用了
        
if __name__=="__main__":
    threads = []
    for i in range(5):
        t = threading.Thread(target=func,name="thread-%s"%i)
        threads.append(t)
        t.start()
        
    for t in threads:
        t.join()
    
    conn.close()

多線程操作 - DBUtils連接池

DBUtils連接池有兩種連接模式:PersistentDB和PooledDB (官網(wǎng)文檔:https://cito.github.io/DBUtils/UsersGuide.html

模式一(DBUtils.PersistentDB):為每個(gè)線程創(chuàng)建一個(gè)連接袱蚓,線程即使調(diào)用了close方法钞啸,也不會(huì)關(guān)閉,只是把連接重新放到連接池喇潘,供自己線程再次使用体斩。當(dāng)線程終止時(shí),連接自動(dòng)關(guān)閉响蓉。

PersistentDB使用代碼如下:

#coding:utf-8

from DBUtils.PersistentDB import PersistentDB
import pymysql
import threading

pool = PersistentDB(
    creator = pymysql,  # 使用鏈接數(shù)據(jù)庫的模塊
    maxusage = None,    # 一個(gè)鏈接最多被重復(fù)使用的次數(shù)硕勿,None表示無限制
    setsession=[],     # 開始會(huì)話前執(zhí)行的命令列表。如:["set datestyle to ...", "set time zone ..."]
    ping = 0,           # ping MySQL服務(wù)端枫甲,檢查是否服務(wù)可用源武。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
    closeable = False,    # 如果為False時(shí)扼褪, conn.close() 實(shí)際上被忽略,供下次使用粱栖,再線程關(guān)閉時(shí)话浇,才會(huì)自動(dòng)關(guān)閉鏈接。如果為True時(shí)闹究, conn.close()則關(guān)閉鏈接幔崖,那么再次調(diào)用pool.connection時(shí)就會(huì)報(bào)錯(cuò),因?yàn)橐呀?jīng)真的關(guān)閉了連接(pool.steady_connection()可以獲取一個(gè)新的鏈接)
    threadlocal = None,    # 本線程獨(dú)享值得對(duì)象渣淤,用于保存鏈接對(duì)象赏寇,如果鏈接對(duì)象被重置
    host="127.0.0.1",
    port = 3306,
    user = "root",
    password="",
    database="test",
    charset = "utf8"
)

def func():
    conn = pool.connection()
    cursor = conn.cursor()
    cursor.execute("select * from user where nid>1;")
    result = cursor.fetchone()
    print(result)
    cursor.close()
    conn.close()
    
if __name__ == "__main__":
    for i in range(5):
        t = threading.Thread(target=func,name="thread-%s"%i)
        t.start()

模式二(DBUtils.PooledDB):創(chuàng)建一批連接到連接池,供所有線程共享使用价认。

(由于pymysql嗅定、MySQLdb等threadsafety值為1,所以該模式連接池中的線程會(huì)被所有線程共享用踩。)

PooledDB使用代碼如下:

from DBUtils.PooledDB import PooledDB
import pymysql
import threading
import time

pool = PooledDB(
    creator = pymysql,  # 使用鏈接數(shù)據(jù)庫的模塊
    maxconnections = 6,  # 連接池允許的最大連接數(shù)渠退,0和None表示不限制連接數(shù)
    mincached = 2,   # 初始化時(shí),鏈接池中至少創(chuàng)建的空閑的鏈接脐彩,0表示不創(chuàng)建
    maxcached = 5,   # 鏈接池中最多閑置的鏈接碎乃,0和None不限制
    maxshared = 3,   # 鏈接池中最多共享的鏈接數(shù)量,0和None表示全部共享惠奸。PS: 無用梅誓,因?yàn)閜ymysql和MySQLdb等模塊的 threadsafety都為1,所有值無論設(shè)置為多少晨川,_maxcached永遠(yuǎn)為0证九,所以永遠(yuǎn)是所有鏈接都共享。
    blocking = True,  # 連接池中如果沒有可用連接后共虑,是否阻塞等待愧怜。True,等待妈拌;False拥坛,不等待然后報(bào)錯(cuò)
    maxusage = None,   # 一個(gè)鏈接最多被重復(fù)使用的次數(shù),None表示無限制
    setsession = [],   # 開始會(huì)話前執(zhí)行的命令列表尘分。如:["set datestyle to ...", "set time zone ..."]
    ping = 0,           # ping MySQL服務(wù)端猜惋,檢查是否服務(wù)可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
    host="127.0.0.1",
    port = 3306,
    user="root",
    password="",
    database = "test",
    charset = "utf8"
)

def func():
    conn = pool.connection()
    cursor = conn.cursor()
    cursor.execute("select * from user where nid>1;")
    result = cursor.fetchone()
    print(result)
    time.sleep(5)  #為了查看mysql端的線程數(shù)量
    cursor.close()
    conn.close()
    
if __name__=="__main__":
    for i in range(5):
        t = threading.Thread(target=func,name="thread-%s"%i)
        t.start()

MongoDB

暫時(shí)不學(xué)

Redis

暫時(shí)不學(xué)

ORM

暫時(shí)不學(xué)

  • sqlalchemy
  • async-sqlalchemy
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末培愁,一起剝皮案震驚了整個(gè)濱河市著摔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌定续,老刑警劉巖谍咆,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件禾锤,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡摹察,警方通過查閱死者的電腦和手機(jī)恩掷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來供嚎,“玉大人黄娘,你說我怎么就攤上這事】说危” “怎么了逼争?”我有些...
    開封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)劝赔。 經(jīng)常有香客問我氮凝,道長(zhǎng),這世上最難降的妖魔是什么望忆? 我笑而不...
    開封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮竿秆,結(jié)果婚禮上启摄,老公的妹妹穿的比我還像新娘。我一直安慰自己幽钢,他們只是感情好歉备,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著匪燕,像睡著了一般蕾羊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上帽驯,一...
    開封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天龟再,我揣著相機(jī)與錄音,去河邊找鬼尼变。 笑死利凑,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的嫌术。 我是一名探鬼主播哀澈,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼度气!你這毒婦竟也來了割按?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤磷籍,失蹤者是張志新(化名)和其女友劉穎适荣,沒想到半個(gè)月后现柠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡束凑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年晒旅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汪诉。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡废恋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出扒寄,到底是詐尸還是另有隱情鱼鼓,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布该编,位于F島的核電站迄本,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏课竣。R本人自食惡果不足惜嘉赎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望于樟。 院中可真熱鬧公条,春花似錦、人聲如沸迂曲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽路捧。三九已至关霸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間杰扫,已是汗流浹背队寇。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留涉波,地道東北人英上。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像啤覆,于是被迫代替她去往敵國(guó)和親苍日。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

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