在WSGI / Python中分配方法

时间:2015-06-28 18:32:46

标签: wsgi werkzeug

您好我正在审核Werkzeug tutorial,我对此声明感到有些困惑:app.wsgi_app = SharedDataMiddleware(app.wsgi_app, { '/static': os.path.join(os.path.dirname(__file__), 'static') })

包含在内部:

class Shortly(object):

    def __init__(self, config):
        self.redis = redis.Redis(config['redis_host'], config['redis_port'])

    def dispatch_request(self, request):
        return Response('Hello World!')

    def wsgi_app(self, environ, start_response):
        request = Request(environ)
        response = self.dispatch_request(request)
        return response(environ, start_response)

    def __call__(self, environ, start_response):
        return self.wsgi_app(environ, start_response)


def create_app(redis_host='localhost', redis_port=6379, with_static=True):
    app = Shortly({
        'redis_host':       redis_host,
        'redis_port':       redis_port
    })
    if with_static:
        app.wsgi_app = SharedDataMiddleware(app.wsgi_app, {
            '/static':  os.path.join(os.path.dirname(__file__), 'static')
        })
    return app

那里发生了什么?为什么将app.wsgi_app分配给SharedDataMiddleware返回的内容?我的意思是,不是app.wsgi_app只是一个方法名吗?

任何见解将不胜感激:)谢谢!

1 个答案:

答案 0 :(得分:0)

TL; DR 在此示例中,通过使用Shortly对象包装其入口点,将额外的功能添加到SharedDataMiddleware应用。

长解释

app.wsgi_app不是方法名称。它是对该方法的参考。由于Python是非常动态的语言,因此可以在创建此对象后替换任何对象的方法。

让我们考虑一个简单的例子:

class App:
    def run(self, param):
        print(param)

app = App()
app.run('foo')  # prints 'foo'        

original_run = app.run  # save a reference to the original run method

def run_ex(param):
    print('run_ex')      # add our extra functionality
    original_run(param)  # call the original one

app.run = run_ex
app.run('foo')  # prints 'run_ex' and then 'foo'

因此,通过这种方式,可以使用常规函数轻松替换app的方法run

现在,让我们回到Werkzeug。如您所知WSGI specification,应用程序必须是具有特定签名的可调用Shortly wsgi_app方法是理想的可调用方法。但是,有人希望通过Shortly中间件向SharedDataMiddleware应用添加额外的功能。如果你look closer,那么你会发现它是一个使用__call__方法的常规课程。因此,可以调用SharedDataMiddleware类的所有对象。

middleware = SharedDataMiddleware(...)  # create an object
middleware(...)  # call the object. It can be slightly confusing at a first glance

因此,现在您可以看到SharedDataMiddleware的任何对象本身都是WSGI个应用程序。既然您已经知道如何替换app的主要方法wsgi_app,那么您唯一需要做的就是存储对原始方法Shortly.wsgi_app的引用能够以后再打电话。通过将其传递给SharedDataMiddleware构造函数来完成。