2014-02-07 4 views
14
документация

Питона включает an example of creating an HTTP server:Как передать параметры RequestHandler?

def run(server_class=HTTPServer, handler_class=BaseHTTPRequestHandler): 
    server_address = ('', 8000) 
    httpd = server_class(server_address, handler_class) 
    httpd.serve_forever() 

RequestHandler класса предоставляется Server, который затем ухаживает автоматически инстанцирование обработчика.

Предположим, я хочу передать пользовательские параметры обработчику запроса при его создании. Как я могу это сделать?

В частности, я хочу передать параметры из командной строки, и доступ к sys.argv внутри класса обработчика запроса кажется излишне неуклюжим.

Похоже, что это должно быть возможно за счет переопределения частей класса Server, но я чувствую, что упускаю из виду более простое и лучшее решение.

+0

Почему не подкласс класса обработчика? – XORcist

+0

Это похоже на главный недостаток дизайна библиотеки socketserver –

ответ

12

Используйте фабрику классов:

def MakeHandlerClassFromArgv(init_args): 
    class CustomHandler(BaseHTTPRequestHandler): 
     def __init__(self, *args, **kwargs): 
      super(CustomHandler, self).__init__(*args, **kwargs) 
      do_stuff_with(self, init_args) 
    return CustomHandler 

if __name__ == "__main__": 
    server_address = ('', 8000) 
    HandlerClass = MakeHandlerClassFromArgv(sys.argv) 
    httpd = HTTPServer(server_address, HandlerClass) 
    httpd.serve_forever() 
+0

Итак, в этом случае я не буду передавать аргументы в конструктор, а где-то еще? – Jakob

+0

@Jakob Вам больше не нужно передавать аргументы, поскольку они находятся в области действия при создании класса. См. Мое редактирование. –

+0

Хорошее решение. Я думаю, что это должно быть: self.do_stuff_with_self (init_args). – arhuaco

1

Почему не просто подкласс RequestHandler?

class RequestHandler(BaseHTTPRequestHandler): 
    a_variable = None 

class Server(HTTPServer): 
    def serve_forever(self, variable): 
     self.RequestHandlerClass.a_variable = variable 
     HTTPServer.serve_forever(self) 

def run(server_class=Server, handler_class=RequestHandler): 
    server_address = ('', 8000) 
    httpd = server_class(server_address, handler_class) 
    variable = sys.argv 
    httpd.serve_forever(variable) 
+0

У меня уже есть подкласс RequestHandler. Могу ли я передать ему аргументы командной строки без hardcoding 'sys.argv'? Это очень сильно сочетает класс с глобальными переменными и аргументами командной строки сценария (например, уменьшая тестируемость). – Jakob

+0

На самом деле, я пропустил ваше использование 'sys.argv' в этом примере. Я более подробно рассмотрю этот метод и попробую его. – Jakob

+0

Да, вы можете. Возможно, вам стоит заглянуть в многопроцессорную библиотеку. То, что я делал в прошлом (не для аргументов командной строки, но, я думаю, вы могли бы сделать что-то подобное), создает очередь Queue(), которая совместно используется процессом RequestHandler и main, а затем RequestHandler ждет QEvent. – plover

5

Я бы просто прокомментировать ответ Томаса Ороско, но так как я не могу .. Возможно, это поможет другим, которые также столкнулись с этой проблемой. До Python3 у Python есть классы «старого стиля», и BaseHTTPRequestHandler кажется одним из них. Таким образом, завод должен выглядеть

def MakeHandlerClassFromArgv(init_args): 
    class CustomHandler(BaseHTTPRequestHandler, object): 
     def __init__(self, *args, **kwargs): 
      do_stuff_with(self, init_args) 
      super(CustomHandler, self).__init__(*args, **kwargs) 
    return CustomHandler 

, чтобы избежать ошибок, как TypeError: must be type, not classobj.

-2

может получить доступ к переменной уровня модуля, подобной этому.

CONFIG = None 

class MyHandler(BaseHTTPRequestHandler): 
    def __init__(self, ... 
     self.config = CONFIG  # CONFIG is now 'stuff' 

if __name__ == "__main__": 
    global CONFIG 
    CONFIG = 'stuff' 
    server_address = ('', 8000) 
    httpd = HTTPServer(server_address, MyHandler) 
    httpd.serve_forever() 

Обратитесь к Global Statement

Смежные вопросы