flask基本講解
'''
# encoding: utf-8
# 從flask這個(gè)框架中導(dǎo)入flask這個(gè)類
from flask import Flask
# 初始化一個(gè)flask對象
# flask()
# 需要傳遞一個(gè)參數(shù)__name__
# 1.方便flask框架去尋找資源
# 2.方便flask插件比如flask-Sqlalchemy出現(xiàn)錯誤的時(shí)候涝开,去尋找問題所在的位置
app = Flask(__name__)
# @app.route是一個(gè)裝飾器
# @開頭雪侥,并且在函數(shù)的上面,說明是裝飾器
# 這個(gè)裝飾器的作用媚送,是做一個(gè)URL與視圖函數(shù)的映射
# 127。0.0.1:5000/ -> 去請求hello——world這個(gè)函數(shù)全蝶,然后將結(jié)果返回給瀏覽器
@app.route('/')
def hello_world():
return 'Hello World!'
# 如果當(dāng)前這個(gè)文件是作為入口程序運(yùn)行雀监,南無就執(zhí)行app.run()
if __name__ == '__main__':
# 啟動一個(gè)應(yīng)用服務(wù)器來接收用戶的請求
# whlie True:
# listen()
app.run()
'''
debug模式
- 在app.run()中傳入一個(gè)關(guān)鍵字參數(shù)debug,app.run(debug=True),就設(shè)置當(dāng)前項(xiàng)目為debug模式
- debug模式的兩大功能:
- 當(dāng)程序出現(xiàn)問題的時(shí)候,可以在頁面中看到錯誤信息和出錯的位置
- 只要修改了項(xiàng)目中的Python文件在塔,程序會自動加載幻件,不需要手動重新啟動服務(wù)器。
使用配置文件:
新建一個(gè)config.py文件
-
在主app文件中導(dǎo)入這個(gè)文件心俗,并且配置到app中傲武,示例代碼如下:
''' import config app.config.from_object(config) '''
還有許多其他的參數(shù),都是放在這個(gè)配置文件中城榛,比如'SECRET_KEY'和'SQLALCHEMY'這些配置都是在這個(gè)文件中
URL傳參數(shù):
參數(shù)的作用:可以在相同的URL揪利,但是指定不同的參數(shù),來加載 不同的數(shù)據(jù)狠持。
-
在flask中如何使用參數(shù):
''' @app.route('/article/<id>') def article(id): return u'您請求的參數(shù)是:%s' % id '''
- 參數(shù)需要放在兩個(gè)尖括號中
- 視圖函數(shù)中需要放和URL中同名的參數(shù)
反轉(zhuǎn)URL:
什么叫做反轉(zhuǎn)URL:從視圖函數(shù)到URL的轉(zhuǎn)換叫做反轉(zhuǎn)URL
-
反轉(zhuǎn)URL的用處:
- 在頁面重定向的時(shí)候疟位,會使用URL反轉(zhuǎn)。
- 在模板中也會使用URL反轉(zhuǎn)喘垂。
- 代碼實(shí)例:
'''
from flask import Flask,url_for app = Flask(__name__) @app.route('/') def index(): print url_for('my_list') print url_for('article',id='abc') return 'Hello World' @app.route('/list/') def my_list(): return 'list' @app.route('/article/<id>/') def article(id): return u'您請求的id是:%s' % id if __name__ == '__main__': app.run(debug=True)
'''
頁面跳轉(zhuǎn)和重定向
用處:在用戶訪問一些需要登錄的頁面的時(shí)候甜刻,如果用戶沒有登錄,那么可以讓他重定向到登錄的頁面正勒。
-
代碼實(shí)現(xiàn):
'''
from flask import Flask, redirect, url_for app = Flask(__name__) @app.route('/') def index(): # return redirect('/login/') login_url = url_for('login') return redirect(login_url) return u'這是首頁' @app.route('/login/') def login(): return u'這是登錄頁面' @app.route('/question/<is_login>') def question(is_login): if is_login == '1': return u'這是發(fā)布問答頁面' else: return redirect(url_for('login')) if __name__ == '__main__': app.run(debug=True)
'''
Flask渲染Jinja2模板和傳參
- 如何渲染模板:
- 模板放在'templates'文件夾下
- 從'flask'種導(dǎo)入'render_template'函數(shù)得院。
- 在視圖函數(shù)中,使用'render_template'函數(shù)章贞,渲染模板祥绞。注意:只需要填寫模板的名字,不需要填寫'tenplates'這個(gè)文件夾的路徑鸭限。
- 模板傳參:
- 如果只有一個(gè)或者少量的參數(shù)蜕径,直接在'render_template'函數(shù)中添加關(guān)鍵字就可以了。
- 如果有多個(gè)參數(shù)的時(shí)候败京,那么可以先把所有的參數(shù)放在字典中兜喻,然后在'render_template'中,使用兩個(gè)星號赡麦,把字典轉(zhuǎn)換成關(guān)鍵參數(shù)傳遞進(jìn)去朴皆,這樣的代碼更方便管理和使用。
- 在模板中泛粹,如果要使用一個(gè)變量车荔,語法是:'{{params}}'
- 訪問模型中的屬性或者字典,可以通過'{{params.property}}'的形式戚扳,或者是使用'{{params['age']}}'忧便。
if判斷
-
語法:
'''
{% if xxx%} # 開始 {% else %} {% endif %} # 結(jié)束語句
'''
if的使用,可以和python中相差無幾
for循環(huán)遍歷列表和字典:
-
字典的遍歷,語法'python'一樣珠增,可以使用'items()','keys()','values()','iteritems()','iterkeys','itervalues'超歌。
- 示例代碼:
'''
{% for k,v in user.items() %} <p>{{ k }}: {{ v }}</p> {% endfor %}
'''
2.列表的遍歷:語法和'python'一樣
'''
{% for website in websites %}
<p>{{ website }}</p>
{% endfor %}
'''
過濾器
-
介紹和語法:
- 介紹:過濾器可以處理變量,把原始的變量經(jīng)過處理后再展示出來蒂教,作用的對象是變量巍举。
- 語法:
'''
{{ avatar|default('xxx)}}
'''
defailt過濾器:如果當(dāng)前變量不存在,這時(shí)候可以指定默認(rèn)值凝垛。
length過濾器:求列表或者字符串或者字典或者元祖的長度懊悯。
繼承和block
-
繼承作用和語法:
- 作用:可以吧一些公共的代碼放在父模板中,避免每個(gè)模板寫相同的代碼梦皮,太麻煩炭分。
- 語法:
'''
{% extends 'base.html' %}
'''
-
block實(shí)現(xiàn):
- 作用:可以讓子模板實(shí)現(xiàn)一些自己的需求,父模板需要提前定義好剑肯。
- 注意點(diǎn):子模板中的代碼必須放在block中
- 代碼:
'''
{% balock main %} <h1>這是首頁<h1> {% endblock %}
'''
加載靜態(tài)文件
- 語法:' url_for('static',filename='路徑') '
- 靜態(tài)文件捧毛,flask會從'static'文件夾中來時(shí)尋找,所以不需要再寫'static'這個(gè)路徑了让网。
- 可以加載css文件可以加載js文件還有image文件呀忧。
MySQL
安裝
- windows10直接在mysql官網(wǎng)下載64位的安裝離線程序安裝就可以了
- Linux:
MySQL-python中間件的介紹與安裝
- 如果是在類Unix系統(tǒng)上,直接進(jìn)入到虛擬環(huán)境溃睹,輸入'sudo pip install mysql-python'.
- windows上而账,需要在這里下載'https://www.lfd.uci.edu/~gohlke/pythonlibs/#mysql-python'
下載'MySQL_python-1.2.5-cp27-none-win_amd64.whl'然后在命令行中進(jìn)入到'MySQL_python-1.2.5-cp27-none-win_amd64.whl'所在的目錄,輸入一下命令安裝:
'''
pip install MySQL_python-1.2.5-cp27-none-win_amd64.whl
'''
flask-SQLAlchemy的介紹與安裝
ORM:Obiect Relationship Mapping(模型關(guān)系映射)因篇。
flask-SQLAlchemy是一套ORM框架福扬。
ORM的好處:可以讓我們操作數(shù)據(jù)庫跟操作對象一樣,非常方便惜犀。因?yàn)橐粋€(gè)表就抽象成一個(gè)類,一條數(shù)據(jù)就抽象成該類的對象狠裹。
-
安裝'flask-SQLAlchemy':
'''sudo pip install flask-sqlalchemy
'''
Flask-SQLAlchemy的使用:
-
初始化和設(shè)置數(shù)據(jù)庫信息:
- 使用flask-sqlalchemy中的SQLAlchemy進(jìn)行初始化:
'''
from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) db = SQLAlchemy(app)
'''
-
設(shè)置配置信息:在'config.py'文件中添加一下配置信息:
'''
# dialect+driver://username:password@host/database DIALECT = 'mysql' DRIVER = 'mysqldb' USERNAME = 'root' PASSWORD = 'root' HOST = '127.0.0.1' PORT = '3306' DATABASE = 'db_demo1' SQLALCHEMY_DATABASE_URI = "{}+{}://{}:{}@{}:{}/{}?charset=utf8".format(DIALECT,DRIVER,USERNAME,PASSWORD,HOST, PORT,DATABASE) SQLALCHEMY_TRACK_MODIFICATIONS = False
'''
-
在主'app'文件中虽界,添加配置文件
'''
app = Flask(__name__) app.config.from_object(config) db = SQLAlchemy(app)
'''
-
做測試,看有沒有問題
'''
db.create_all()
'''
如果沒有報(bào)錯涛菠,說明配置沒有問題莉御,如果有錯誤可以根據(jù)錯誤進(jìn)行修改。
使用flask-SQLAlchemy創(chuàng)建模型與表的映射:
- 模型需要繼承自'db.Model',然后需要映射到表中的屬性俗冻,必須寫成'db.Column'的數(shù)據(jù)類型礁叔。
- 數(shù)據(jù)類型:
- 'db.Integer'代表的是整形
- 'db.String'代表的是‘varchar’,需要指定最長的長度迄薄。
- 'db.Text'代表的是text琅关。
- 其他參數(shù):
- 'primary_key':代表的是將這個(gè)字段設(shè)置為主鍵。
- 'autoincrement':代表的是這個(gè)主鍵為自增長的讥蔽。
- 'nullable': 代表的是這個(gè)字段是否可以為空涣易,默認(rèn)為空画机,設(shè)置為False在數(shù)據(jù)庫中值就不能為空了
- 最后需要調(diào)用'db.create_all'來將模型創(chuàng)建到數(shù)據(jù)庫中。
Flask-SQLAlchemy數(shù)據(jù)的增新症,刪步氏,改,查:
-
增:
'''
# 增加 article1 = Article(title='aaa',content='bbb') db.session.add(article1) # 事物 db.session.commit()
'''
-
查:
'''
# 查 # select * from article where article.title='aaa' article1 = Article.query.filter(Article.title == 'aaa').first() print 'title:%s' % article1.title print 'content:%s' % article1.content
'''
-
改:
'''
# 改 # 1. 先把你要更改的數(shù)據(jù)查找出來 article1 = Article.query.filter(Article.title == 'aaa').first() # 2. 把這條數(shù)據(jù)徒爹,你需要修改的地方進(jìn)行修改 article1.title = 'new title' # 3. 做事物的提交 db.session.commit()
'''
-
刪:
'''
# 刪 # 1. 把需要刪除的數(shù)據(jù)查找出來 article1 = Article.query.filter(Article.content == 'bbb').first() # 2. 把這條數(shù)據(jù)刪除掉 db.session.delete(article1) # 3. 做事物提交 db.session.commit()
'''
Flask-SQLAlchemy外鍵及其關(guān)系:
-
外鍵:
'''
class User(db.Model): __tablename__ = 'user' id = db.Column(db.Integer,primary_key=True,autoincrement=True) username = db.Column(db.String(100),nullable=False) class Article(db.Model): __tablename__ = 'article' id = db.Column(db.Integer,primary_key=True,autoincrement=True) title = db.Column(db.String(100),nullable=False) content = db.Column(db.Text,nullable=False) author_id = db.Column(db.Integer,db.ForeignKey('user.id')) author = db.relationship('User',backref=db.backref('articles')) db.create_all()
'''
-
'author = db.relationship('User',backref=db.backref('articles'))'解釋:
- 給'Article'這個(gè)模型添加一個(gè)'author'
屬性荚醒,可以訪問這篇文章的作者的數(shù)據(jù),像訪問不同模型一樣隆嗅。 - 'backref'是定義反向引用界阁,可以通過'User.articles'訪問這個(gè)模型所寫的所有的文章。
- 給'Article'這個(gè)模型添加一個(gè)'author'
-
多對多:
- 多對多的關(guān)系榛瓮,要通過一個(gè)中間表進(jìn)行關(guān)聯(lián)铺董。
- 中間表,不能通過'class'的方式實(shí)現(xiàn)禀晓,只能通過'db.Table'的方式實(shí)現(xiàn)精续。
- 設(shè)置關(guān)聯(lián):'tags = db.relationship('Tag',secondary=article_tag,backref=db.backref('articles'))'需要使用一個(gè)關(guān)鍵字參數(shù)'secondary=中間表'來進(jìn)行關(guān)聯(lián)。
- 訪問和數(shù)據(jù)添加可以通過一下方式進(jìn)行操作:
-
添加數(shù)據(jù):
'''article1 = Article(title='aaa') article2 = Article(title='bbb') tag1 = Tag(name='111') tag2 = Tag(name='222') article1.tags.append(tag1) article1.tags.append(tag2) article2.tags.append(tag1) article2.tags.append(tag2) db.session.add(article1) db.session.add(article2) db.session.add(tag1) db.session.add(tag2) db.session.commit()
'''
-
訪問數(shù)據(jù):
'''article1 = Article.query.filter(Article.title == 'aaa').first() tags = article1.tags for tag in tags: print tag.name
'''
-
Flask-Script的介紹安裝:
Flask-Script:Flask——Script的作用是可以通過命令行的形式來操作Flask粹懒。例如通過命令跑一個(gè)開發(fā)版本的服務(wù)器重付,設(shè)置數(shù)據(jù)庫,定時(shí)任務(wù)等凫乖。
安裝:首先進(jìn)入到虛擬環(huán)境中确垫,然后'pip install flask-script'來進(jìn)行安裝。
如果直接在主'manage.py'中寫命令帽芽,那么終端就只需要'python manage.py command_name'就可以了删掀。
如果把一些命令集中在一個(gè)文件中,那么就需要在終端輸入一個(gè)父命令导街,比如'python manage.py db init'披泪。
-
例子:
'''from flask_script import Manager from flask_script_demo import app from db_script import DBManager manager = Manager(app) # 數(shù)據(jù)庫相關(guān)的操作,都放在一起 @manager.command def runaerver(): print '服務(wù)器跑起來了' manager.add_command('db',DBManager)
'''
-
有子命令的例子:
'''from flask_script import Manager DBManager = Manager() @DBManager.command def init(): print '數(shù)據(jù)庫初始化完成' @DBManager.command def migrate(): print '數(shù)據(jù)表遷移成功'
'''
分開'models'以及解決循環(huán)引用:
- 分開models的目的:為了讓代碼更加方便的管理搬瑰。
- 如何解決循環(huán)引用:把'db'放在一個(gè)單獨(dú)的文件中款票,切斷循環(huán)引用的線條就可以了。
Flask-Migrate的介紹與安裝:
介紹:因?yàn)椴捎?db.craete_all'子后期修改字段的時(shí)候泽论,不會自動的映射到數(shù)據(jù)庫中艾少,必須刪除表,然后重新運(yùn)行'db.craete_all'才會重新映射翼悴,這樣不符合我們的需求缚够,因此flask-migrate就是為了解決這個(gè)問題,他可以在每次修改模型后,可以將修改的東西映射到數(shù)據(jù)庫中潮瓶。
首先進(jìn)入到你的虛擬環(huán)境中然后使用'pip install flask-migrate'進(jìn)行安裝就可以了陶冷。
使用'falsk_migrate'必須借助'flask_scripts',這個(gè)包的'MigrateCommand'中包含了所有和數(shù)據(jù)庫相關(guān)的命令。
-
'flask_migrate'相關(guān)的命令:
'python manage.py db init':初始化一個(gè)遷移腳本的環(huán)境毯辅,只需要執(zhí)行一次埂伦。
'python manage.py db migrate':將模型生成遷移文件,只要模型更改了思恐,就需要執(zhí)行一遍這個(gè)命令沾谜。
'python manage.py db upgrade':將遷移文件真正的映射到數(shù)據(jù)庫中。每次運(yùn)行migrate命令后胀莹,就記得要運(yùn)行這個(gè)命令基跑。
注意點(diǎn):需要將你想要映射到數(shù)據(jù)庫中的模型,都要導(dǎo)入到manage.py文件中描焰,如果沒有導(dǎo)入進(jìn)去就不會映射到數(shù)據(jù)庫中
-
'manage.py'相關(guān)代碼:
'''
from flask_script import Manager from migrate_demo import app from flask_migrate import Migrate,MigrateCommand from exts import db from models import Article # init 初始化遷移環(huán)境 # migrate 生成遷移文件 # upgrade # 數(shù)據(jù)庫遷移一般分為兩步 # # 生成遷移的腳本 # 運(yùn)行腳本媳否,更改數(shù)據(jù)庫 # 模型 -> 遷移文件 -> 表 manager = Manager(app) # 1. 要使用flask——migrate,必須綁定app和db migrate = Migrate(app,db) # 2. 把MigrateCommand命令添加到manader中 manager.add_command('db',MigrateCommand) if __name__ == '__main__': manager.run()
'''
cookie:
- 'cookie'出現(xiàn)的原因:在網(wǎng)站中荆秦,http是無狀態(tài)的篱竭。也就是說即使第一次和服務(wù)器鏈接后并且登錄成功后,第二次請求服務(wù)器依然不能知道當(dāng)前請求的是那個(gè)用戶步绸。cookie的出現(xiàn)就是為了解決這個(gè)問題掺逼,第一次登錄后服務(wù)器返回一些數(shù)據(jù)cookie給瀏覽器,然后瀏覽器保存在本地瓤介,當(dāng)該用戶發(fā)送第二次請求的時(shí)候吕喘,就會自動的把上次請求存儲的cookie數(shù)據(jù)自動的攜帶給服務(wù)器,服務(wù)器通過瀏覽器攜帶的數(shù)據(jù)就能判斷當(dāng)前的用戶是哪個(gè)了刑桑。
- 如果服務(wù)器返回了cookie給瀏覽器氯质,南無瀏覽器下次在請求相同的服務(wù)器的時(shí)候,就會自動的把cookie發(fā)送給服務(wù)器祠斧,這個(gè)過程用戶根本不需要管闻察。
- cookie是保存在瀏覽器中的,相對的是瀏覽器梁肿。
session:
- session介紹:session和cookie的作用有點(diǎn)類似,都是為了存儲用戶相關(guān)的信息觅彰,不同的是吩蔑,cookie是存儲在本地瀏覽器,為session存儲在服務(wù)器填抬。存儲在服務(wù)器的數(shù)據(jù)會更加安全烛芬,不容易被竊取,但存儲在服務(wù)器也有一定的弊端,就是會占用服務(wù)器的資源赘娄,但現(xiàn)在服務(wù)器已經(jīng)發(fā)展至今仆潮,一些session信息還是綽綽有余的。
- 使用session的好處:
- 敏感數(shù)據(jù)不是直接發(fā)送給瀏覽器遣臼,而是發(fā)送會一個(gè)session_id,服務(wù)器將session_id和敏感數(shù)據(jù)做一個(gè)映射存儲在session(服務(wù)器上面)中性置,更加安全店诗。
- session可以設(shè)置過期時(shí)間繁疤,也從另外一方面,保證了用戶的賬號安全钳宪。
flask中的session工作機(jī)制:
- flask中的session機(jī)制是:把敏感數(shù)據(jù)經(jīng)過加密后放入session中屏歹,然后在把session存儲到cookie中隐砸,下次請求的時(shí)候。再從瀏覽器發(fā)送過來的cookie中讀取session蝙眶,然后在從session中讀取敏感數(shù)據(jù)季希,并進(jìn)行解密,獲取最終的用戶數(shù)據(jù)幽纷。
- flask的這種session機(jī)制式塌,可以節(jié)省服務(wù)器的開銷,因?yàn)榘阉械男畔⒍即鎯υ诳蛻舳耍g覽器)霹崎。
- 安全是相對的珊搀,把session放到cookie中經(jīng)過加密也是比較安全的,這點(diǎn)大家放心使用就可以了尾菇。
操作session:
- session的操作方式:
- 使用session需要flask中導(dǎo)入session境析,以后所有和session相關(guān)的操作都是通過這個(gè)變量來的。
- 使用session需要設(shè)置SECRET_KEY派诬,用來作為加密用的劳淆。并且這個(gè)SECRET_KEY,如果每次服務(wù)器啟動都變化的話,那么之前的session就不能通過當(dāng)前這個(gè)SECRET_KEY進(jìn)行解密了默赂。
- 操作session的時(shí)候沛鸵,跟操作字典是一樣的。
- 添加session:'session['username']'
- 刪除session:session.pop('username')或者del session['username']
- 清除所有session:'session.clear()'
- 獲壤掳恕session: 'session.get(username)'
- 設(shè)置session的過期時(shí)間:
- 如果沒有指定session的過期時(shí)間曲掰,那么默認(rèn)是瀏覽器關(guān)閉之后就自動結(jié)束
- 如果設(shè)置session的permanent屬性為True,那么過期時(shí)間是31天
- 可以通過給'app.config'設(shè)置'PERMANENT_SESSION_LIFETIME'來更改過期時(shí)間奈辰,這個(gè)值的數(shù)據(jù)類型是'datetime.timedelay'類型栏妖。
get請求post請求:
- get請求:
- 使用場景:如果只對服務(wù)器獲取數(shù)據(jù),并沒有對服務(wù)器產(chǎn)生任何影響奖恰,那么這個(gè)時(shí)候使用get請求吊趾。
- 傳參:get請求傳參是放在URL中的宛裕,并且是通過'?'的形式來指定key和value的。
- post請求:
- 使用場景:如果要對服務(wù)器產(chǎn)生影響论泛,那么使用post請求揩尸。
- post請求傳參不是放在URL中的,是通過'from data'的形式發(fā)送給服務(wù)器的屁奏。
get和post請求獲取參數(shù):
get請求是通過'flask.request.args'來獲取岩榆。
post請求是通過'flask.request.form'來獲取
-
post請求在模板中要注意幾點(diǎn):
- input標(biāo)簽中,要寫name來標(biāo)識value的key了袁,方便后臺獲取朗恳。
- 在寫form表單的時(shí)候,要指定'method='post''并且要指定'action='/login/''载绿。
-
示例代碼:
'''<form action="{{ url_for('login') }}" method="post"> <table> <tbody> <tr> <td>用戶名:</td> <td><input type="text" placeholder="請輸入用戶名" name="username"></td> </tr> <tr> <td>密碼:</td> <td><input type="text" placeholder="請輸入密碼" name="password"></td> </tr> <tr> <td></td> <td><input type="submit" value="登錄"></td> </tr> </tbody> </table>
</form>
'''
保存全局變量的g屬性:
g: global
- g對象是專門保存用戶的數(shù)據(jù)的
- g對象在一次請求中的所有代碼的地方粥诫,都是可以使用的。
鉤子函數(shù)(hook)
-
before_request:
- 在請求之前執(zhí)行的
- 是在視圖函數(shù)之前執(zhí)行的
- 這個(gè)函數(shù)只是一個(gè)裝飾器崭庸,它可以把需要設(shè)置為鉤子函數(shù)的代碼放到視圖函數(shù)執(zhí)行之前來執(zhí)行
-
context_processor:
- 上下文處理器用該返回一個(gè)字典怀浆。字典中的key會在模板中當(dāng)成變量來渲染。
- 上下文處理器中返回的字典怕享,在所有頁面中都是可用的执赡。
- 被這個(gè)裝飾器修飾的鉤子函數(shù),必須返回一個(gè)字典函筋,即使為空也要返回沙合。
裝飾器
- 裝飾器實(shí)際上就是一個(gè)函數(shù),有兩個(gè)特別之處
- 參數(shù)是一個(gè)函數(shù)
- 返回值是一個(gè)函數(shù)
- 裝飾器使用是通過@符號跌帐,放在函數(shù)上面
- 裝飾器中定義的函數(shù)首懈,要使用args,kwargs兩對兄弟的組合。并且在這個(gè)函數(shù)中執(zhí)行原函數(shù)的時(shí)候也要把args, **kwargs傳進(jìn)去谨敛。
- 需要使用functiils.wraps在裝飾器中的函數(shù)上把傳進(jìn)來的這個(gè)函數(shù)進(jìn)行一個(gè)包裹究履,這樣就不會丟失原來的函數(shù)name等屬性
- from functools import wraps