将参数传递给SimpleHTTPRequestHandler

4
我需要向SimpleHTTPRequestHandler类传递一个参数,因此我使用了类工厂来创建自定义处理程序,如下所示。
def RequestHandlerClass(application_path):    

  class CustomHandler(SimpleHTTPRequestHandler):

    def __init__(self, request, client_address, server):

        SimpleHTTPRequestHandler.__init__(self, request, client_address, server)
        self._file_1_done = False 
        self._file_2_done = False 
        self._application_path = application_path

    def _reset_flags(self):

        self._file_1_done = False 
        self._file_2_done = False 

    def do_GET(self):

        if (self.path == '/file1.qml'):
            self._file_1_done = True  

        if (self.path == '/file2.qml'):
            self._file_2_done = True 

        filepath = self._application_path + '/' + self.path  # Error here

        try:
            f = open(filepath) 
            self.send_response(200)
            self.end_headers()
            self.wfile.write(f.read())
            f.close()
        except IOError as e :
            self.send_error(404,'File Not Found: %s' % self.path)    


        if (self._file_1_done and self._file_2_done):
            self._reset_flags()  
            self.server.app_download_complete_event.set()
  return CustomHandler 

这是我的使用自定义处理程序的http服务器。
class PythonHtpServer(BaseHTTPServer.HTTPServer, threading.Thread):

  def __init__(self, port, serve_path):
    custom_request_handler_class = RequestHandlerClass(serve_path)
    BaseHTTPServer.HTTPServer.__init__(self, ('0.0.0.0', port), custom_request_handler_class)
    threading.Thread.__init__(self)
    self.app_download_complete_event = threading.Event()

  def run(self):
    self.serve_forever()

  def stop(self):
    self.shutdown()    

我使用以下命令启动服务器

http_server = PythonHtpServer(port = 8123, serve_path = '/application/main.qml')

服务器已经启动,但我收到了这个错误提示。
AttributeError: CustomHandler instance has no attribute '_application_path'

基本上,从错误信息中可以得知服务器已经启动,但我不知道为什么它没有创建属性(或init方法没有被调用)。请告诉我我做错了什么。任何帮助都将受到欢迎。

3个回答

3

我认为最简单的方法是将_application_path作为该类的静态属性。它仅在类声明时声明,并且可以被该类的实例透明地使用:

def RequestHandlerClass(application_path):    

  class CustomHandler(SimpleHTTPRequestHandler):

    _application_path = application_path   # static attribute

    def __init__(self, request, client_address, server):

        SimpleHTTPRequestHandler.__init__(self, request, client_address, server)
        self._file_1_done = False 
        self._file_2_done = False 

    def _reset_flags(self):
        ...

这样,每个自定义处理程序类的新实例都可以通过 self._application_path 访问应用程序路径。


0

这里的问题是BaseHttpRequestHandler(以及其子类SimpleHttpRequestHandler)从未离开其__init__方法:

因此,如果您想将信息传递给处理程序,则必须在调用超级__init__之前执行此操作。我可能为时已晚,无法帮助您,但对于未来的读者,您可以只需切换__init__的顺序即可:

class CustomHandler(http.server.SimpleHTTPRequestHandler):

  def __init__(self, *args, **kwargs):
    self._file_1_done = False 
    self._file_2_done = False
    self._application_path = application_path
    super().__init__(*args, **kwargs)

我可能会使用functools.partial而不是将整个内容包装在一个函数中:

class CustomHandler(http.server.SimpleHTTPRequestHandler):

  def __init__(self, application_path, *args, **kwargs):
    self._file_1_done = False 
    self._file_2_done = False
    self._application_path = application_path
    super().__init__(*args, **kwargs)

...

custom_request_handler_class = functools.partial(CustomHandler, serve_path)
BaseHTTPServer.HTTPServer(('0.0.0.0', port), custom_request_handler_class)

通常情况下,在你的初始化函数结尾处调用super().__init__可能不是一个好主意(因为它可能会搞乱初始化),但在这里似乎Python有点逼你这么做。


0
从概念上讲,您编写了类似于以下内容的代码(在此示例中,application_path ~= var):
def createClass(var):
    class MyClass:
        def __init__(self):
            self.var = var
        def func(self):
            # use var in some way
            print (self.var)
    # Return class definition
    return MyClass

因此,这个类被编写来在创建MyClass实例时保存变量var。然而,当函数完成时,变量被销毁了,并且由于该类仅返回一个类定义而不是一个类实例,因此在原始变量var被销毁之前,MyClass的实例并没有被创建,因此变量var实际上从未被MyClass保存。

相反,您可以将var作为参数添加到MyClass.__init__函数中,并创建一个生成器类来处理MyClass实例的创建,如下所示:

class MyClass:
    def __init__(self, arg1, arg2, var):
        (self.arg1, self.arg2, self.var) = (arg1, arg2, var)
    # Insert other methods as usual

class MyClassGenerator:
    def __init__(self, var):
        self.var = var
    def make(self, arg1, arg2):
        return MyClass(arg1, arg2, var)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接