2017-02-09 3 views
0

Это уже раздражало меня некоторое время. Я пытаюсь создать очень простой REST-подобный интерфейс (без использования сторонних библиотек, которые, как я знаю, доступны).Python - доступ «импорт» из класса

Идея это то, что я могу иметь каталог, например mylib, где я могу упасть в питона файлов, как 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!'} 

Когда я запустим сервер и попытка POST к 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, потому что модуль importlib является гораздо более надежным в 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 немного добавил ответ, чтобы вы могли видеть другие способы. Это характерно для многих библиотек. –