【问题标题】:BaseHTTPRequestHandler with custom instanceBaseHTTPRequestHandler 与自定义实例
【发布时间】:2013-08-28 23:00:22
【问题描述】:

这是我的 http 服务器:

from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer

class test:
    def show(self):
        return "aaaa"

class http_server:
    def __init__(self, t1):
        self.t1 = t1
        server = HTTPServer(('', 8080), myHandler)
        server.serve_forever()

class myHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type','text/html')
        self.end_headers()
        self.wfile.write(self.t1.show()) #Doesnt work
        return

class main:
    def __init__(self):
        self.t1 = test()
        self.server = http_server(self.t1)

if __name__ == '__main__':
    m = main()

我需要访问 myHander 中的实例 t1。

有什么办法吗?

谢谢!

【问题讨论】:

    标签: python httpserver basehttpserver requesthandler basehttprequesthandler


    【解决方案1】:

    稍微好一点的版本,每个实例的 t1 都不相同。

    from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
    
    class test:
        def show(self):
            return "aaaa"
    
    class http_server:
        def __init__(self, t1):
            def handler(*args):
                myHandler(t1, *args)
            server = HTTPServer(('', 8080), handler)
            server.serve_forever()
    
    class myHandler(BaseHTTPRequestHandler):
        def __init__(self, t1, *args):
            self.t1 = t1
            BaseHTTPRequestHandler.__init__(self, *args)
    
        def do_GET(self):
            self.send_response(200)
            self.send_header('Content-type','text/html')
            self.end_headers()
            self.wfile.write(self.t1.show()) #Doesnt work
            return
    
    class main:
        def __init__(self):
            self.t1 = test()
    
            self.server = http_server(self.t1)
    
    if __name__ == '__main__':
        m = main()
    

    【讨论】:

    • 嗨,我不明白处理程序是如何工作的,你能解释一下吗?该函数只是创建一个 myHandler 的实例,但它不返回任何内容。谢谢
    • @Francesco 为了更好的可读性,返回语句是有意义的。然而,事实证明,HTTPServer 类只是调用处理函数,并不关心它的返回值。所以不返回任何东西仍然有效。如果您查看“class BaseServer”(HTTPServer 的基类)——finish_request 方法只调用传递的 RequestHandlerClass(同时将 ref 传递给自身),并且不关心来自此类的响应。所以上面的代码有效:-)
    • 更准确地说,因为这引起了我一分钟的注意,HTTPServer 实例化处理程序而不是调用它(实际上是通过调用Handler(args_to_init)) .因为@rsmoorthy 的handler 函数像处理程序的常规实例化一样嘎嘎叫,所以HTTPServer 可以用它“实例化”它,即使它实际上只是调用handler 函数。我在下面添加了另一个答案,但使用functools.partial 希望增加清晰度
    【解决方案2】:

    有一种方法是将属性设置为类:

    from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
    
    class test:
        def show(self):
            return "aaaa"
    
    class http_server:
        def __init__(self, t1):
            myHandler.t1 = t1
            server = HTTPServer(('', 8080), myHandler)
            server.serve_forever()
    
    class myHandler(BaseHTTPRequestHandler):
        t1 = None
        def do_GET(self):
            self.send_response(200)
            self.send_header('Content-type','text/html')
            self.end_headers()
            self.wfile.write(self.t1.show()) #Doesnt work
            return
    
    class main:
        def __init__(self):
            self.t1 = test()
    
            self.server = http_server(self.t1)
    
    if __name__ == '__main__':
        m = main()
    

    您必须小心,您使用 myHandler 的每个地方都将是 t1 的同一个实例

    【讨论】:

    • 现在这救了我的命!在不覆盖 init 方法的情况下实例化类要简单得多(至少目前如此),然后设置 handler.t1 = value
    • 我从没想过要使用静态类成员。相反,我浪费了一个多小时来搜索如何访问HTTPServer 在内部创建的实例(基于您作为处理程序传递给它的类)。不用说,它演变成了一个典型的先有鸡还是先有蛋的问题——处理程序的构造函数需要服务器的实例,而在服务器类之外创建处理程序时显然不存在该实例。 XD
    • @Philippe T. 刚刚挽救了另一个生命!顺便说一句,从代码中删除#Doesnt work 注释。
    【解决方案3】:

    我知道我回答得很晚,但这可能对未来的观众有所帮助。访问t1 有一种非常简单的方法,就像使用BaseHTTPRequestHandler 对象的server 变量一样:

    from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
    
    class test:
        def show(self):
            return "aaaa"
    
    class http_server:
        def __init__(self, t1):
            server = HTTPServer(('', 8080), myHandler)
            server.t1 = t1
            server.serve_forever()
    
    class myHandler(BaseHTTPRequestHandler):
        def do_GET(self):
            self.send_response(200)
            self.send_header('Content-type','text/html')
            self.end_headers()
            self.wfile.write(self.server.t1.show())
            return
    
    class main:
        def __init__(self):
            self.t1 = test()
            self.server = http_server(self.t1)
    
    if __name__ == '__main__':
        m = main()
    

    【讨论】:

    • 很好的答案,但我认为它应该是 http_server 构造函数中的“server.t1 = t1”而不是“self.t1 = t1”。
    • 以及 server.t1 = t1 需要在 HTTPServer() 分配之后进行
    【解决方案4】:

    这个 8 年前的问题的另一种答案:) 我也想避免使用在所有 Handler 对象之间共享的类变量以防万一,但我花了一分钟才明白为什么@rsmoorthy 的答案有效。这与他的答案基本相同,但使用functools.partial 来增加清晰度。

    由于 HTTPServer 期望处理程序为 RequestHandlerClass,因此我们无法完全实例化该类。但是我们可以给我们的子类一个自定义的__init__ 来接受额外的数据,然后使用functools.partial 为HTTPServer 填写额外的信息。这样,它只是像它想要的那样实例化我们的处理程序,但我们仍然得到 t1 内部传递。

    from http.server import BaseHTTPRequestHandler, HTTPServer
    import functools
    
    
    class test:
        def show(self):
            return b"aaaa"
    
    class http_server:
        def __init__(self, t1):
            handler_partial = functools.partial(Handler, t1=t1)
            server = HTTPServer(('', 8080), handler_partial)
            server.serve_forever()
    
    class Handler(BaseHTTPRequestHandler):
        def __init__(self, *args, t1=None, **kwargs):
            # Assign before super().__init__ because init is what triggers parsing the request
            self.t1 = t1
            super().__init__(*args, **kwargs)
    
        def do_GET(self):
            self.send_response(200)
            self.send_header('Content-type','text/html')
            self.end_headers()
            self.wfile.write(self.t1.show())
            return
    
    class main:
        def __init__(self):
            self.t1 = test()
            self.server = http_server(self.t1)
    
    if __name__ == '__main__':
        m = main()
    

    【讨论】:

      【解决方案5】:

      Aaa 和这个老问题的另一个答案,这次使用工厂函数创建 BaseHTTPRequestHandler 的子类,我们的 t1 已经可用。

      from http.server import BaseHTTPRequestHandler, HTTPServer
      
      class test:
          def show(self):
              return b"aaaa"
      
      class http_server:
          def __init__(self, t1):
              myHandler = handlerFactory(t1)
              server = HTTPServer(('', 8080), myHandler)
              server.serve_forever()
      
      def handlerFactory(t1):
          class myHandler(BaseHTTPRequestHandler):
              def do_GET(self):
                  self.send_response(200)
                  self.send_header('Content-type','text/html')
                  self.end_headers()
                  self.wfile.write(t1.show())
                  return
          return myHandler
      
      class main:
          def __init__(self):
              self.t1 = test()
              self.server = http_server(self.t1)
      
      if __name__ == '__main__':
          m = main()
      

      【讨论】:

        【解决方案6】:

        遇到了同样的问题,正在尝试关注@XaF's answer;由于酷点值低无法评论,所以在下面添加一个答案。

        在我的情况下,我将 HTTPServer 作为服务器类的“私有”成员,但没有意识到 Python 会处理“私有”成员,以便在处理程序的 server 实例中访问相应的成员实际上前面是服务器类的名称,在 OP 的示例中为 self.server._http_server__t1。所以使用self.server._<server class name>__<private member name> 而不是self.server.<member name>

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-12-24
          • 2016-05-04
          • 1970-01-01
          • 1970-01-01
          • 2015-04-09
          • 2019-05-20
          • 2013-06-19
          • 2012-07-10
          相关资源
          最近更新 更多