天天看點

Day 5 - 編寫Web架構 要了解的問題多多

别人的了解

http://yeqianfeng.me/aiphttp-handler-of-comming-request/

自己的了解

<code>先看懂整體架構,再看詳細實作</code>

<code>1.coroweb</code><code>.py在client請求開始傳回func(</code><code>*</code><code>args, </code><code>*</code><code>*</code><code>kw),然後編寫func(</code><code>*</code><code>args,</code><code>*</code><code>*</code><code>kw)處理</code>

<code>#比如get('/index')(func(*args, **kw))</code>

<code>2.middlewares</code><code>=</code><code>[logger_factory, response_factory]</code>

<code>init_jinja2(app, filters</code><code>=</code><code>dict</code><code>(datetime</code><code>=</code><code>datetime_filter))</code>

<code>3.</code><code>先看懂add_routes(app, </code><code>'handlers'</code><code>),然後是add_static(app),最後await handler(request) </code>

<code>add_route(app, handles.create_comment) 變成</code>

<code># 自動把handler子產品的所有符合條件的函數注冊了:</code>

<code>add_routes(app, </code><code>'handlers'</code><code>)</code>

<code>add_routes,handler</code><code>-</code><code>&gt;是否有index,blog等屬性</code>

<code>/</code><code>/</code><code>不了解的 fn </code><code>=</code> <code>getattr</code><code>(mod, attr)</code>

<code>/</code><code>/</code><code>到了add_route,變成了app.router.add_route(method, path, RequestHandler(app, fn))</code>

<code>4.</code><code>最後的細節</code>

<code>func(</code><code>*</code><code>args, </code><code>*</code><code>*</code><code>kw)</code>

<code>if</code> <code>全部都會執行</code>

<code>5.middlewares</code> <code>攔截器</code>

<code>/</code><code>/</code><code>await handler(request)</code>

<code>06.30</code> <code>更新</code>

<code>上面一團亂糟糟的,重新梳理</code>

<code>1.coroweb</code><code>.py 主要是app.router.add_route(method, path, RequestHandler(app, fn))</code>

<code>了解為url和對應的函數綁定</code>

<code>2.add_route</code><code>(app,fn) fn變成協程</code>

<code>3.</code><code>然後handlers.py寫具體實作方法,比如index()</code>

<code>請求一過來,先找到add_route對應的函數,因為app.py已經批量綁定了handlers.py中方法到url上(模糊比對,類似的感覺,通用)</code>

<code>找到對應的函數,執行handlers中的函數,執行的過程調用coroweb.py中的get和post偏函數,就是裝飾器</code>

<code>4.</code><code>再添加一些攔截器</code>

<code>app </code><code>=</code> <code>web.Application(loop</code><code>=</code><code>loop, middlewares</code><code>=</code><code>[logger_factory, response_factory])</code>

<code>其中</code><code>return</code> <code>(await  handler(request)),handler(request)應該是在架構裡面寫好了。</code>

<code>5.handlers</code><code>.py就是寫全部邏輯的地方。</code>

代碼位址

https://github.com/michaelliao/awesome-python3-webapp/blob/day-05/www/coroweb.py

http://blog.csdn.net/qq_38801354/article/details/73008111

然後要搞清楚一下這些東西,多

<code>文檔</code>

<code>http:</code><code>/</code><code>/</code><code>aiohttp.readthedocs.io</code><code>/</code><code>en</code><code>/</code><code>stable</code><code>/</code><code>web.html</code>

<code>參數定義的順序必須是:必選參數、預設參數、可變參數、命名關鍵字參數和關鍵字參數。</code>

<code>去熟悉這些寫法</code>

<code>資料集合并</code>

<code>http:</code><code>/</code><code>/</code><code>pandas.pydata.org</code><code>/</code><code>pandas</code><code>-</code><code>docs</code><code>/</code><code>stable</code><code>/</code><code>merging.html</code>

<code>from</code> <code>jinja2 </code><code>import</code> <code>Environment</code>

<code>python inspect子產品解析 </code><code>-</code> <code>郭猛的個人空間</code>

<code>Python 的内置函數</code><code>__import__</code>

<code>inspect.signature</code>

<code>https:</code><code>/</code><code>/</code><code>docs.python.org</code><code>/</code><code>3</code><code>/</code><code>library</code><code>/</code><code>inspect.html</code>

<code>為啥程序池封裝在裝飾器中不能生效,而多程序可以?</code>

<code>http:</code><code>/</code><code>/</code><code>pythontutor.com</code><code>/</code><code>visualize.html</code><code>#mode=edit</code>

<code>1000</code><code>+</code><code>w 的資料去重也可以用 bloom </code><code>filter</code> <code>啊,就用 Redis 的 bitmap 存 bit 數組就可以了。</code>

<code>aiomysql.DictCursor會将結果傳回為字典</code>

<code>__all__</code><code>=</code><code>[</code><code>"echo"</code><code>,</code><code>"surround"</code><code>,</code><code>"reverse"</code><code>]。</code>

<code>這就意味着當</code><code>from</code> <code>sound.effects </code><code>import</code> <code>*</code><code>語句執行時,會導入那三個子產品</code>

<code>相當詳細的解釋</code>

<code>https:</code><code>/</code><code>/</code><code>github.com</code><code>/</code><code>icemilk00</code><code>/</code><code>Python_L_Webapp</code><code>/</code><code>blob</code><code>/</code><code>master</code><code>/</code><code>www</code><code>/</code><code>app.py</code>

<code>https:</code><code>/</code><code>/</code><code>github.com</code><code>/</code><code>icemilk00</code><code>/</code><code>Python_L_Webapp</code>

<code>https:</code><code>/</code><code>/</code><code>www.v2ex.com</code><code>/</code><code>t</code><code>/</code><code>347788</code>

<code>https:</code><code>/</code><code>/</code><code>www.v2ex.com</code><code>/</code><code>t</code><code>/</code><code>347421</code>

<code>還要不斷的去翻python3的原始文檔,看asyncio,httpio的說明和源代碼,最終還是明白了</code>

<code>優先看</code>

<code>https:</code><code>/</code><code>/</code><code>github.com</code><code>/</code><code>moling3650</code><code>/</code><code>mblog</code><code>/</code><code>blob</code><code>/</code><code>master</code><code>/</code><code>www</code><code>/</code><code>app</code><code>/</code><code>frame</code><code>/</code><code>__init__.py</code>

<code>http:</code><code>/</code><code>/</code><code>blog.csdn.net</code><code>/</code><code>qq_38801354</code><code>/</code><code>article</code><code>/</code><code>details</code><code>/</code><code>73008111</code>

<code>https:</code><code>/</code><code>/</code><code>segmentfault.com</code><code>/</code><code>a</code><code>/</code><code>1190000008400059</code>

<code>http:</code><code>/</code><code>/</code><code>www.w2bc.com</code><code>/</code><code>article</code><code>/</code><code>218471</code>

<code>https:</code><code>/</code><code>/</code><code>zhuanlan.zhihu.com</code><code>/</code><code>p</code><code>/</code><code>22494483</code>

<code>http:</code><code>/</code><code>/</code><code>lovenight.github.io</code><code>/</code><code>2016</code><code>/</code><code>09</code><code>/</code><code>25</code><code>/</code><code>Python</code><code>-</code><code>3</code><code>-</code><code>%</code><code>E5</code><code>%</code><code>AD</code><code>%</code><code>A6</code><code>%</code><code>E4</code><code>%</code><code>B9</code><code>%</code><code>A0</code><code>%</code><code>E7</code><code>%</code><code>AC</code><code>%</code><code>94</code><code>%</code><code>E8</code><code>%</code><code>AE</code><code>%</code><code>B0</code><code>/</code>

<code>http:</code><code>/</code><code>/</code><code>blog.csdn.net</code><code>/</code><code>yueguanghaidao</code><code>/</code><code>article</code><code>/</code><code>details</code><code>/</code><code>11708417</code>

<code>def</code> <code>init_jinja2(app, </code><code>*</code><code>*</code><code>kw):</code>

<code>    </code><code>logging.info(</code><code>'init jinja2...'</code><code>)</code>

<code>    </code><code>options </code><code>=</code> <code>dict</code><code>(</code>

<code>        </code><code>autoescape </code><code>=</code> <code>kw.get(</code><code>'autoescape'</code><code>, </code><code>True</code><code>),</code>

<code>        </code><code>block_start_string </code><code>=</code> <code>kw.get(</code><code>'block_start_string'</code><code>, </code><code>'{%'</code><code>),</code>

<code>        </code><code>block_end_string </code><code>=</code> <code>kw.get(</code><code>'block_end_string'</code><code>, </code><code>'%}'</code><code>),</code>

<code>        </code><code>variable_start_string </code><code>=</code> <code>kw.get(</code><code>'variable_start_string'</code><code>, </code><code>'{{'</code><code>),</code>

<code>        </code><code>variable_end_string </code><code>=</code> <code>kw.get(</code><code>'variable_end_string'</code><code>, </code><code>'}}'</code><code>),</code>

<code>        </code><code>auto_reload </code><code>=</code> <code>kw.get(</code><code>'auto_reload'</code><code>, </code><code>True</code><code>)</code>

<code>    </code><code>)</code>

<code>    </code><code>path </code><code>=</code> <code>kw.get(</code><code>'path'</code><code>, </code><code>None</code><code>)</code>

<code>    </code><code>if</code> <code>path </code><code>is</code> <code>None</code><code>:</code>

<code>        </code><code>path </code><code>=</code> <code>os.path.join(os.path.dirname(os.path.abspath(__file__)), </code><code>'templates'</code><code>)</code>

<code>    </code><code>logging.info(</code><code>'set jinja2 template path: %s'</code> <code>%</code> <code>path)</code>

<code>    </code><code>env </code><code>=</code> <code>Environment(loader</code><code>=</code><code>FileSystemLoader(path), </code><code>*</code><code>*</code><code>options)</code>

<code>    </code><code>filters </code><code>=</code> <code>kw.get(</code><code>'filters'</code><code>, </code><code>None</code><code>)</code>

<code>    </code><code>if</code> <code>filters </code><code>is</code> <code>not</code> <code>None</code><code>:</code>

<code>        </code><code>for</code> <code>name, f </code><code>in</code> <code>filters.items():</code>

<code>            </code><code>env.filters[name] </code><code>=</code> <code>f</code>

<code>    </code><code>app[</code><code>'__templating__'</code><code>] </code><code>=</code> <code>env</code>

<code>env上添加屬性datetime_filter,變成了方法</code>

最後看能不能看懂别人的問題和回複

問題

看到好多函數都有request做參數,但這個request是什麼時候傳進去的呢,沒看到從哪裡得到request的,新手求輕噴

哥們,你源碼裡的所有url處理函數的參數都是來源于request。可我查詢了aiohttp,發現request是一個對象,好像沒有那些屬性呀。aiohttp。迷惑中,盼回。

RequestHandler

我遇到的第二個難點就是RequestHandler,因為RequestHandler看起來是一個類,但又不是一個類,從本質上來說,它是一個函數,那問題來了,這個函數的作用到底是什麼呢?

如果大家有仔細看day2的hello world的例子的話,就會發現在那個index函數裡是包含了一個request參數的,但我們新定義的很多函數中,request參數都是可以被省略掉的,那是因為新定義的函數最終都是被RequestHandler處理,自動加上一個request參數,進而符合app.router.add_route第三個參數的要求,是以說RequestHandler起到統一标準化接口的作用。

接口是統一了,但每個函數要求的參數都是不一樣的,那又要如何解決呢?得益于factory的理念,我們很容易找一種解決方案,就如同response_factory一樣把任何類型的傳回值最後都統一封裝成一個web.Response對象。RequestHandler也可以把任何參數都變成self._func(**kw)的形式。那問題來了,那kw的參數到底要去哪裡去擷取呢?

request.match_info的參數: match_info主要是儲存像@get('/blog/{id}')裡面的id,就是路由路徑裡的參數

GET的參數: 像例如/?page=2

POST的參數: api的json或者是網頁中from

request參數: 有時需要驗證使用者資訊就需要擷取request裡面的資料

說到這裡應該很清楚了吧,RequestHandler的主要作用就是構成标準的app.router.add_route第三個參數,還有就是擷取不同的函數的對應的參數,就這兩個主要作用。隻要你實作了這個作用基本上是随你怎麼寫都行的,當然最好加上參數驗證的功能,否則出錯了卻找不到出錯的消息是一件很頭痛的是事情。在這個難點的我沒少參考同學的注釋,但覺得還是把這部分的代碼太過複雜化了,是以我用自己的方式重寫了RequestHandler,從老師的先檢驗再擷取轉換成先擷取再統一驗證,從邏輯上應該是沒有問題,但大幅度簡化了程式。

你可以參考我的data_factory的實作。

如果method == 'GET'時,參數就是查詢字元串,也就是request.query_string

如果method == 'POST'時,有兩種可能,Ajax的json和html的form(表單),分别對應request.json()和request.post()。 data_factory的主要作用就是把這些參數統一綁定在request.__data__上。

在RequestHandler裡,init是初始化用的,在生成執行個體的時候執行,而call是模拟()的調用,需要在執行個體上應用,在下面這句代碼裡:

  app.router.add_route(method, path, RequestHandler(func))

  RequestHandler這個類并沒有建立執行個體,是不是意味着call并沒有執行,在我的代碼裡貌似是這樣的。

  小白一隻,卡在這裡好幾天了,希望能解決我的疑惑。。。

你了解錯了,RequestHandler(func)就是一個執行個體,隻不過沒有給它命名,最終會在factorys的response_factory調用。

r = await handler(request)

這裡的request也就是__call__(request)的參數。

你說的意思是 r = await handler(request) 裡的handler就代表RequestHandler(func),這樣call就被執行了,可是我還是不太明白handler怎麼跟RequestHandler(func)聯系起來的

response_factory的r = await handler(request)實際上是調用r = await RequestHandler(request),然後内部又調用了await self._func(**kw),這裡才是調用我們自己定義的函數比如await hello(**kw),最後把函數處理後的資料傳回到response_factory,response_factory根據hello(**kw)的傳回值封裝成一個響應對象發送給浏覽器。

app.router.add_route隻不過是一個注冊器,把我們寫的某的函數和URL綁定,形成一個映射關系而已

不賴@流留66 ,我也糊塗了。

難道r = await handler(request)不是調用r = await RequestHandler(app,fn)(request)的意思嗎?

@灰_手 你手滑了?

pymysql.err.InternalError: (1054, "Unknown column 'password' in 'field list'")

我的git的ORM測試,不過要将# 測試count rows語句下面兩句注釋,我重寫了findNum方法了。

day06,day07是水課,後邊除了還有個day13 watchdog , day15 fabric之外都是體力活

day12 日志清單分頁,如果之前沒有做過分頁,這一天的課程也很有趣

前端确實是個大坑,前端屆太鬧騰.今天這個架構火了,明天那個庫黃了.

要學的東西又多又雜,看得我兩股戰戰,幾欲先走.

最基本的老三樣還是得掌握的:

html掌握常用标簽,會簡單布個局.

css 掌握選擇符和浮動清除的概念就能畢業,日常使用查手冊就差不多了.

css這東西掌握了沒卵用,我用起來和别人用起來是兩回事,沒有美感做出東西來照樣醜.

像UIKit,bootstrap這些UI包真的是業界良心,一下子把沒有美感不懂設計的人們救活了.

原生javascript,它的很多概念我學過又忘記了.

隻剩下document.getElementById,XMLHttpRequest,setInterval是我的三寶.

有了這三樣,DOM,ajax,動畫我都能捅咕一下.

以前javascript對象的繼承方式有很多種,我一樣也記不住.

prototype引用來引用去的根本鬧不清什麼狀況.

廖大的教程講ES6,我要學一下.

學習資料

石川(blue) 2012年錄制的一套javascript教程32集.

第1集 初探javascript魅力

http://v.youku.com/v_show/id_XNDU1MjMxNTQ0.html

我學習實戰的時候day04,day05卡了一個星期.

前端的部分我是直接抄廖大的代碼.我對廖大實作的ORM特别感興趣.

day04,day05以後我就判定自己畢業了,部落格的其他功能我根本沒完成.

我現在複習了一遍整個教程,目前看到sqlalchemy部分,快到實戰填坑了,假如在實戰部分我學習起前端來,大概就繞不回來了.到時候咱們就隻好在node.js教程裡見了.

前端是大坑!

html,css,js的耦合度太高了,随便一個改動也是非常困難的,比如你想把vue.js從0.12版更新到1.02版,就會發現在文法有N多不相容的地方,不但要改js,就連html也要改,如果你想把uikit換成bootstrap的話,你會發現html要改,javascipt也是要改的,css是改成最少的地,前提是你不用它,隻要換了ui架構,命名問題必要存在,除非你自己在js把id和class寫成可變的... 總之就是牽一發而動全身。

有問題多找文檔,沒有精力學就是複制廖大的代碼好了。

 UK中文網,雖然容易看懂,但也有些deom不适用了。能看英文最好看英文的

Vue.js中文官網,這裡的文檔還是挺好的,易實作,效果好。

import(module_name, fromlist=['get_submodule'])裡的get_submodule是什麼意思?

在其他代碼裡也沒發現get_submodule子產品

get submodule沒有任何意思。這裡是個黑魔法。當fromlist不為空時,__import__可以直接導入子子產品

user.id 是users表中每一行記錄業務無關的唯一辨別.

它的值由定義在models.py中的next_id()生成.

@post('/api/authenticate') #登入鑒定

sha1.update(user.id.encode('utf-8'))

sha1.update(b':')

sha1.update(passwd.encode('utf-8'))

這麼驗證的原因是為了配合建立使用者的時候設定的密碼的格式

@post('/api/users')#建立使用者

sha1_passwd = '%s:%s' % (uid, passwd) #密碼的生成格式

user = User(id=uid, name=name.strip(), email=email,

     passwd=hashlib.sha1(sha1_passwd.encode('utf-8')).hexdigest(),#看密碼那裡

     image='http://www.gravatar.com/avatar/%s?d=mm&amp;s=120' % hashlib.md5(email.encode('utf-8')).hexdigest())

    await user.save()

 這裡看到的password已經是進行過一次摘要的,防止密碼明文在中途被截獲.

 注冊使用者頁面和使用者登入頁面上使用javascript 提前将email和password明文揉在一起 

 CryptoJS.SHA1(email + ':' + this.password1).toString()

 最後将摘要作為password,和email一起發送給服務端.服務端将user.id:password再次進行摘要操作.作為使用者的密碼密文存儲在資料庫表中.

帶cookie的登入流程:

前提條件:

建立一個管理者賬戶,注冊新使用者,admin字段手動修改為1.我記得我改過.

1.通路/manage開頭的url時,auth_factory middleware檢查用戶端帶來的cookie,鑒定是否可以免登入.如果用戶端沒有帶來一個叫COOKIE_NAME的cookie或者cookie内容是僞造的,将用戶端浏覽器重定向到登入頁面.

2.在登陸頁面填寫email和passwrod,點選登入按鈕.

前端代碼将email:password進行一次摘要作為password,然後通過廖大的postJSON将email和password發送給服務端 /api/authenticate.

3.服務端鑒定,authenticate方法中,首先通過email查找到對應的user,得到user.id.

然後将user.id:password進行一次摘要,并與建立使用者時生成的user.password進行對比.

若兩者相同,則建立一個免登入cookie,随response一起響應給用戶端.

cookie的内容,檢視user2cookie()方法.

為什麼 user.passwd = '******'

user.passwd = '********'

r.content_type = 'application/json'

r.body = json.dumps(user, ensure_ascii=False).encode('utf-8')

return r

因為這個response的body部分是将代表目前登入使用者的user對象轉化為了一個json傳回給用戶端.

如果不抹掉user.passwd,用戶端就能拿到使用者登入密碼的密文.

免登入cookie的制作配方裡用到了這個密文

def user2cookie(user, max_age):

    '''

    Generate cookie str by user.

    # build cookie string by: id-expires-sha1

    expires = str(int(time.time() + max_age))

    s = '%s-%s-%s-%s' % (user.id, user.passwd, expires, _COOKIE_KEY)

    L = [user.id, expires, hashlib.sha1(s.encode('utf-8')).hexdigest()]

    return '-'.join(L)

 用戶端現在拿到密文雖然沒什麼卵用,但本站在未來被黑的風險增加.

 在未來的日子裡,不排除有科學家使用者首先日翻了消息摘要算法,然後截獲本站管理者的登入密碼密文,僞造出合法的免登入cookie,用管理者的身份來日翻本站.

 這種情況屬于天有不測風雲,不可抗力,真有那一天,反正大家都被日翻了,誰也不笑話誰.

這是我代碼存放的地點:https://github.com/WalleSun415/awesome-python3-webapp

登陸按鈕的動作

templates/signin.html

這段js大概是vue與jquery混合雙打的寫法.我對vue沒有研究,大概能猜出這段代碼的意思.

data裡email和passwd的值由vue來維護.

methods裡邊的submit對應的就是送出處理代碼.

首先一個event.preventDefault()阻止預設事件,由用戶端決定行為.

然後下邊把email:password摘要一次,然後用廖大的postJSON向 /api/authenticate發送post請求,如果傳回沒有錯誤,就給浏覽器位址欄定位到站點根目錄.

 &lt;script&gt;

$(function() {

    var vmAuth = new Vue({

        el: '#vm',

        data: {

            email: '',

            passwd: ''

        },

        methods: {

            submit: function(event) {

                event.preventDefault();

                var

                    $form = $('#vm'),

                    email = this.email.trim().toLowerCase(),

                    data = {

                        email: email,

                        passwd: this.passwd==='' ? '' : CryptoJS.SHA1(email + ':' + this.passwd).toString()

                    };

                $form.postJSON('/api/authenticate', data, function(err, result) {

                    if (! err) {

                        location.assign('/');

                    }

                });

            }

        }

    });

});

    &lt;/script&gt;

你說的注冊按鈕綁定的 在

templates/register.html裡修改

 $(function () {

        var vm = new Vue({

            el: '#vm',

            data: {

                name: '',

                email: '',

                password1: '',

                password2: ''

            },

            methods: {

                submit: function (event) {

                    event.preventDefault();

                    var $form = $('#vm');

                    if (!this.name.trim()) {

                        return $form.showFormError('請輸入名字');

                    if (!validateEmail(this.email.trim().toLowerCase())) {

                        return $form.showFormError('請輸入正确的Email位址');

                    if (this.password1.length &lt; 6) {

                        return $form.showFormError('密碼長度至少為6個字元');

                    if (this.password1 !== this.password2) {

                        return $form.showFormError('兩次輸入的密碼不一緻');

                    var email = this.email.trim().toLowerCase();

                    $form.postJSON('/api/users', { #這裡postJSON('/api/users')

                        name: this.name.trim(),

                        passwd: CryptoJS.SHA1(email + ':' + this.password1).toString()

                    }, function (err, r) {

                        if (err) {

                            return $form.showFormError(err);

                        }

                        return location.assign('/');

                    });

                }

        });

        $('#vm').show();

@get('/register')

這個url是用來顯示注冊使用者頁面的.你github裡沒寫錯呀.

這個問題我自己找到了,問題就在那段js腳本中el,data,methods中的methods,我寫成了method,這樣就導緻了沒有調用到這個方法,還是自己太粗心了,哎呀,好氣呀!

在昨天是終于把所有功能都實作了,在自己的電腦上也都跑通了,接下來還不打算部署,而是想好好總結一下,總結一下前段後端的所有流程、功能,還想畫一個所有函數調用的流程圖給後來人作為參考,到時可能還要請教你看我的想法是否是正确的;其次,把前段界面按照自己的想法風格改一下,現在的界面還都是和廖大教程裡的一樣,雖然是簡潔,但是我醜起來我自己都害怕...最後,就是想重構一下,按照自己的想法把項目去耦合,再用flask實作一遍,這樣這個東西就可以結束了。

在這短時間内,真是多謝謝你和@灰_手,經常會麻煩你們幫忙解答我的各種問題,多謝多謝!你最近複習教程後在做什麼?接下來準備幹嘛?(ps:你有新浪微網誌或是知乎的賬号麼?我關注你 。。。)

我複習到python實戰第一天的時候,忽然心血來潮學起了廖大的javascript教程.看到DOM部分了.後邊我想試試node.js. python的實戰不知道什麼時候才能繞回去.

哈哈,等你重構完實戰項目,咱們node.js教程裡見.

我的git有現成的flask架構搭建的後端,需要有些地方可以改進,不過還是可以用的。

flask和aiohttp都是web架構吧,我看到網上很多關于flask和Django的資料,aiohttp很少,這些架構有什麼優劣嗎?

在        #聯調時一直出現如下錯誤    

        #self._encoding = charset_by_name(self._charset).encoding

        #AttributeError: 'NoneType' object has no attribute 'encoding'

        #原因竟然是把這裡的utf8 寫成了utf-8,卧槽!!

        charset=kw.get('charset', 'utf8'),

        autocommit=kw.get('autocommit', True),

        #預設最大連接配接數

        maxsize=kw.get('maxsize', 10),

        minsize=kw.get('minsize', 1),

        loop=loop

        此插入代碼

day05難點,06,07簡單,跑起來了。

本文轉自 liqius 51CTO部落格,原文連結:http://blog.51cto.com/szgb17/1943521,如需轉載請自行聯系原作者