書籍介紹-深入淺出Python(第二版)-part2

Flask:

  • 小型web架構, 不適用於正式環境
py -3 -m pip install flask
  • __name__, 前後2個__的變數, 慣稱為dunder name, 即double underscore的意思
  • _var, 簡稱為wonder, 即one underscore的意思
  • dunder name dunder main。直接以python執行程式檔與透過import 模組來使用, 其__name__會是不同的:
    • 直接用python執行時, __name__會指定為’_main__’
    • 若程式是被import後使用的, 則__name__會指定為import的模組名稱
if __name__ == '__main__':
    app.run()

DB-API:

pip install pyodbc 
  • 連線資訊可以用字典型態將資料傳入
dbconfig={'SERVER':'serverhost',
    'UID':'useid',
    'PWD':'uidpasswd',
    'DATABASE':'yourDB',
    'DRIVER':'{ODBC Driver 18 for SQL Server}'}
#字典的key與連線字串的屬性一致, 即可以下面方式將字典物件直接傳入
conn=pyodbc.connect(**dbconfig)
cu=conn.cursor()
cu.execute("Select * from something .......")
row=cu.fetchone()
while row:
    print(row[0])
    row=cu.fetchone()
  • 書中範例用MySQL, .execute可傳2個引數, SQL指令可以用佔位符%s, 所以要用tuple來包含所有對應佔位符的參數
  • 但我用pyodbc時, 這個卻試不出書中寫的方式, 反而.execute可用不受限的引數, 而佔位符不能用%s, 反而可用?
  • 另外, 書中寫到可取user_agent.browser, 但我實測時browser總是None, 無法取得單獨browser種類, 只能用user_agent.string取得整個user_agent字串
    _SQL = """
        Insert Into log (phrase,letters,ip,browser_string,results)
        values (?,?,?,?,?)    """
    cu.execute(_SQL, req.form['phrase'], req.form['letters'],
               req.remote_addr, req.user_agent.string, res,)

類別:

  • class中的def, 都要自帶一個必要引數self, 且是第一個。self就代表物件本身的別名
  • 物件自帶的dunder name __func__方法, 就是可以做覆寫的函式(一樣也都有自帶self引數)
  • 當叫用物件但未指明方法, 預設等於是叫用物件的__repr__方法來回傳物件16進制記憶體位址
>>> i=CountFromBy(1,10)
>>> i    
<countfromby.CountFromBy object at 0x000001A70EABEBF0>
>>> type(i)
<class 'countfromby.CountFromBy'>
>>> id(i)
1817017314288
>>> hex(id(i))
'0x1a70eabebf0'
  • 環境管理器: 使用with來管理資源使用, 會應用到的dunder name: __init__、 __enter__及__exit__
    • 先由__init__開始
    • 進入with … as ..則會執行__enter__
    • 結束時會執行__exit__

函式: (再談)

  • 函式也是物件, 函式可以當作引數傳遞給另一個函式
def dowork():
    pass

def apply(func: object) -> object:
    return func()

id(dowork) #把dowork()函式傳給id()函式, 此處id()沒執行dowork()
apply(dowork) #把dowork()函式傳給apply()函式, 此處apply()執行了dowork()
  • 引數的變化
    • *args, 可接受任意數量的引數, 例如print定義中的*values
    • **kwargs, 可接受任意數量、順序的鍵/值對引數。
    • (*args, **kwargs), 代表接受任何型式的引數
def work1(*args):
    for i in args:
        print(i)

def work2(**kwargs):
    for k,v in kwargs.items():
        print(k, v, sep='->')

#以下皆可正確執行
work1()
work1(1)
work1(2,4,'a','Z',['x'])
work2()
work2(a=1)
work2(b=1,c=2,d=4,e='hello')
d={'a':10,'b':20,'d':40,'c':30}
work2(**d)
  • @修飾器, 就是函式。
    • 可達到以函式為引數(page1)呼叫函式(do_deco), 回傳函式物件(wrapper)的應用效果
    • page1函式專注在其自身邏輯, 不用做額外邏輯; 但page1仍會受到do_deco函式的控制
from functools import wraps

def to_deco(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
            return func(*args, **kwargs)
        return 'others .... '
    return wrapper

@app.route('/')
@to_deco
def page1() -> str:  #<- 等於呼叫do_deco(page1)
    return 'This is page 1.'

迴圈優化:

  • conprehension, 將for迴圈寫法改成單行語法, 不但寫法簡化, conprehension也有效能優化
  • 可用於set,list,dict, 但沒有tuple
  • 還可以加上篩選過濾
origList = ['AVD', 'UCJ', 'ERIM','abhy']
finalList = []
for dt in origList:
    if dt.title().startswith('A'):
        finalList.append(dt.title())

#conprehension寫法, 單行語法取代以上2~5行寫法
newList = [dt.title()
           for dt in origList
           if dt.title().startswith('A')]

print(finalList) #['Avd', 'Abhy']
print(newList) #['Avd', 'Abhy']->一樣的結果
origDict = {'a': 12, 'c': 100, 'd': 999}
finalDict = {}
for k, v in origDict.items():
    finalDict[k] = v*10

newDict = {k: v*10
           for k, v in origDict.items()}

print(finalDict) #{'a': 120, 'c': 1000, 'd': 9990}
print(newDict) #{'a': 120, 'c': 1000, 'd': 9990}
  • 和以上同樣的樣式, 若改以(和)來刮起來, 看來像tuple的conprehension, 但其實是程式產生器
  • for迴圈中使用list,set,dict conprehension和程式產生器在產生結果的效果上有很大的不同
    • 前者, list,set,dict conprehension, 會在整個集合執行完成才會一次全部顯示結果。當集合很大時, 將會等待很久。改用函式加上yield回傳, 可解決此限制
    • 後者, 程式產生器, 會執行一次就顯示一次結果, 逐一呈現結果
# list,set,dict conprehension in for loop
for i in [x for x in listX]:
    #do.....

for i in {k:v for k,v in dictX.items()}:
    #do.....

#程式產生器
for i in (t for t in tupleX):
    #do.....
  • yield相當於return, 可如同return使用, 但可避免for迴圈中呼叫函式使用return導致結束上層for迴圈的問題
tp=('1234','5678','abcd')
def someFunc(para):
    for p in para:
        yield p[:1],p[-1:]   #這裡用return, 以下for loop會有錯誤

for a,b in someFunc(tp):
    print(a,b)

#1 4
#5 8
#a d

發表留言

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料