如何使用装饰器 (bottle.py)

How to use decorators (bottle.py)

我正在尝试使用 bottle.py 构建一些网页。似乎使用 bottle 的主要部分是学习使用装饰器,但我已经阅读了 python 文档对装饰器的解释,但我仍然不确定我是否理解它们。

文档说:

"A Python decorator is a specific change to the Python syntax that allows us to more conveniently alter functions and methods (and possibly classes in a future version)."

听起来您正在调用一个函数并进行了一些更改,但我不确定您为什么要这样做或如何阅读装饰器。

查看一些瓶子代码:

if __name__ == '__main__':
    PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
    STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static').replace('\', '/')
    HOST = os.environ.get('SERVER_HOST', 'localhost')
    try:
        PORT = int(os.environ.get('SERVER_PORT', '5555'))
    except ValueError:
        PORT = 5555

    @bottle.route('/static/<filepath:path>')
    def server_static(filepath):
        """Handler for static files, used with the development server.
        When running under a production server such as IIS or Apache,
        the server should be configured to serve the static files."""
        return bottle.static_file(filepath, root=STATIC_ROOT)

    # Starts a local test server.
    bottle.run(server='wsgiref', host=HOST, port=PORT)

这一行的作用是什么@bottle.route('/static/<filepath:path>')

如果它是一个奇特的函数调用,那么为什么要这样做而不是仅仅调用函数?

感谢您的帮助! :D

装饰器只是一个函数包装器,它需要一些可计算值并用更多可计算值包围它,从技术上讲,装饰器是一个函数,returns一个函数(或一个对象,实际上有装饰器类).

比如说你想做一个记录器装饰器,这个记录器装饰器将执行一些东西并记录谁在执行它:

def loggger(name):
    def wrapper(f):
        def retF(*args, **kwargs):
            print name, "is executing"
            f(*args, **kwargs)
        return retF
    return wrapper

所以,我们的装饰器会在调用我们想要的函数之前打印 "Daniel is executing",例如

@logger("Daniel")
def add2Nums(a,b):
    return a+b

>>> add2Nums(1,2)
>>> Daniel is executing
>>> 3

Bottle 的工作原理相同,在

@bottle.route('/static/<filepath:path>')

它只是包装您的 server_static 调用,因此每当调用路由您的函数的某些访问时。

查看此代码:

def my_decorator(func):
    return lambda: print("goodbye")

def greet():
    print('hello')

result = my_decorator(greet)
result()

--output:--
goodbye

以下是完成同样事情的捷径:

def my_decorator(func):
    return lambda: print("goodbye")

@my_decorator
def greet():
    print('hello')

greet()

--output:--
goodbye

@my_decorator 语法采用其下方的函数 greet,并进行此调用:

greet = my_decorator(greet)

必须定义 my_decorator() 函数,以便:

  1. 它接受一个函数作为参数。

  2. Return一个函数。

A Python decorator is a specific change to the Python syntax that allows us to more conveniently alter functions and methods (and possibly classes in a future version).

好吧,假设你想 add 到 greet() 函数所做的任何事情:

def my_decorator(func):  # func = greet

    def add_to_greet():
        func()   #<*********This is greet()
        print('world') #<***This is additional stuff.

    return add_to_greet

@my_decorator
def greet():
    print('hello')

greet()

--output:--
hello
world

What does this line do @bottle.route('/static/<filepath:path>')

好了,准备好了吗?如果 @some_name 语法指定了一个参数,例如:

 @wrapper('world')
 def do_stuff():

首先 python会执行下面的调用:

 @wrapper('world')
 def do_stuff():
      ...

 #****HERE:
 decorator = wrapper('world')  #decorator is a newly created variable

wrapper() 函数必须定义为:

  1. 采用任何旧参数,例如'world'
  2. Return 一个函数:
    1. 将函数作为参数。
    2. Return是一个函数。

其次,python会执行调用:

 @wrapper('world')
 def do_stuff():
     ...

 decorator = wrapper('world') 
 #*****HERE:   
 do_stuff = decorator(do_stuff) 

哇!这是一个例子:

def wrapper(extra_greeting):

    def my_decorator(func):

        def add_to_greet():
            func()
            print(extra_greeting)

        return add_to_greet

    return my_decorator


@wrapper('world')
def greet():
    print('hello')

greet()

--output:--
hello
world

现在,让我们分析一下这个装饰器:

@bottle.route('/static/<filepath:path>')
def server_static(filepath):

bottle  -- a module
route   -- a function(or other callable) defined in the bottle module
'/static/<filepath:path>'  -- a route

所以瓶子模块可能看起来像这样:

#bottle.py

def route(your_route):  #your_route <= '/static/<filepath:path>'

    def my_decorator(func):  #The decorator syntax will cause python to call this function with server_static as the argument

        def do_stuff(filepath):
            func(filepath)  #Call the server_static() function with the part of the url that matched filepath

        return do_stuff  #This function will be called when your code calls server_static(...)

    return my_decorator

If its a fancy function call then why do it this way rather than just calling the function?

高级东西。

评论: 也许你忘了解释路由装饰器具体做了什么?


@route('/hello')
def hello():
    return "Hello World!"

The route() decorator binds a piece of code to an URL path. In this case, we link the /hello path to the hello() function. This is called a route (hence the decorator name) and is the most important concept of this framework. You can define as many routes as you want. Whenever a browser requests a URL, the associated function is called and the return value is sent back to the browser. It’s as simple as that.

http://bottlepy.org/docs/dev/tutorial.html

路径可以包含通配符:

The simplest form of a wildcard consists of a name enclosed in angle brackets (e.g. <name>)....Each wildcard matches one or more characters, but stops at the first slash (/). The rule /<action>/<item> matches as follows:

Path        Result
/save/123   {'action': 'save', 'item': '123'}
/save/123/  No Match
/save/      No Match
//123       No Match

Filters are used to define more specific wildcards, and/or transform the matched part of the URL before it is passed to the callback. A filtered wildcard is declared as <name:filter>


The following standard filters are implemented:

:path matches all characters including the slash character in a non-greedy way and may be used to match more than one path segment.

http://bottlepy.org/docs/dev/routing.html