0

免責事項:私は明らかにデコレータにはまったく慣れていません

Pythonで関数を作成して装飾することは非常に簡単で簡単です。この優れた答え(最も賛成票が多いもの)は、非常に良い紹介を提供し、デコレータをネストする方法を示しています. まあ、これはすべて問題なく、ダンディです。しかし、私がまだ把握していないのは、(python)-web-frameworks (フラスコ、django など) のうちいくつを呼び出すことができるかということです

私の言いたいことを示す例 (Flask を使用しますが、多くのフレームワークで似ています)。

@application.route('/page/a_page')
def show_a_page():
    return html_content

@application.route('/page/another_page')
def show_another_page():
    return html_content

ここで、mysite.com/page/a_pageflask へのリクエストを行うと、何らかの方法で を呼び出す必要があることがわかりますshow_a_page。もちろん、show_another_pageリクエストが への場合も同様mysite.com/page/a_pageです。

自分のプロジェクトで同様の機能を実装するにはどうすればよいのでしょうか?

各関数の装飾(?)dir(module_name)に関する情報を抽出するために使用するようなものがあると思いますか?

4

3 に答える 3

0

BeautifulSoupを使用した大まかな例を次に示します。これは、David Robinson の回答に基づいています。デコレータは渡された文字列を関数に対応する辞書のキーとして使用します。これは、キーワード引数を介して、それが呼び出される装飾された関数に渡されます。

import os
import sys

# Import System libraries
from copy import deepcopy

# Import Custom libraries
from BeautifulSoup import BeautifulSoup, Tag

page_base_str = \
'''
<!doctype html>
<html>
<head>
    <title>Example Domain</title>

    <meta charset="utf-8" />
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style type="text/css">
    body {
        background-color: #f0f0f2;
        margin: 0;
        padding: 0;
        font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;

    }
    div {
        width: 600px;
        margin: 5em auto;
        padding: 50px;
        background-color: #fff;
        border-radius: 1em;
    }
    a:link, a:visited {
        color: #38488f;
        text-decoration: none;
    }
    @media (max-width: 700px) {
        body {
            background-color: #fff;
        }
        div {
            width: auto;
            margin: 0 auto;
            border-radius: 0;
            padding: 1em;
        }
    }
    </style>    
</head>

<body>
<div>
    <h1>Example Domain</h1>
    <div id="body">
        <p>This domain is established to be used for illustrative examples in documents. You may use this
        domain in examples without prior coordination or asking for permission.</p>
        <p><a href="http://www.iana.org/domains/example">More information...</a></p>
    </div>
</div>
</body>
</html>
'''
page_base_tag = BeautifulSoup(page_base_str)

def default_gen(*args):
    return page_base_tag.prettify()

def test_gen(**kwargs):
    copy_tag = deepcopy(page_base_tag)

    title_change_locations = \
    [
        lambda x: x.name == u"title",
        lambda x: x.name == u"h1"
    ]
    title = kwargs.get("title", "")
    if(title):
        for location in title_change_locations:
            search_list = copy_tag.findAll(location)
            if(not search_list):
                continue
            tag_handle = search_list[0]
            tag_handle.clear()
            tag_handle.insert(0, title)

    body_change_locations = \
    [
        lambda x: x.name == "div" and set([(u"id", u"body")]) <= set(x.attrs)
    ]
    body = kwargs.get("body", "")
    if(body):
        for location in body_change_locations:
            search_list = copy_tag.findAll(location)
            if(not search_list):
                continue
            tag_handle = search_list[0]
            tag_handle.clear()
            tag_handle.insert(0, body)

    return copy_tag.prettify()

page_gens = \
{
    "TEST" : test_gen
}

def page_gen(name = ""):
    def dec(func):
        def inner_func(**kwargs):
            kwargs["PAGE_FUNC"] = page_gens.get(name, default_gen)
            return func(**kwargs)
        return inner_func
    return dec

@page_gen("TEST")
def test_page_01(**kwargs):
    content = kwargs["PAGE_FUNC"](title = "Page 01", body = "Page 01 body")
    return content

@page_gen("TEST")
def test_page_02(**kwargs):
    content = kwargs["PAGE_FUNC"](title = "Page 02", body = "Page 02 body")
    return content

@page_gen()
def a_page(**kwargs):
    content = kwargs["PAGE_FUNC"]()
    return content

print test_page_01()
print test_page_02()
print a_page()
于 2013-07-02T02:34:07.847 に答える
0

関数に対してデコレータが何をするかは、デコレータ次第です。別の関数でラップしたり、属性にメタ情報を追加したり、辞書に保存したりすることもできます。

複数の関数をディクショナリに保存する方法の例を次に示します。このディクショナリは後でそれらの関数を検索するために使用できます。

function_table = {}

def add_to_table(name):
    def dec(func):
        def inner_func(*args, **kwargs):
            return func(*args, **kwargs)
        function_table[name] = inner_func
        return inner_func
    return dec

@add_to_table("my_addition_function")
def myfunction(a, b):
    return a + b

@add_to_table("my_subtraction_function")
def myfunction2(a, b):
    return a - b

print myfunction(1, 3)
# 4
print function_table["my_addition_function"](1, 4)
# 5
print function_table["my_subtraction_function"](1, 4)
# -3

これは、Flask が行っていることの非常に単純なバージョンです。どのパスが使用されているかに基づいて、どの関数を呼び出すかのテーブルを保存します。

于 2013-07-01T22:18:08.407 に答える
0

関数をラップすることに加えて、デコレータが他のことをできない理由はありません

>>> def print_stuff(stuff):
...     def decorator(f):
...         print stuff
...         return f
...     return decorator
...
>>> @print_stuff('Hello, world!')
... def my_func():
...     pass
...
Hello, world!

この例では、関数を定義するときにデコレーターのコンストラクターに渡された引数を単純に出力します。「Hello, world!」と出力したことに注目してください。実際に呼び出さずにmy_func- これは、デコレータ自体ではなく、デコレータを構築するときに印刷が発生するためです。

何が起こっているかとapplication.routeいうと、それ自体はデコレータではありません。むしろ、ルートを取り、ビュー関数に適用されるデコレータを生成し、そのルートでビュー関数を登録する関数です。フラスコでは、デコレーター コンストラクターはルートとビュー関数の両方にアクセスできるため、アプリケーション オブジェクトのそのルートでビュー関数を登録できます。興味がある場合は、Github の Flask ソース コードを参照してください。

https://github.com/mitsuhiko/flask/blob/master/flask/app.py

于 2013-07-01T22:12:37.133 に答える