Python Decorators: различия между версиями

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску
(Новая: =Декораторы в питоне= Разбор только одного примера, что был сложен для меня.)
 
 
(не показано 7 промежуточных версий этого же участника)
Строка 1: Строка 1:
  +
[[Категория:Python]]
 
=Декораторы в питоне=
 
=Декораторы в питоне=
   
 
Разбор только одного примера, что был сложен для меня.
 
Разбор только одного примера, что был сложен для меня.
  +
  +
  +
<PRE>
  +
# coding=utf8
  +
from webob import Request
  +
from wsgiref import simple_server
  +
from webob.exc import HTTPNotFound
  +
  +
</PRE>
  +
webob - работа с HTTP
  +
wsgiref - веб сервер. можно использовать любой другой, и имя им легион.
  +
  +
Декоратор. Сама идея декоратора прекрасна - обернуть вызов ф-и в другую ф-ю и потом переопределить оригинальную.
  +
вот хорошие ссылки:
  +
* http://habrahabr.ru/post/141411/
  +
* http://habrahabr.ru/post/139866/
  +
  +
Это декоратор:
  +
<PRE>
  +
def webob_wrap(func):
  +
def wrapped(environ, start_response):
  +
aaa=100
  +
req = Request(environ)
  +
app = func(req, environ)
  +
return app(environ, start_response)
  +
return wrapped
  +
</PRE>
  +
  +
  +
Это собственно функции которые борабатывают URL.
  +
<PRE>
  +
def list_topics_app(environ, start_response):
  +
start_response('200 OK', [('Content-type', 'text/plain')])
  +
return "\n".join(["%s=%s" % (k, v) for k, v in environ.items()])
  +
#return "123"
  +
  +
def view_topic_app(environ, start_response):
  +
start_response('200 OK', [('Content-type', 'text/plain')])
  +
return "\n".join(["%s=%s" % (k, v) for k, v in environ.items()])
  +
#return "123"
  +
  +
def fff(environ, start_response):
  +
start_response('200 OK', [('Content-type', 'text/plain')])
  +
return "\n".join(["%s=%s" % (k, v) for k, v in environ.items()])
  +
</PRE>
  +
  +
<PRE>
  +
@webob_wrap
  +
def forum_app(req, environ):
  +
peek = req.path_info_peek()
  +
if not peek:
  +
return list_topics_app
  +
elif peek == 'new_topic':
  +
return new_topic_app
  +
elif peek.isdigit():
  +
topic_id = int(req.path_info_pop())
  +
environ['forum_app.topic_id'] = topic_id
  +
return view_topic_app
  +
else:
  +
return HTTPNotFound()
  +
</PRE>
  +
  +
Запуск сервера
  +
<PRE>
  +
server = simple_server.WSGIServer(
  +
('127.0.0.1', 8080),
  +
simple_server.WSGIRequestHandler,
  +
)
  +
  +
server.set_app(forum_app)
  +
server.serve_forever()
  +
</PRE>
  +
  +
Логика работы приложения такая
  +
* при любом запросе исполниться forum_app
  +
* т.к. ф-я обернута в декоратор, то на самом деле вызов будет выглядеть так
  +
<PRE>
  +
forum_app=webob_wrap(forum_app):
  +
forum_app(environ, start_response)
  +
</PRE>
  +
Т.е. в декоратор будут передано окружение.
  +
* forum_app вернет ту ф-ю которая потом будет вызвана внутри декоратора
  +
**app = func(req, environ) - эта строчка в app запишет ф-ю (но не вызывая ее!) в зависимости от req.
  +
**return app(environ, start_response) - а вернет на самом деле результат одной из ф-я обрабатывающих URL

Текущая версия на 16:41, 28 сентября 2012

Декораторы в питоне

Разбор только одного примера, что был сложен для меня.


# coding=utf8
from webob import Request
from wsgiref import simple_server
from webob.exc import HTTPNotFound

webob - работа с HTTP wsgiref - веб сервер. можно использовать любой другой, и имя им легион.

Декоратор. Сама идея декоратора прекрасна - обернуть вызов ф-и в другую ф-ю и потом переопределить оригинальную. вот хорошие ссылки:

Это декоратор:

def webob_wrap(func):
    def wrapped(environ, start_response):
        aaa=100
        req = Request(environ)
        app = func(req, environ)
        return app(environ, start_response)
    return wrapped


Это собственно функции которые борабатывают URL.

def list_topics_app(environ, start_response):
    start_response('200 OK', [('Content-type', 'text/plain')])
    return "\n".join(["%s=%s" % (k, v) for k, v in environ.items()])
    #return "123"

def view_topic_app(environ, start_response):
    start_response('200 OK', [('Content-type', 'text/plain')])
    return "\n".join(["%s=%s" % (k, v) for k, v in environ.items()])
    #return "123"

def fff(environ, start_response):
    start_response('200 OK', [('Content-type', 'text/plain')])
    return "\n".join(["%s=%s" % (k, v) for k, v in environ.items()])
@webob_wrap
def forum_app(req, environ):
    peek = req.path_info_peek()
    if not peek:
        return list_topics_app
    elif peek == 'new_topic':
        return new_topic_app
    elif peek.isdigit():
        topic_id = int(req.path_info_pop())
        environ['forum_app.topic_id'] = topic_id
        return view_topic_app
    else:
        return HTTPNotFound()

Запуск сервера

server = simple_server.WSGIServer(
            ('127.0.0.1', 8080),
            simple_server.WSGIRequestHandler,
        )

server.set_app(forum_app)
server.serve_forever()

Логика работы приложения такая

  • при любом запросе исполниться forum_app
  • т.к. ф-я обернута в декоратор, то на самом деле вызов будет выглядеть так
forum_app=webob_wrap(forum_app):
forum_app(environ, start_response)

Т.е. в декоратор будут передано окружение.

  • forum_app вернет ту ф-ю которая потом будет вызвана внутри декоратора
    • app = func(req, environ) - эта строчка в app запишет ф-ю (но не вызывая ее!) в зависимости от req.
    • return app(environ, start_response) - а вернет на самом деле результат одной из ф-я обрабатывающих URL