如何扩展 python3 BaseHTTPRequestHandler class 以便可以使用成员变量调用函数
How to extend python3 BaseHTTPRequestHandler class so that can call function with member variable
我正在尝试使用我自己的成员变量扩展 BaseHTTPRequestHandler。我将这些成员变量传递给自由函数但是当我这样做时我得到:
Exception happened during processing of request from ('127.0.0.1', 30006)
Traceback (most recent call last):
File "c:\Python37\lib\socketserver.py", line 313, in _handle_request_noblock
self.process_request(request, client_address)
File "c:\Python37\lib\socketserver.py", line 344, in process_request
self.finish_request(request, client_address)
File "c:\Python37\lib\socketserver.py", line 357, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "fruiterer.py", line 41, in __init__
BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
File "c:\Python37\lib\socketserver.py", line 712, in __init__
self.handle()
File "c:\Python37\lib\http\server.py", line 426, in handle
self.handle_one_request()
File "c:\Python37\lib\http\server.py", line 414, in handle_one_request
method()
File "fruiterer.py", line 62, in do_POST
fruit_handler(val, Event_dictionary_list, cached_timestamp)
NameError: name 'Event_dictionary_list' is not defined
这里是 python3 源代码:
# sample python HTTP POST handler
__metaclass__= type
from http.server import BaseHTTPRequestHandler, HTTPServer
import os
import time
import threading
import requests
import json
def calculate(Event_dictionary_list, cached_timestamp):
# do a calculation here based on fruits in Event_dictionary_list
print("there are: %i items" % len(Event_dictionary_list))
Event_dictionary_list.clear() #- empty Event_dictionary_list
cached_timestamp = 0
def Async_func(Event_dictionary_list, cached_timestamp):
calculate(Event_dictionary_list, cached_timestamp)
def fruit_handler(event, Event_dictionary_list, cached_timestamp):
if not Event_dictionary_list: #Checking if Event_dictionary_list is empty
# cache first item added
cached_timestamp = event['timestamp']
#- set a 30 second timer
threading.Timer(60,Async_func, Event_dictionary_list, cached_timestamp).start()
# make decision as to when to calculate
if event['timestamp'] - cached_timestamp < 60*1000: #- in milliseconds
# append event to list
Event_dictionary_list.append(event)
#############################################################################################################
# we create a server to handle POST requests from Xovis
class fruiterer(BaseHTTPRequestHandler):
def __init__(self, *args, **kwargs):
BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
self.Event_dictionary_list = []
self.cached_timestamp = 0
# we only need to support he POST http method
def do_POST(self):
#print("post msg received");
self.data_string = self.rfile.read(int(self.headers['Content-Length']))
self.send_response(200) # 200 = success - thanks for message response
#self.send_header() #'Content-type','text-html')
self.end_headers()
data = json.loads(self.data_string)
# we assume json will be decoded as object, eg:
# {"fruit":{"timestamp":1538688902037,"name":"apple","colour":"red","weight":100}}
if type(data) is dict:
for key, val in data.items():
# we are only interested in fruits
if key == "fruit":
fruit_handler(val, Event_dictionary_list, cached_timestamp)
break
return
def run():
print('http server is starting...')
# change port to listen on here - arbitrarily using port 7777
port = 7777
server_address = ('127.0.0.1', port)
#use the code from here .start()
httpd = HTTPServer(server_address, fruiterer)
print('http server is listening on port %d' % port)
httpd.serve_forever()
if __name__ == '__main__':
run()
这可以通过在 POST 正文中发送以下 json 格式来测试:
{"fruit":{"timestamp":1538688902037,"name":"apple","colour":"red","weight":100}}
我做错了什么?
您需要从 do_POST()
方法中传入 self.Event_dictionary_list
,而不是 Event_dictionary_list
。这同样适用于 cached_timestamp
.
然后您会发现您将在 self.Event_dictionary_list
上获得 AttributeError
,因为该属性从未在您的 __init__
方法中设置。文档对此有点含糊,但调用 BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
会触发单个请求的处理,因此该方法不会 return 直到 在 请求处理程序之后已经完成了。
将那些属性的设置移动到之前你调用基础__init__
方法:
class fruiterer(BaseHTTPRequestHandler):
def __init__(self, *args, **kwargs):
self.Event_dictionary_list = []
self.cached_timestamp = 0
super().__init__(*args, **kwargs)
我在这里使用了 super().__init__()
语法以允许将来进一步的合作继承。如果你真的愿意,你仍然可以使用 BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
,但上面的内容不那么冗长。
请注意每个单独的请求 self.Event_dictionary_list = []
是 运行。
如果此对象在您的 Python 程序(与服务器 运行ning 一起)期间应存在,请改为将其设为 class 属性:
class fruiterer(BaseHTTPRequestHandler):
Event_dictionary_list = []
cached_timestamp = 0
另一个问题是在其他函数中将 cached_timestamp
设置为 cached_timestamp = ...
只会改变局部变量。整数是不可变对象,因此您只能将新整数赋值给变量,但您调用的函数中的局部变量不与请求处理程序共享命名空间。
但是如果您希望该值在所有请求中保持不变,那么您可以在任何地方引用 fruiterer.cached_timestamp
并直接分配给该属性。
我正在尝试使用我自己的成员变量扩展 BaseHTTPRequestHandler。我将这些成员变量传递给自由函数但是当我这样做时我得到:
Exception happened during processing of request from ('127.0.0.1', 30006)
Traceback (most recent call last):
File "c:\Python37\lib\socketserver.py", line 313, in _handle_request_noblock
self.process_request(request, client_address)
File "c:\Python37\lib\socketserver.py", line 344, in process_request
self.finish_request(request, client_address)
File "c:\Python37\lib\socketserver.py", line 357, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "fruiterer.py", line 41, in __init__
BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
File "c:\Python37\lib\socketserver.py", line 712, in __init__
self.handle()
File "c:\Python37\lib\http\server.py", line 426, in handle
self.handle_one_request()
File "c:\Python37\lib\http\server.py", line 414, in handle_one_request
method()
File "fruiterer.py", line 62, in do_POST
fruit_handler(val, Event_dictionary_list, cached_timestamp)
NameError: name 'Event_dictionary_list' is not defined
这里是 python3 源代码:
# sample python HTTP POST handler
__metaclass__= type
from http.server import BaseHTTPRequestHandler, HTTPServer
import os
import time
import threading
import requests
import json
def calculate(Event_dictionary_list, cached_timestamp):
# do a calculation here based on fruits in Event_dictionary_list
print("there are: %i items" % len(Event_dictionary_list))
Event_dictionary_list.clear() #- empty Event_dictionary_list
cached_timestamp = 0
def Async_func(Event_dictionary_list, cached_timestamp):
calculate(Event_dictionary_list, cached_timestamp)
def fruit_handler(event, Event_dictionary_list, cached_timestamp):
if not Event_dictionary_list: #Checking if Event_dictionary_list is empty
# cache first item added
cached_timestamp = event['timestamp']
#- set a 30 second timer
threading.Timer(60,Async_func, Event_dictionary_list, cached_timestamp).start()
# make decision as to when to calculate
if event['timestamp'] - cached_timestamp < 60*1000: #- in milliseconds
# append event to list
Event_dictionary_list.append(event)
#############################################################################################################
# we create a server to handle POST requests from Xovis
class fruiterer(BaseHTTPRequestHandler):
def __init__(self, *args, **kwargs):
BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
self.Event_dictionary_list = []
self.cached_timestamp = 0
# we only need to support he POST http method
def do_POST(self):
#print("post msg received");
self.data_string = self.rfile.read(int(self.headers['Content-Length']))
self.send_response(200) # 200 = success - thanks for message response
#self.send_header() #'Content-type','text-html')
self.end_headers()
data = json.loads(self.data_string)
# we assume json will be decoded as object, eg:
# {"fruit":{"timestamp":1538688902037,"name":"apple","colour":"red","weight":100}}
if type(data) is dict:
for key, val in data.items():
# we are only interested in fruits
if key == "fruit":
fruit_handler(val, Event_dictionary_list, cached_timestamp)
break
return
def run():
print('http server is starting...')
# change port to listen on here - arbitrarily using port 7777
port = 7777
server_address = ('127.0.0.1', port)
#use the code from here .start()
httpd = HTTPServer(server_address, fruiterer)
print('http server is listening on port %d' % port)
httpd.serve_forever()
if __name__ == '__main__':
run()
这可以通过在 POST 正文中发送以下 json 格式来测试:
{"fruit":{"timestamp":1538688902037,"name":"apple","colour":"red","weight":100}}
我做错了什么?
您需要从 do_POST()
方法中传入 self.Event_dictionary_list
,而不是 Event_dictionary_list
。这同样适用于 cached_timestamp
.
然后您会发现您将在 self.Event_dictionary_list
上获得 AttributeError
,因为该属性从未在您的 __init__
方法中设置。文档对此有点含糊,但调用 BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
会触发单个请求的处理,因此该方法不会 return 直到 在 请求处理程序之后已经完成了。
将那些属性的设置移动到之前你调用基础__init__
方法:
class fruiterer(BaseHTTPRequestHandler):
def __init__(self, *args, **kwargs):
self.Event_dictionary_list = []
self.cached_timestamp = 0
super().__init__(*args, **kwargs)
我在这里使用了 super().__init__()
语法以允许将来进一步的合作继承。如果你真的愿意,你仍然可以使用 BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
,但上面的内容不那么冗长。
请注意每个单独的请求 self.Event_dictionary_list = []
是 运行。
如果此对象在您的 Python 程序(与服务器 运行ning 一起)期间应存在,请改为将其设为 class 属性:
class fruiterer(BaseHTTPRequestHandler):
Event_dictionary_list = []
cached_timestamp = 0
另一个问题是在其他函数中将 cached_timestamp
设置为 cached_timestamp = ...
只会改变局部变量。整数是不可变对象,因此您只能将新整数赋值给变量,但您调用的函数中的局部变量不与请求处理程序共享命名空间。
但是如果您希望该值在所有请求中保持不变,那么您可以在任何地方引用 fruiterer.cached_timestamp
并直接分配给该属性。