導航:首頁 > 編程語言 > pythondecorated

pythondecorated

發布時間:2022-06-24 17:59:34

『壹』 如何用 flask 優雅的實現 restful api

首先,安裝Flask
pip install flask
閱讀這篇文章之前我假設你已經了解RESTful API的相關概念,如果不清楚,可以閱讀我之前寫的這篇博客[Designing a RESTful Web API
Flask是一個使用python開發的基於Werkzeug的Web框架。
Flask非常適合於開發RESTful API,因為它具有以下特點:
?使用Python進行開發,Python簡潔易懂
?容易上手
?靈活
?可以部署到不同的環境
?支持RESTful請求分發
我一般是用curl命令進行測試,除此之外,還可以使用Chrome瀏覽器的postman擴展。
資源
首先,我創建一個完整的應用,支持響應/, /articles以及/article/:id。
from flask import Flask, url_for
app = Flask(__name__)
@app.route('/')
def api_root():
return 'Welcome'
@app.route('/articles')
def api_articles():
return 'List of ' + url_for('api_articles')
@app.route('/articles/<articleid>')
def api_article(articleid):
return 'You are reading ' + articleid
if __name__ == '__main__':
app.run()
可以使用curl命令發送請求:
響應結果分別如下所示:
GET /
Welcome
GET /articles
List of /articles
GET /articles/123
You are reading 123
路由中還可以使用類型定義:
@app.route('/articles/<articleid>')
上面的路由可以替換成下面的例子:
@app.route('/articles/<int:articleid>')
@app.route('/articles/<float:articleid>')
@app.route('/articles/<path:articleid>')
默認的類型為字元串。
請求
請求參數
假設需要響應一個/hello請求,使用get方法,並傳遞參數name
from flask import request
@app.route('/hello')
def api_hello():
if 'name' in request.args:
return 'Hello ' + request.args['name']
else:
return 'Hello John Doe'
伺服器會返回如下響應信息:
GET /hello
Hello John Doe
GET /hello?name=Luis
Hello Luis
請求方法
Flask支持不同的請求方法:
@app.route('/echo', methods = ['GET', 'POST', 'PATCH', 'PUT', 'DELETE'])
def api_echo():
if request.method == 'GET':
return "ECHO: GET\n"
elif request.method == 'POST':
return "ECHO: POST\n"
elif request.method == 'PATCH':
return "ECHO: PACTH\n"
elif request.method == 'PUT':
return "ECHO: PUT\n"
elif request.method == 'DELETE':
return "ECHO: DELETE"
可以使用如下命令進行測試:
curl -X PATCH :5000/echo
不同請求方法的響應如下:
GET /echo
ECHO: GET
POST /ECHO
ECHO: POST
...
請求數據和請求頭
通常使用POST方法和PATCH方法的時候,都會發送附加的數據,這些數據的格式可能如下:普通文本(plain text), JSON,XML,二進制文件或者用戶自定義格式。
Flask中使用request.headers類字典對象來獲取請求頭信息,使用request.data 獲取請求數據,如果發送類型是application/json,則可以使用request.get_json()來獲取JSON數據。
from flask import json
@app.route('/messages', methods = ['POST'])
def api_message():
if request.headers['Content-Type'] == 'text/plain':
return "Text Message: " + request.data
elif request.headers['Content-Type'] == 'application/json':
return "JSON Message: " + json.mps(request.json)
elif request.headers['Content-Type'] == 'application/octet-stream':
f = open('./binary', 'wb')
f.write(request.data)
f.close()
return "Binary message written!"
else:
return "415 Unsupported Media Type ;)"
使用如下命令指定請求數據類型進行測試:
curl -H "Content-type: application/json" \
-X POST :5000/messages -d '{"message":"Hello Data"}'
使用下面的curl命令來發送一個文件:
curl -H "Content-type: application/octet-stream" \
-X POST :5000/messages --data-binary @message.bin
不同數據類型的響應結果如下所示:
POST /messages {"message": "Hello Data"}
Content-type: application/json
JSON Message: {"message": "Hello Data"}
POST /message <message.bin>
Content-type: application/octet-stream
Binary message written!
注意Flask可以通過request.files獲取上傳的文件,curl可以使用-F選項模擬上傳文件的過程。
響應
Flask使用Response類處理響應。
from flask import Response
@app.route('/hello', methods = ['GET'])
def api_hello():
data = {
'hello' : 'world',
'number' : 3
}
js = json.mps(data)
resp = Response(js, status=200, mimetype='application/json')
resp.headers['Link'] = 'http://luisrei.com'
return resp
使用-i選項可以獲取響應信息:
curl -i :5000/hello
返回的響應信息如下所示:
GET /hello
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 31
Link: http://luisrei.com
Server: Werkzeug/0.8.2 Python/2.7.1
Date: Wed, 25 Apr 2012 16:40:27 GMT
{"hello": "world", "number": 3}
mimetype指定了響應數據的類型。
上面的過程可以使用Flask提供的一個簡便方法實現:
from flask import jsonify
...
# 將下面的代碼替換成
resp = Response(js, status=200, mimetype='application/json')
# 這里的代碼
resp = jsonify(data)
resp.status_code = 200
狀態碼和錯誤處理
如果成功響應的話,狀態碼為200。對於404錯誤我們可以這樣處理:
@app.errorhandler(404)
def not_found(error=None):
message = {
'status': 404,
'message': 'Not Found: ' + request.url,
}
resp = jsonify(message)
resp.status_code = 404
return resp
@app.route('/users/<userid>', methods = ['GET'])
def api_users(userid):
users = {'1':'john', '2':'steve', '3':'bill'}
if userid in users:
return jsonify({userid:users[userid]})
else:
return not_found()
測試上面的兩個URL,結果如下:
GET /users/2
HTTP/1.0 200 OK
{
"2": "steve"
}
GET /users/4
HTTP/1.0 404 NOT FOUND
{
"status": 404,
"message": "Not Found: :5000/users/4"
}
默認的Flask錯誤處理可以使用@error_handler修飾器進行覆蓋或者使用下面的方法:
app.error_handler_spec[None][404] = not_found
即使API不需要自定義錯誤信息,最好還是像上面這樣做,因為Flask默認返回的錯誤信息是HTML格式的。
認證
使用下面的代碼可以處理 HTTP Basic Authentication。
from functools import wraps
def check_auth(username, password):
return username == 'admin' and password == 'secret'
def authenticate():
message = {'message': "Authenticate."}
resp = jsonify(message)
resp.status_code = 401
resp.headers['WWW-Authenticate'] = 'Basic realm="Example"'
return resp
def requires_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth:
return authenticate()
elif not check_auth(auth.username, auth.password):
return authenticate()
return f(*args, **kwargs)
return decorated
接下來只需要給路由增加@require_auth修飾器就可以在請求之前進行認證了:
@app.route('/secrets')
@requires_auth
def api_hello():
return "Shhh this is top secret spy stuff!"
現在,如果沒有通過認證的話,響應如下所示:
GET /secrets
HTTP/1.0 401 UNAUTHORIZED
WWW-Authenticate: Basic realm="Example"
{
"message": "Authenticate."
}
curl通過-u選項來指定HTTP basic authentication,使用-v選項列印請求頭:
curl -v -u "admin:secret"
響應結果如下:
GET /secrets Authorization: Basic YWRtaW46c2VjcmV0
Shhh this is top secret spy stuff!
Flask使用MultiDict來存儲頭部信息,為了給客戶端展示不同的認證機制,可以給header添加更多的WWW-Autheticate。
resp.headers['WWW-Authenticate'] = 'Basic realm="Example"'resp.headers.add('WWW-Authenticate', 'Bearer realm="Example"')
調試與日誌
通過設置debug=True來開啟調試信息:
app.run(debug=True)
使用Python的logging模塊可以設置日誌信息:
import logging
file_handlewww.huashijixun.com?.ogging.FileHandler('app.log')
app.logger.addHandler(file_handler)
app.logger.setLevel(logging.INFO)
@app.route('/hello', methods = ['GET'])
def api_hello():
app.logger.info('informing')
app.logger.warning('warning')
app.logger.error('screaming bloody murder!')
return "check your logs\n"
CURL 命令參考
選項
作用
-X 指定HTTP請求方法,如POST,GET
-H 指定請求頭,例如Content-type:application/json
-d 指定請求數據
--data-binary 指定發送的文件
-i 顯示響應頭部信息
-u 指定認證用戶名與密碼
-v 輸出請求頭部信息

『貳』 Openstack 創建主機 Virtual Interface creation failed Code: 500 Details:

看下底層libvirt報錯,一般在/var/log/libvirt/libvirtd.log

『叄』 python非同步有哪些方式

yield相當於return,他將相應的值返回給調用next()或者send()的調用者,從而交出了CPU使用權,而當調用者再次調用next()或者send()的時候,又會返回到yield中斷的地方,如果send有參數,還會將參數返回給yield賦值的變數,如果沒有就和next()一樣賦值為None。但是這里會遇到一個問題,就是嵌套使用generator時外層的generator需要寫大量代碼,看如下示例:
注意以下代碼均在Python3.6上運行調試

#!/usr/bin/env python# encoding:utf-8def inner_generator():
i = 0
while True:
i = yield i if i > 10: raise StopIterationdef outer_generator():
print("do something before yield")
from_inner = 0
from_outer = 1
g = inner_generator()
g.send(None) while 1: try:
from_inner = g.send(from_outer)
from_outer = yield from_inner except StopIteration: breakdef main():
g = outer_generator()
g.send(None)
i = 0
while 1: try:
i = g.send(i + 1)
print(i) except StopIteration: breakif __name__ == '__main__':
main()041

為了簡化,在Python3.3中引入了yield from

yield from

使用yield from有兩個好處,

1、可以將main中send的參數一直返回給最里層的generator,
2、同時我們也不需要再使用while循環和send (), next()來進行迭代。

我們可以將上邊的代碼修改如下:

def inner_generator():
i = 0
while True:
i = yield i if i > 10: raise StopIterationdef outer_generator():
print("do something before coroutine start") yield from inner_generator()def main():
g = outer_generator()
g.send(None)
i = 0
while 1: try:
i = g.send(i + 1)
print(i) except StopIteration: breakif __name__ == '__main__':
main()

執行結果如下:

do something before coroutine start123456789101234567891011

這里inner_generator()中執行的代碼片段我們實際就可以認為是協程,所以總的來說邏輯圖如下:

我們都知道Python由於GIL(Global Interpreter Lock)原因,其線程效率並不高,並且在*nix系統中,創建線程的開銷並不比進程小,因此在並發操作時,多線程的效率還是受到了很大制約的。所以後來人們發現通過yield來中斷代碼片段的執行,同時交出了cpu的使用權,於是協程的概念產生了。在Python3.4正式引入了協程的概念,代碼示例如下:

import asyncio# Borrowed from http://curio.readthedocs.org/en/latest/[email protected] countdown(number, n):
while n > 0:
print('T-minus', n, '({})'.format(number)) yield from asyncio.sleep(1)
n -= 1loop = asyncio.get_event_loop()
tasks = [
asyncio.ensure_future(countdown("A", 2)),
asyncio.ensure_future(countdown("B", 3))]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()12345678910111213141516

示例顯示了在Python3.4引入兩個重要概念協程和事件循環,
通過修飾符@asyncio.coroutine定義了一個協程,而通過event loop來執行tasks中所有的協程任務。之後在Python3.5引入了新的async & await語法,從而有了原生協程的概念。

async & await

在Python3.5中,引入了aync&await 語法結構,通過」aync def」可以定義一個協程代碼片段,作用類似於Python3.4中的@asyncio.coroutine修飾符,而await則相當於」yield from」。

先來看一段代碼,這個是我剛開始使用async&await語法時,寫的一段小程序。

#!/usr/bin/env python# encoding:utf-8import asyncioimport requestsimport time


async def wait_download(url):
response = await requets.get(url)
print("get {} response complete.".format(url))


async def main():
start = time.time()
await asyncio.wait([
wait_download("http://www.163.com"),
wait_download("http://www.mi.com"),
wait_download("http://www.google.com")])
end = time.time()
print("Complete in {} seconds".format(end - start))


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

這里會收到這樣的報錯:

Task exception was never retrieved
future: <Task finished coro=<wait_download() done, defined at asynctest.py:9> exception=TypeError("object Response can't be used in 'await' expression",)>
Traceback (most recent call last):
File "asynctest.py", line 10, in wait_download
data = await requests.get(url)
TypeError: object Response can't be used in 'await' expression123456

這是由於requests.get()函數返回的Response對象不能用於await表達式,可是如果不能用於await,還怎麼樣來實現非同步呢?
原來Python的await表達式是類似於」yield from」的東西,但是await會去做參數檢查,它要求await表達式中的對象必須是awaitable的,那啥是awaitable呢? awaitable對象必須滿足如下條件中其中之一:

1、A native coroutine object returned from a native coroutine function .

原生協程對象

2、A generator-based coroutine object returned from a function decorated with types.coroutine() .

types.coroutine()修飾的基於生成器的協程對象,注意不是Python3.4中asyncio.coroutine

3、An object with an await method returning an iterator.

實現了await method,並在其中返回了iterator的對象

根據這些條件定義,我們可以修改代碼如下:

#!/usr/bin/env python# encoding:utf-8import asyncioimport requestsimport time


async def download(url): # 通過async def定義的函數是原生的協程對象
response = requests.get(url)
print(response.text)


async def wait_download(url):
await download(url) # 這里download(url)就是一個原生的協程對象
print("get {} data complete.".format(url))


async def main():
start = time.time()
await asyncio.wait([
wait_download("http://www.163.com"),
wait_download("http://www.mi.com"),
wait_download("http://www.google.com")])
end = time.time()
print("Complete in {} seconds".format(end - start))


loop = asyncio.get_event_loop()
loop.run_until_complete(main())27282930

好了現在一個真正的實現了非同步編程的小程序終於誕生了。
而目前更牛逼的非同步是使用uvloop或者pyuv,這兩個最新的Python庫都是libuv實現的,可以提供更加高效的event loop。

uvloop和pyuv

pyuv實現了Python2.x和3.x,但是該項目在github上已經許久沒有更新了,不知道是否還有人在維護。
uvloop只實現了3.x, 但是該項目在github上始終活躍。

它們的使用也非常簡單,以uvloop為例,只需要添加以下代碼就可以了

import asyncioimport uvloop
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())123

『肆』 P148-42 python,函數返回值,括弧的問題

這樣寫你看下:這是這種寫法無法將x傳到b裡面去
def b(y):
return x+y

def a(x):
return b

其實你調用a-->列印的是a的內存地址,a(x)就是調用的a方法,返回的是b相當於你直接列印b的內存地址一樣,
所以
a-->函數a的內存地址
a(x) -->調用a方法,返回b函數對象相當於-->b
a(x)(y)-->b(y)調用b方法返回x和y的值,這里x取的是a方法的參數值,y是b方法的參數值,這點可以理解下參數的作用域

『伍』 Python裝飾器報錯,找不到名字

定義語句必須出現在調用語句之前。

『陸』 P148-42 python,函數返回值,括弧的問題

這樣寫你看下:這是這種寫法無法將x傳到b裡面去
def
b(y):
return
x+y
def
a(x):
return
b
其實你調用a-->列印的是a的內存地址,a(x)就是調用的a方法,返回的是b相當於你直接列印b的內存地址一樣,
所以
a-->函數a的內存地址
a(x)
-->調用a方法,返回b函數對象相當於-->b
a(x)(y)-->b(y)調用b方法返回x和y的值,這里x取的是a方法的參數值,y是b方法的參數值,這點可以理解下參數的作用域

『柒』 如何在Python使用裝飾器來注冊回調函數

之前一直知道裝飾器可以增強一個已經存在的方法,Python也提供了annotation的方法,很好用. 但是再看flask login的擴展包的時候. 發現裝飾器還可以實現回調函數的注冊功能.
flask login就是通過下面的裝飾器,來注冊回調函數,當沒有sessionID時,通過裝飾器指定的函數來讀取用戶到session中.
@login_manager.user_loader
下面寫了一個簡單的測試例子來演示這個功能.
import time
import functools
class Test():
#/**feature將調用callback(), 但是在Test中並沒有真正的定義callback**/
def feature(self):
self.callback()
def decorate(self, func):
self.callback=func
return func
test = Test()
#/**將foo注冊為回調函數*//
@test.decorate
def foo():
print 'in foo()'
#/**調用feature將觸發回調函數**/
test.feature()

『捌』 如何理解Python裝飾器

理解Python中的裝飾器
@makebold
@makeitalic
def say():
return "Hello"

列印出如下的輸出:
<b><i>Hello<i></b>

你會怎麼做?最後給出的答案是:

def makebold(fn):
def wrapped():
return "<b>" + fn() + "</b>"
return wrapped

def makeitalic(fn):
def wrapped():
return "<i>" + fn() + "</i>"
return wrapped

@makebold
@makeitalic
def hello():
return "hello world"

print hello() ## 返回 <b><i>hello world</i></b>

現在我們來看看如何從一些最基礎的方式來理解Python的裝飾器。英文討論參考Here。
裝飾器是一個很著名的設計模式,經常被用於有切面需求的場景,較為經典的有插入日誌、性能測試、事務處理等。裝飾器是解決這類問題的絕佳設計,有了裝飾器,我們就可以抽離出大量函數中與函數功能本身無關的雷同代碼並繼續重用。概括的講,裝飾器的作用就是為已經存在的對象添加額外的功能。
1.1. 需求是怎麼來的?
裝飾器的定義很是抽象,我們來看一個小例子。

def foo():
print 'in foo()'
foo()

這是一個很無聊的函數沒錯。但是突然有一個更無聊的人,我們稱呼他為B君,說我想看看執行這個函數用了多長時間,好吧,那麼我們可以這樣做:

import time
def foo():
start = time.clock()
print 'in foo()'
end = time.clock()
print 'used:', end - start

foo()

很好,功能看起來無懈可擊。可是蛋疼的B君此刻突然不想看這個函數了,他對另一個叫foo2的函數產生了更濃厚的興趣。
怎麼辦呢?如果把以上新增加的代碼復制到foo2里,這就犯了大忌了~復制什麼的難道不是最討厭了么!而且,如果B君繼續看了其他的函數呢?
1.2. 以不變應萬變,是變也
還記得嗎,函數在Python中是一等公民,那麼我們可以考慮重新定義一個函數timeit,將foo的引用傳遞給他,然後在timeit中調用foo並進行計時,這樣,我們就達到了不改動foo定義的目的,而且,不論B君看了多少個函數,我們都不用去修改函數定義了!

import time

def foo():
print 'in foo()'

def timeit(func):
start = time.clock()
func()
end =time.clock()
print 'used:', end - start

timeit(foo)

看起來邏輯上並沒有問題,一切都很美好並且運作正常!……等等,我們似乎修改了調用部分的代碼。原本我們是這樣調用的:foo(),修改以後變成了:timeit(foo)。這樣的話,如果foo在N處都被調用了,你就不得不去修改這N處的代碼。或者更極端的,考慮其中某處調用的代碼無法修改這個情況,比如:這個函數是你交給別人使用的。
1.3. 最大限度地少改動!
既然如此,我們就來想想辦法不修改調用的代碼;如果不修改調用代碼,也就意味著調用foo()需要產生調用timeit(foo)的效果。我們可以想到將timeit賦值給foo,但是timeit似乎帶有一個參數……想辦法把參數統一吧!如果timeit(foo)不是直接產生調用效果,而是返回一個與foo參數列表一致的函數的話……就很好辦了,將timeit(foo)的返回值賦值給foo,然後,調用foo()的代碼完全不用修改!

#-*- coding: UTF-8 -*-
import time

def foo():
print 'in foo()'

# 定義一個計時器,傳入一個,並返回另一個附加了計時功能的方法
def timeit(func):

# 定義一個內嵌的包裝函數,給傳入的函數加上計時功能的包裝
def wrapper():
start = time.clock()
func()
end =time.clock()
print 'used:', end - start

# 將包裝後的函數返回
return wrapper

foo = timeit(foo)
foo()

這樣,一個簡易的計時器就做好了!我們只需要在定義foo以後調用foo之前,加上foo = timeit(foo),就可以達到計時的目的,這也就是裝飾器的概念,看起來像是foo被timeit裝飾了。在在這個例子中,函數進入和退出時需要計時,這被稱為一個橫切面(Aspect),這種編程方式被稱為面向切面的編程(Aspect-Oriented Programming)。與傳統編程習慣的從上往下執行方式相比較而言,像是在函數執行的流程中橫向地插入了一段邏輯。在特定的業務領域里,能減少大量重復代碼。面向切面編程還有相當多的術語,這里就不多做介紹,感興趣的話可以去找找相關的資料。
這個例子僅用於演示,並沒有考慮foo帶有參數和有返回值的情況,完善它的重任就交給你了 :)
上面這段代碼看起來似乎已經不能再精簡了,Python於是提供了一個語法糖來降低字元輸入量。

import time

def timeit(func):
def wrapper():
start = time.clock()
func()
end =time.clock()
print 'used:', end - start
return wrapper

@timeit
def foo():
print 'in foo()'

foo()

重點關注第11行的@timeit,在定義上加上這一行與另外寫foo = timeit(foo)完全等價,千萬不要以為@有另外的魔力。除了字元輸入少了一些,還有一個額外的好處:這樣看上去更有裝飾器的感覺。
-------------------
要理解python的裝飾器,我們首先必須明白在Python中函數也是被視為對象。這一點很重要。先看一個例子:

def shout(word="yes") :
return word.capitalize()+" !"

print shout()
# 輸出 : 'Yes !'

# 作為一個對象,你可以把函數賦給任何其他對象變數

scream = shout

# 注意我們沒有使用圓括弧,因為我們不是在調用函數
# 我們把函數shout賦給scream,也就是說你可以通過scream調用shout

print scream()
# 輸出 : 'Yes !'

# 還有,你可以刪除舊的名字shout,但是你仍然可以通過scream來訪問該函數

del shout
try :
print shout()
except NameError, e :
print e
#輸出 : "name 'shout' is not defined"

print scream()
# 輸出 : 'Yes !'

我們暫且把這個話題放旁邊,我們先看看python另外一個很有意思的屬性:可以在函數中定義函數:

def talk() :

# 你可以在talk中定義另外一個函數
def whisper(word="yes") :
return word.lower()+"...";

# ... 並且立馬使用它

print whisper()

# 你每次調用'talk',定義在talk裡面的whisper同樣也會被調用
talk()
# 輸出 :
# yes...

# 但是"whisper" 不會單獨存在:

try :
print whisper()
except NameError, e :
print e
#輸出 : "name 'whisper' is not defined"*

函數引用
從以上兩個例子我們可以得出,函數既然作為一個對象,因此:
1. 其可以被賦給其他變數
2. 其可以被定義在另外一個函數內
這也就是說,函數可以返回一個函數,看下面的例子:

def getTalk(type="shout") :

# 我們定義另外一個函數
def shout(word="yes") :
return word.capitalize()+" !"

def whisper(word="yes") :
return word.lower()+"...";

# 然後我們返回其中一個
if type == "shout" :
# 我們沒有使用(),因為我們不是在調用該函數
# 我們是在返回該函數
return shout
else :
return whisper

# 然後怎麼使用呢 ?

# 把該函數賦予某個變數
talk = getTalk()

# 這里你可以看到talk其實是一個函數對象:
print talk
#輸出 : <function shout at 0xb7ea817c>

# 該對象由函數返回的其中一個對象:
print talk()

# 或者你可以直接如下調用 :
print getTalk("whisper")()
#輸出 : yes...

還有,既然可以返回一個函數,我們可以把它作為參數傳遞給函數:

def doSomethingBefore(func) :
print "I do something before then I call the function you gave me"
print func()

doSomethingBefore(scream)
#輸出 :
#I do something before then I call the function you gave me
#Yes !

這里你已經足夠能理解裝飾器了,其他它可被視為封裝器。也就是說,它能夠讓你在裝飾前後執行代碼而無須改變函數本身內容。
手工裝飾
那麼如何進行手動裝飾呢?

# 裝飾器是一個函數,而其參數為另外一個函數
def my_shiny_new_decorator(a_function_to_decorate) :

# 在內部定義了另外一個函數:一個封裝器。
# 這個函數將原始函數進行封裝,所以你可以在它之前或者之後執行一些代碼
def the_wrapper_around_the_original_function() :

# 放一些你希望在真正函數執行前的一些代碼
print "Before the function runs"

# 執行原始函數
a_function_to_decorate()

# 放一些你希望在原始函數執行後的一些代碼
print "After the function runs"

#在此刻,"a_function_to_decrorate"還沒有被執行,我們返回了創建的封裝函數
#封裝器包含了函數以及其前後執行的代碼,其已經准備完畢
return the_wrapper_around_the_original_function

# 現在想像下,你創建了一個你永遠也不遠再次接觸的函數
def a_stand_alone_function() :
print "I am a stand alone function, don't you dare modify me"

a_stand_alone_function()
#輸出: I am a stand alone function, don't you dare modify me

# 好了,你可以封裝它實現行為的擴展。可以簡單的把它丟給裝飾器
# 裝飾器將動態地把它和你要的代碼封裝起來,並且返回一個新的可用的函數。
a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function_decorated()
#輸出 :
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs

現在你也許要求當每次調用a_stand_alone_function時,實際調用卻是a_stand_alone_function_decorated。實現也很簡單,可以用my_shiny_new_decorator來給a_stand_alone_function重新賦值。

a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function()
#輸出 :
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs

# And guess what, that's EXACTLY what decorators do !

裝飾器揭秘
前面的例子,我們可以使用裝飾器的語法:

@my_shiny_new_decorator
def another_stand_alone_function() :
print "Leave me alone"

another_stand_alone_function()
#輸出 :
#Before the function runs
#Leave me alone
#After the function runs

當然你也可以累積裝飾:

def bread(func) :
def wrapper() :
print "</''''''\>"
func()
print "<\______/>"
return wrapper

def ingredients(func) :
def wrapper() :
print "#tomatoes#"
func()
print "~salad~"
return wrapper

def sandwich(food="--ham--") :
print food

sandwich()
#輸出 : --ham--
sandwich = bread(ingredients(sandwich))
sandwich()
#outputs :
#</''''''\>
# #tomatoes#
# --ham--
# ~salad~
#<\______/>

使用python裝飾器語法:

@bread
@ingredients
def sandwich(food="--ham--") :
print food

sandwich()
#輸出 :
#</''''''\>
# #tomatoes#
# --ham--
# ~salad~
#<\______/>

『玖』 是否有等同於局部類任何Python

1. 如果你的問題真的只是正與一大班在編輯器中,第一個解決方案,我會真正期待的是一個更好的方式來打破的問題。第二個解決方案是一個更好的編輯器,最好是有代碼折疊。
這就是說,有幾個方法你可能會打破一個班級分成多個文件。python讓一個文件夾作為一個模塊通過將一個__init__.py在裡面,然後可以從其他文件中導入的東西。我們'這種能力在每一個解決方案。做一個調用,比如文件夾,bigclass第一。
在文件夾放.py文件將你的類.each人都應該包含在最終的類,而不是類函數和變數定義。在__init__.py在文件夾中寫入以下加入他們一起。
class Bigclass(object):

from classdef1 import foo, bar, baz, quux
from classdef2 import thing1, thing2
from classdef3 import magic, moremagic
# unfortunately, "from classdefn import *" is an error or warning

num = 42 # add more members here if you like

這有你最終直接來源於單個類的優勢object,這將很好看在你的繼承圖。
你的類的你多重繼承的部分。在你的各個模塊,你會寫一個類定義Bigclass帶之類的部件。然後在你的__init__.py寫:
import classdef1, classdef2, classdef3

class Bigclass(classdef1.Bigclass, classdef2.Bigclass, classdef3.Bigclass):
num = 42 # add more members if desired

如果多重繼承的問題,你可以使用單繼承:只需每個類繼承自另外一個連鎖的方式。假設你沒有在多個類中定義的話,就是順序無關緊要。例如,classdef2.py會是這樣的:
import classdef1
class Bigclass(classdef1.Bigclass):
# more member defs here

classdef3將進口Bigclass從classdef2並添加到它,等等。您的__init__.py將剛剛導入的最後一個:
from classdef42 import Bigclass

我一般喜歡#1它是更加明確要導入從哪個文件,但所有這些解決方案可以為你工作。
類中的任何一種情況你可以導入,使用文件夾作為模塊from bigclass import Bigclass

2.
包含數百行確實發生「在野外」(我看到在類定義中流行的開放源代碼的基於Python的,但我相信,如果你思考什麼都做,將有可能減少到可管理的大多數類的長度。點的例子:
尋找其中大部分代碼出現一次以上的地方。打破代碼分解到其與調用它的每一個地方
「私人」的方法是做任何對象狀態的可以帶出的類作為獨立的功能。
只應在特定條件下被調用的方法可能表明需要在子類的地方。
直接解決你的問題,它可以分裂一個類的定義.a種方法是「猴子補丁」之類通過定義它,然後添加外功能,它另一個是內置的type功能「手動」來創建類,其提供的任何基類,並在一本字典屬性。但我不這樣做,只是定義將是長期的,否則。那種治癒的是比疾病在我看來更糟。

3.
我已經有類似玩弄各地。是一個抽象語法樹節點的類層次結構,然後我希望把所有的如:以漂亮的funtions在一個單獨的prettyprint.py文件,但仍然有他們的班。
有一件事我想是一個裝飾的放裝飾的功能作為一個屬性上指定的類。在我而言這是prettyprint.py包含大量的def prettyprint(self)所有裝飾著不同@inclass(...)有這方面的一個問題是,必須確保該子文件總是進口的,而且它們所依賴的主類,這對於一個循環依賴,這可能
def inclass(kls):
"""
Decorator that adds the decorated function
as a method in specified class
"""
def _(func):
setattr(kls,func.__name__, func)
return func
return _

## exampe usage
class C:
def __init__(self, d):
self.d = d

# this would be in a separate file.
@inclass(C)
def meth(self, a):
"""Some method"""
print "attribute: %s - argument: %s" % (self.d, a)

i = C(10)
print i.meth.__doc__
i.meth(20)

4.
我已經,但是,這個包稱為部分索賠增加的部分類別的支持。
好像還有一些其他的方法,你會這樣自己也是如此。
你可以分開的類的部分作為單獨的文件混入,然後將它們導入所有和繼承他們。
或者,您也可以在每個類的,然後在中央文件中導入,並指定其為一個類的屬性,來創建整個對象。像這樣:
a.py:
def AFunc( self, something ):
# Do something
pass

b.py:
def BFunc( self, something ):
# Do something else
pass

c.py:
import a, b

class C:
AFunc = a.AFunc
BFunc = b.BFunc

你甚至可以走那麼遠,自動完成這個過程,如果你真的想要的-通過所有模塊所提供的功能迴路a和b然後將它們添加為屬性上C。雖然這可能是總矯枉過正。
可能還有其他的(可能更好)的方式去了解它,但那些都是閃入腦海的2。

5.
首先,我想說,這可能不是一個好主意只是為了找到你的類中的地方更容易-這將是最好的補充高亮部分等。不過,我看你能做到這一點有兩種方式:
寫的類在幾個文件,然後讀取它們的文字,將它們連接起來,並exec結果字元串。
在每個文件創建一個單獨的類,然後繼承他們都為一個大師班的混入。但是,如果你繼承另一個類已經就可能導致MRO問題。你能解決這個問題通過創建其手動解決MRO你的大師班,但是這可能
最簡單的是第一個選項。

6.
首先,我不明白怎麼分裂全班分成多個文件,使編輯變得更容易.a個體面的IDE應該能夠很容易地找到是否在一個文件或多個,如果你是一個體面的IDE,分裂的維護者有猜測哪些文件是,這聽起來更難,而不是更容易。
更多這個類-如此之大,你想有一個特殊的語言功能只是為了支撐其重量-破碎的聲音。我們是如何多行代碼在談論什麼?幾乎可以肯定,這將是一個更好的主意,這樣做的一個:
重構代碼復制到更少的,更普遍的原語
定義一個基類和子類與擴展它作為卡羅利霍瓦特在暗示(這是最接近於「局部類」那你問我會贊同)
定義一些單獨的類來封裝這種不同部分
類的功能,這個類的實例的
較小的。

7.
的情況-我想slipt我班2個文件。
原因是-我想第1部分為GUI布局,只有布局
而另一個文件保存了所有的功能。
像C#的部分類.a個用於XAML和另一個用於功能。

8.
你可以做到這一點的,像這樣的裝飾:
class Car(object):

def start(self):
print 'Car has started'

def extends(klass):
def decorator(func):
setattr(klass, func.__name__, func)
return func
return decorator

#this can go in a different mole/file
@extends(Car)
def do_start(self):
self.start()

#so can this
car = Car()
car.do_start()

#=> Car has started

『拾』 P148-41 python,代碼執行順序問題,

這個不好描述,《python核心編程》過一遍應該就知道為什麼了

閱讀全文

與pythondecorated相關的資料

熱點內容
怎麼查看u盤加密區 瀏覽:181
台電加密是什麼格式 瀏覽:155
php論壇版塊在哪個文件夾 瀏覽:442
暗黑的伺服器為什麼維護 瀏覽:623
android內存溢出的原因 瀏覽:17
標志307的壓縮比是多少 瀏覽:636
伺服器啟動為什麼叫三聲 瀏覽:997
追風箏的人英文pdf 瀏覽:939
解壓小熊手機殼 瀏覽:346
成都市區建成面積演算法 瀏覽:660
智能家居單片機 瀏覽:97
買男裝用什麼app好 瀏覽:855
文件夾合並了怎麼拆開 瀏覽:260
波段副圖源碼無未來函數 瀏覽:89
livecn伺服器地址 瀏覽:259
程序員這個工作真的很吃香嗎 瀏覽:847
程序員和數學分析師待遇 瀏覽:681
壓縮氣彈簧怎麼拆 瀏覽:325
華為公有雲伺服器添加虛擬ip 瀏覽:211
程序員和運營哪個累 瀏覽:27