真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯網站制作重慶分公司

python同步函數 python調用異步函數

后端編程Python3-數據庫編程

對大多數軟件開發(fā)者而言,術語數據庫通常是指RDBMS(關系數據庫管理系統(tǒng)), 這些系統(tǒng)使用表格(類似于電子表格的網格),其中行表示記錄,列表示記錄的字段。表格及其中存放的數據是使用SQL (結構化査詢語言)編寫的語句來創(chuàng)建并操縱的。Python提供了用于操縱SQL數據庫的API(應用程序接口),通常與作為標準的SQLite 3數據庫一起發(fā)布。

成都創(chuàng)新互聯公司是一家專注于成都網站設計、網站制作與策劃設計,江津網站建設哪家好?成都創(chuàng)新互聯公司做網站,專注于網站建設十年,網設計領域的專業(yè)建站公司;建站業(yè)務涵蓋:江津等地區(qū)。江津做網站價格咨詢:13518219792

另一種數據庫是DBM (數據庫管理器),其中存放任意數量的鍵-值項。Python 的標準庫提供了幾種DBM的接口,包括某些特定于UNIX平臺的。DBM的工作方式 與Python中的字典類似,區(qū)別在于DBM通常存放于磁盤上而不是內存中,并且其鍵與值總是bytes對象,并可能受到長度限制。本章第一節(jié)中講解的shelve模塊提供了方便的DBM接口,允許我們使用字符串作為鍵,使用任意(picklable)對象作為值。

如果可用的 DBM 與 SQLite 數據庫不夠充分,Python Package Index, pypi.python.org/pypi中提供了大量數據庫相關的包,包括bsddb DBM ("Berkeley DB"),對象-關系映射器,比如SQLAlchemy (),以及流行的客戶端/服務器數據的接口,比如 DB2、Informix、Ingres、MySQL、ODBC 以及 PostgreSQL。

本章中,我們將實現某程序的兩個版本,該程序用于維護一個DVD列表,并追蹤每個DVD的標題、發(fā)行年份、時間長度以及發(fā)行者。該程序的第一版使用DBM (通過shelve模塊)存放其數據,第二版則使用SQLite數據庫。兩個程序都可以加載與保存簡單的XML格式,這使得從某個程序導出DVD數據并將其導入到其他程序成為可能。與DBM版相比,基于SQL的程序提供了更多一些的功能,并且其數據設計也稍干凈一些。

12.1 DBM數據庫

shelve模塊為DBM提供了一個wrapper,借助于此,我們在與DBM交互時,可以將其看做一個字典,這里是假定我們只使用字符串鍵與picklable值,實際處理時, shelve模塊會將鍵與值轉換為bytes對象(或者反過來)。

由于shelve模塊使用的是底層的DBM,因此,如果其他計算機上沒有同樣的DBM,那么在某臺計算機上保存的DBM文件在其他機器上無法讀取是可能的。為解決這一問題,常見的解決方案是對那些必須在機器之間可傳輸的文件提供XML導入與導出功能,這也是我們在本節(jié)的DVD程序dvds-dbm.py中所做的。

對鍵,我們使用DVD的標題;對值,則使用元組,其中存放發(fā)行者、發(fā)行年份以及時間。借助于shelve模塊,我們不需要進行任何數據轉換,并可以把DBM對象當做一個字典進行處理。

程序在結構上類似于我們前面看到的那種菜單驅動型的程序,因此,這里主要展示的是與DBM程序設計相關的那部分。下面給出的是程序main()函數中的一部分, 忽略了其中菜單處理的部分代碼。

db = None

try:

db = shelve.open(filename, protocol=pickle.HIGHEST_PROTOCOL)

finally:

if db is not None:

db.dose()

這里我們已打開(如果不存在就創(chuàng)建)指定的DBM文件,以便于對其進行讀寫操作。每一項的值使用指定的pickle協議保存為一個pickle,現有的項可以被讀取, 即便是使用更底層的協議保存的,因為Python可以計算出用于讀取pickle的正確協議。最后,DBM被關閉——其作用是清除DBM的內部緩存,并確保磁盤文件可以反映出已作的任何改變,此外,文件也需要關閉。

該程序提供了用于添加、編輯、列出、移除、導入、導出DVD數據的相應選項。除添加外,我們將忽略大部分用戶接口代碼,同樣是因為已經在其他上下文中進行了展示。

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()

像程序菜單調用的所有函數一樣,這一函數也以DBM對象(db)作為其唯一參數。該函數的大部分工作都是獲取DVD的詳細資料,在倒數第二行,我們將鍵-值項存儲在DBM文件中,DVD的標題作為鍵,發(fā)行者、年份以及時間(由shelve模塊pickled在一起)作為值。

為與Python通常的一致性同步,DBM提供了與字典一樣的API,因此,除了 shelve.open() 函數(前面已展示)與shelve.Shelf.sync()方法(該方法用于清除shelve的內部緩存,并對磁盤上文件的數據與所做的改變進行同步——這里就是添加一個新項),我們不需要學習任何新語法。

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 的標題,因為標題用作鍵,值則用于存放其他相關數據。由于必要的功能在其他場合 (比如移除DVD)也需要使用,因此我們將其實現在一個單獨的find_dvd()函數中,稍后將査看該函數。如果找到了該DVD,我們就獲取用戶所做的改變,并使用現有值作為默認值,以便提高交互的速度。(對于這一函數,我們忽略了大部分用戶接口代碼, 因為其與添加DVD時幾乎是相同的。)最后,我們保存數據,就像添加時所做的一樣。如果標題未作改變,就重寫相關聯的值;如果標題已改變,就創(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ā)現某個DVD,我們需要用戶只輸入其標題的一個或頭幾個字符。在具備了標題的起始字符后,我們在DBM中迭代并創(chuàng)建一個匹配列表。如果只有一個匹配項,就返回該項;如果有幾個匹配項(但少于DISPLAY_LIMIT, 一個在程序中其他地方設置的整數),就以大小寫不敏感的順序展示所有這些匹配項,并為每一項設置一個編號,以便用戶可以只輸入編號就可以選擇某個標題。(Console.get_integer()函數可以接受0,即便最小值大于0,以便0可以用作一個刪除值。通過使用參數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()函數就是簡單的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文件,以及如何向其中添加項、編輯項、對其項進行迭代以及移除某個項。

遺憾的是,在我們的數據設計中存在一個瑕疵。發(fā)行者名稱是重復的,這很容易導致不一致性,比如,發(fā)行者Danny DeVito可能被輸入為"Danny De Vito",用于 一個電影;也可以輸入為“Danny deVito",用于另一個。為解決這一問題,可以使用兩個DBM文件,主DVD文件使用標題鍵與(年份,時間長度,發(fā)行者ID)值; 發(fā)行者文件使用發(fā)行者ID (整數)鍵與發(fā)行者名稱值。下一節(jié)展示的SQL數據庫 版程序將避免這一瑕疵,這是通過使用兩個表格實現的,一個用于DVD,另一個用于發(fā)行者。

12.2 SQL數據庫

大多數流行的SQL數據庫的接口在第三方模塊中是可用的,Python帶有sqlite3 模塊(以及SQLite 3數據庫),因此,在Python中,可以直接開始數據庫程序設計。SQLite是一個輕量級的SQL數據庫,缺少很多諸如PostgreSQL這種數據庫的功能, 但非常便于構造原型系統(tǒng),并且在很多情況下也是夠用的。

為使后臺數據庫之間的切換盡可能容易,PEP 249 (Python Database API Specification v2.0)提供了稱為DB-API 2.0的API規(guī)范。數據庫接口應該遵循這一規(guī)范,比如sqlite3模塊就遵循這一規(guī)范,但不是所有第三方模塊都遵循。API規(guī)范中指定了兩種主要的對象,即連接對象與游標對象。表12-1與表12-2中分別列出了這兩種對象必須支持的API。在sqlite3模塊中,除DB-API 2.0規(guī)范必需的之外,其連接對象與游標對象都提供了很多附加的屬性與方法。

DVD程序的SQL版本為dvds.sql.py,該程序將發(fā)行者與DVD數據分開存儲,以 避免重復,并提供一個新菜單,以供用戶列出發(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()函數會返回一個數據庫對象,并打開其指定的數據庫文件。如果該文件不存在,就創(chuàng)建一個空的數據庫文件。鑒于此,在調用sqlite3.connect()之前,我們要注意數據庫是否是準備從頭開始創(chuàng)建,如果是,就必須創(chuàng)建該程序要使用的表格。所有査詢都是通過一個數據庫游標完成的,可以從數據庫對象的cursor()方法獲取。

注意,兩個表格都是使用一個ID字段創(chuàng)建的,ID字段有一個AUTOINCREMENT 約束——這意味著SQLite會自動為ID字段賦予唯一性的數值,因此,在插入新記錄時,我們可以將這些字段留給SQLite處理。

SQLite支持有限的數據類型——實際上就是布爾型、數值型與字符串——但使用數據'‘適配器”可以對其進行擴展,或者是擴展到預定義的數據類型(比如那些用于日期與datetimes的類型),或者是用于表示任意數據類型的自定義類型。DVD程序并不需要這一功能,如果需要,sqlite3模塊的文檔提供了很多詳細解釋。我們使用的外部鍵語法可能與用于其他數據庫的語法不同,并且在任何情況下,只是記錄我們的意圖,因為SQLite不像很多其他數據庫那樣需要強制關系完整性,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()

這一函數的開始代碼與dvds-dbm.py程序中的對應函數一樣,但在完成數據的收集后,與原來的函數有很大的差別。用戶輸入的發(fā)行者可能在也可能不在directors表格中,因此,我們有一個get_and_set_director()函數,在數據庫中尚無某個發(fā)行者時, 該函數就將其插入到其中,無論哪種情況都返回就緒的發(fā)行者ID,以便在需要的時候插入到dvds表。在所有數據都可用后,我們執(zhí)行一條SQL INSERT語句。我們不需要指定記錄ID,因為SQLite會自動為我們提供。

在査詢中,我們使用問號(?)作為占位符,每個?都由包含SQL語句的字符串后面的序列中的值替代。命名的占位符也可以使用,后面在編輯記錄時我們將看到。盡管避免使用占位符(而只是簡單地使用嵌入到其中的數據來格式化SQL字符串)也是可能的,我們建議總是使用占位符,并將數據項正確編碼與轉義的工作留給數據庫模塊來完成。使用占位符的另一個好處是可以提高安全性,因為這可以防止任意的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)

這一函數返回給定發(fā)行者的ID,并在必要的時候插入新的發(fā)行者記錄。如果某個記錄被插入,我們首先嘗試使用get_director_id()函數取回其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()函數返回給定發(fā)行者的ID,如果數據庫中沒有指定的發(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記錄,我們必須首先找到用戶需要操縱的記錄。如果找到了某個記錄,我們就給用戶修改其標題的機會,之后取回該記錄的其他字段,以便將現有值作為默認值,將用戶的輸入工作最小化,用戶只需要按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ā)行者記錄),之后使用新數據對數據庫進行更新。我們采用了一種簡化的方法,對記錄的所有字段進行更新,而不僅僅是那些做了修改的字段。

在使用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)

這一函數的功能與dvdsdbm.py程序中的find_dvd()函數相同,并返回一個二元組 (DVD標題,DVD ID)或(None, None),具體依賴于是否找到了某個記錄。這里并不需要在所有數據上進行迭代,而是使用SQL通配符(%),因此只取回相關的記錄。

由于我們希望匹配的記錄數較小,因此我們一次性將其都取回到序列的序列中。如果有不止一個匹配的記錄,但數量上又少到可以顯示,我們就打印記錄,并將每條記錄附帶一個數字編號,以便用戶可以選擇需要的記錄,其方式與在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()函數返回)數量超過了顯示限制值,就將第2個元素添加到WHERE 分支,之后執(zhí)行該査詢,并在結果上進行迭代。每個記錄都是一個序列,其字段是與 SELECT査詢相匹配的。

def dvd_count(db):

cursor = db.cursor()

cursor.execute("SELECT COUNT(*) FROM dvds")

return cursor.fetchone()[0]

我們將這幾行代碼放置在一個單獨的函數中,因為我們在幾個不同的函數中都需要使用這幾行代碼。

我們忽略了 list_directors()函數的代碼,因為該函數在結構上與list_dvds()函數非常類似,只不過更簡單一些,因為本函數只列出一個字段(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()

在用戶需要刪除一個記錄時,將調用本函數,并且本函數與dvds-dbm.py程序中 相應的函數是非常類似的。

到此,我們完全查閱了 dvds-sql.py程序,并且了解了如何創(chuàng)建數據庫表格、選取 記錄、在選定的記錄上進行迭代以及插入、更新與刪除記錄。使用execute()方法,我們可以執(zhí)行底層數據庫所支持的任意SQL語句。

SQLite提供了比我們這里使用的多得多的功能,包括自動提交模式(以及任意其他類型的事務控制),以及創(chuàng)建可以在SQL查詢內執(zhí)行的函數的能力。提供一個工廠函數并用于控制對每個取回的記錄返回什么(比如,一個字典或自定義類型,而不是字段序列)也是可能的。此外,通過傳遞“:memory:”作為文件名,創(chuàng)建內存中的SQLite 數據庫也是可能的。

以上內容部分摘自視頻課程05后端編程Python22 數據庫編程,更多實操示例請參照視頻講解。跟著張員外講編程,學習更輕松,不花錢還能學習真本領。

python所有內置函數的定義詳解

1、定義函數

函數是可重用的程序。本書中已經使用了許多內建函數,如len()函數和range()函數,但是還沒自定義過函數。定義函數的語法格式如下:

def 函數名(參數):

函數體

定義函數的規(guī)則如下:

①關鍵字def用來定義一個函數,它是define的縮寫。

②函數名是函數的唯一標識,函數名的命名規(guī)則遵循標識符的命名規(guī)則。

③函數名后面一定要緊跟著一個括號,括號內的參數是可選的,括號后面要有冒號。

④函數體(statement)為一個或一組Python語句,注意要有縮進。

⑤函數體的第一行可以有文檔字符串,用于描述函數的功能,用三引號括起來。

按照定義規(guī)則,可以定義第一個函數了:

def?hello_world():

...?????print('Hello,world!')???#?注意函數體要有縮進

...

hello_world()

Hello,world!

這個函數不帶任何參數,它的功能是打印出“Hello,world!”。最后一行代碼hello_world()是調用函數,即讓Python執(zhí)行函數的代碼。

2、全局變量和局部變量

全局變量是定義在所有函數外的變量。例如,定義一個全局變量a,分別在函數test1()和test2()使用變量a:

a?=?100???#?全局變量

def?test1():

...?????print(a)

...

def?test2():

...?????print(a)

...

test1()

100

test2()

100

定義了全局變量a之后,在函數test1()和test2()內都可以使用變量a,由此可知,全局變量的作用范圍是全局。

局部變量是在函數內定義的變量,除了用關鍵字global修飾的變量以外。例如,在函數test1()內定義一個局部變量a,分別在函數外和另一個函數test2()內使用變量a:

def?test1():

...?????a?=?100???#?局部變量

...?????print(a)

...

def?test2():

...?????print(a)

...

test1()

100

print(a)

Traceback?(most?recent?call?last):

File?"stdin",?line?1,?in?module

NameError:?name?'a'?is?not?defined

test2()

Traceback?(most?recent?call?last):

File?"stdin",?line?1,?in?module

File?"stdin",?line?2,?in?test2

NameError:?name?'a'?is?not?defined

Python解釋器提示出錯了。由于局部變量a定義在函數test1()內,因此,在函數test1()內可以使用變量a,但是在函數外或者另一個函數test2()內使用變量a,都會報錯,由此可見,局部變量的作用范圍是定義它的函數內部。

一般情況下,在函數內聲明的變量都是局部變量,但是采用關鍵字global修飾的變量卻是全局變量:

def?test1():

...?????global?a???#?全局變量

...?????a?=?100

...?????print(a)

...

def?test2():

...?????print(a)

...

test1()

100

print(a)

100

test2()

100

這個程序與上個程序相比,只是在函數test1()中多了一行代碼“global a”,程序便可以正確運行了。在函數test1()中,采用關鍵字global修飾了變量a之后,變量a就變成了全局變量,不僅可以在該函數內使用,還可以在函數外或者其他函數內使用。

如果在某個函數內局部變量與全局變量同名,那么在該函數中局部變量會覆蓋全局變量:

a?=?100???#?全局變量

def?test1():

...?????a?=?200???#?同名局部變量

...?????print(a)

...

def?test2():

...?????print(a)

...

test1()

200

test2()

100

由于在函數test1()中定義了一個與全局變量同名的局部變量a,因此,在函數test1()中全局變量a的值被局部變量覆蓋了,但是在函數test2()中全局變量a的值沒有被覆蓋。

綜上所述,在Python中,全局變量保存的數據供整個腳本文件使用;而局部變量只用于臨時保存數據,變量僅供局部代碼塊使用。

Python 怎么為正在運行的程序傳值(或者控制其中函數的運行和停止)

進程間同步Python有asyncio標準庫,多進程有multiprocessing庫,如果是主機間通信需要使用網絡協議socket、http等庫。

可以參考Python文檔的

The Python Standard Library - 18. Interprocess

Communication and Networking -

18.5. asyncio – Asynchronous

I/O, event loop, coroutines and tasks

python有多少內置函數

Python內置函數有很多,為大家推薦5個神仙級的內置函數:

(1)Lambda函數

用于創(chuàng)建匿名函數,即沒有名稱的函數。它只是一個表達式,函數體比def簡單很多。當我們需要創(chuàng)建一個函數來執(zhí)行單個操作并且可以在一行中編寫時,就可以用到匿名函數了。

Lamdba的主體是一個表達式,而不是一個代碼塊。僅僅能在lambda表達式中封裝有限的邏輯進去。

利用Lamdba函數,往往可以將代碼簡化許多。

(2)Map函數

會將一個函數映射到一個輸入列表的所有元素上,比如我們先創(chuàng)建了一個函數來返回一個大寫的輸入單詞,然后將此函數應有到列表colors中的所有元素。

我們還可以使用匿名函數lamdba來配合map函數,這樣可以更加精簡。

(3)Reduce函數

當需要對一個列表進行一些計算并返回結果時,reduce()是個非常有用的函數。舉個例子,當需要計算一個整數列表所有元素的乘積時,即可使用reduce函數實現。

它與函數的最大的區(qū)別就是,reduce()里的映射函數(function)接收兩個參數,而map接收一個參數。

(4)enumerate函數

用于將一個可遍歷的數據對象(如列表、元組或字符串)組合為一個索引序列,同時列出數據和數據下標,一般用在for循環(huán)當中。

它的兩個參數,一個是序列、迭代器或其他支持迭代對象;另一個是下標起始位置,默認情況從0開始,也可以自定義計數器的起始編號。

(5)Zip函數

用于將可迭代的對象作為參數,將對象中對應的元素打包成一個個元組,然后返回由這些元組組成的列表

當我們使用zip()函數時,如果各個迭代器的元素個數不一致,則返回列表長度與最短的對象相同。

PYTHON多線程同步的幾種方法

Python進階(二十六)-多線程實現同步的四種方式

臨界資源即那些一次只能被一個線程訪問的資源,典型例子就是打印機,它一次只能被一個程序用來執(zhí)行打印功能,因為不能多個線程同時操作,而訪問這部分資源的代碼通常稱之為臨界區(qū)。

鎖機制

threading的Lock類,用該類的acquire函數進行加鎖,用realease函數進行解鎖

import threadingimport timeclass Num:

def __init__(self):

self.num = 0

self.lock = threading.Lock() def add(self):

self.lock.acquire()#加鎖,鎖住相應的資源

self.num += 1

num = self.num

self.lock.release()#解鎖,離開該資源

return num

n = Num()class jdThread(threading.Thread):

def __init__(self,item):

threading.Thread.__init__(self)

self.item = item def run(self):

time.sleep(2)

value = n.add()#將num加1,并輸出原來的數據和+1之后的數據

print(self.item,value)for item in range(5):

t = jdThread(item)

t.start()

t.join()#使線程一個一個執(zhí)行12345678910111213141516171819202122232425262728

當一個線程調用鎖的acquire()方法獲得鎖時,鎖就進入“l(fā)ocked”狀態(tài)。每次只有一個線程可以獲得鎖。如果此時另一個線程試圖獲得這個鎖,該線程就會變?yōu)椤癰locked”狀態(tài),稱為“同步阻塞”(參見多線程的基本概念)。

直到擁有鎖的線程調用鎖的release()方法釋放鎖之后,鎖進入“unlocked”狀態(tài)。線程調度程序從處于同步阻塞狀態(tài)的線程中選擇一個來獲得鎖,并使得該線程進入運行(running)狀態(tài)。

信號量

信號量也提供acquire方法和release方法,每當調用acquire方法的時候,如果內部計數器大于0,則將其減1,如果內部計數器等于0,則會阻塞該線程,知道有線程調用了release方法將內部計數器更新到大于1位置。

import threadingimport timeclass Num:

def __init__(self):

self.num = 0

self.sem = threading.Semaphore(value = 3) #允許最多三個線程同時訪問資源

def add(self):

self.sem.acquire()#內部計數器減1

self.num += 1

num = self.num

self.sem.release()#內部計數器加1

return num

n = Num()class jdThread(threading.Thread):

def __init__(self,item):

threading.Thread.__init__(self)

self.item = item def run(self):

time.sleep(2)

value = n.add()

print(self.item,value)for item in range(100):


本文題目:python同步函數 python調用異步函數
當前網址:http://weahome.cn/article/hgjcig.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部