2017-02-09 50 views
0

這讓我一陣頭痛。我正在嘗試創建一個非常簡單的類似REST的界面(不使用第三方庫,我知道這些庫是可用的)。Python - 從一個類中訪問「導入」

其背後的想法是,我可以有一個目錄,例如mylib,在那裏我可以在Python的文件拖放,像do_something.py,並通過張貼到http://localhost/do_something代碼將春天到生活,做一些事情!

我想我已經成功地附近的某個地方讓我的結構如下目標:是 Project folder contains example.py and a folder called mylib, which contains a file called init.py and my_module.py

文件的內容如下。

example.py 
from http.server import HTTPServer 
from http.server import BaseHTTPRequestHandler 
import json, logging 
from mylib import my_module 

class MyRequestHandler (BaseHTTPRequestHandler): 

    # Send JSON responses 
    # ----------- 
    def send_json(self, json_message, response_code=200): 
     self.send_response(response_code) 
     self.send_header('Content-type', 'application/json') 
     self.end_headers() 
     self.request.sendall(json.dumps(json_message).encode()) 


    # Get JSON requests 
    # ---------- 
    def get_json(self): 
     body = self.rfile.read(int(self.headers.get('Content-Length'))) 
     if (body): 
      try: 
       receivedData = json.loads(body.decode()) 
      except: 
       self.send_json({"Status": "Error", "Message": "Invalid JSON received"}, 400) 
       receivedData = None 
     else: 
      receivedData = None 
     return receivedData 


    # POST 
    # --------- 
    def do_POST(self): 

     module_to_call = (self.path).replace('/', '.')[1:] 
     if module_to_call.endswith('.'): # Remove trailing dot 
      module_to_call = module_to_call[:-1] 
     print("Path is: '" + module_to_call + "'") 

     # invoke function 
     module_to_call = getattr(self, module_to_call) 
     response = module_to_call() 
     self.send_json(response) 

    # GET 
    # -------- 
    def do_GET(self): 

     pass 


# ----------------------------------------------------------------------------- 
# Server startup code 
# ------------------- 
def start_server(): 


# Begin serving 
# ------------- 
    port = 8003 
    server = HTTPServer(('', port), MyRequestHandler) 
    print(("Server now running on port {0} ...").format(port)) 

    server.serve_forever() 


# ----------------------------------------------------------------------------- 
# Start the Server 
# ---------------- 
if __name__ == '__main__': 
    start_server() 

my_module.py

def my_module(): 
    print("Hello World!") 
    return{'Greeting': 'Hello World!'} 

當我火起來的服務器,並嘗試張貼到http://localhost:8003/my_module,我得到下面的輸出:

Server now running on port 8003 ... 
Path is: 'my_module' 
---------------------------------------- 
Exception happened during processing of request from ('127.0.0.1', 59541) 
Traceback (most recent call last): 
    File "C:\Users\Test\AppData\Local\Programs\Python\Python35-32\lib\socketserver.py", line 313, in _handle_request_noblock 
    self.process_request(request, client_address) 
    File "C:\Users\Test\AppData\Local\Programs\Python\Python35-32\lib\socketserver.py", line 341, in process_request 
    self.finish_request(request, client_address) 
    File "C:\Users\Test\AppData\Local\Programs\Python\Python35-32\lib\socketserver.py", line 354, in finish_request 
    self.RequestHandlerClass(request, client_address, self) 
    File "C:\Users\Test\AppData\Local\Programs\Python\Python35-32\lib\socketserver.py", line 681, in __init__ 
    self.handle() 
    File "C:\Users\Test\AppData\Local\Programs\Python\Python35-32\lib\http\server.py", line 422, in handle 
    self.handle_one_request() 
    File "C:\Users\Test\AppData\Local\Programs\Python\Python35-32\lib\http\server.py", line 410, in handle_one_request 
    method() 
    File ".\example.py", line 43, in do_POST 
    module_to_call = getattr(self, module_to_call) 
AttributeError: 'MyRequestHandler' object has no attribute 'my_module' 
---------------------------------------- 

這是非常合情合理的,因爲' MyRequestHandler「沒有屬性」my_module「!我無法纏住我的頭,是如何解決這個問題的?

我應該將「mylib」傳遞給MyRequestHandler嗎?我是否應該在課堂上進行導入(但是這個功能只能在課堂上使用)?我試圖讓事情保持簡潔,甚至是一個Python新手(就像我似乎是!)只需編寫一個獨立的腳本,將其放入「mylib」,並且所有內容「正常工作」。新手可以訪問他們的腳本的網址,並讓它神奇地運行。

任何幫助或建議將受到感謝。

+1

由於您將模塊導入到腳本的全局範圍內,因此可以使用globals()[module_to_call]'從任何函數內部訪問它。但是,這不是你真正想要的,因爲你手動導入'my_module',如果有人丟棄一個新文件,它不會「正常工作」。 – kazemakase

+0

我不知道你想要做什麼的用例,但我建議你不要重新發明輪子,而是使用輕量級框架(例如Flask),因爲這就是你將要結束的無論如何。 – yedpodtrzitko

+2

[Python中的動態模塊導入]的可能重複(http://stackoverflow.com/questions/301134/dynamic-module-import-in-python) – kazemakase

回答

2

使用__import__()方法:

temp = __import__('mylib', globals(), locals(), ['module_to_call'], -1) 
response = temp.module_to_call() 

我用2.6的工作,而這通常是用來使用甚至2.7的,因爲導入庫模塊是遠遠3更健壯如果使用3即可做到以下幾點:

from importlib import import_module 

temp = import_module('mylib') 

,但現在你必須使用GETATTR得到你想要被調用的函數

func_to_call = getattr(temp, 'module_to_call') 
response = func() 

或者你可以在另一個模塊中有一個函數字典,但是隨着字典的增長,這將需要很多工作。

+0

雖然我喜歡這個答案,我也有點警惕它,因爲我的印象是使用'__import__'有點爭議。例如http://stackoverflow.com/a/26476048/1798547 –

+1

@LesterBurnham增加了一些答案,所以你可以看到其他方式。這在很多圖書館很常見。 –