2015-04-03 43 views
4

是否有更優雅/系統/未來的證明方式來調用if __name__ == '__main__'中的所有代碼比複製/過去更好?在python中啓動SimpleHTTPServer

我正在將我的bash腳本轉換爲python。我們使用的兩個命令是python -m SimpleHTTPServer YOUR_PORTpython -m http.server YOUR_PORT

在2.x中翻譯它相當乾淨。

SimpleHTTPServer main

if __name__ == '__main__': 
    test() 

我的代碼來模擬主:

import SimpleHTTPServer 
SimpleHTTPServer.test() 

在3.x的翻譯,這是不乾淨的。

http.server main

if __name__ == '__main__': 
    parser = argparse.ArgumentParser() 
    parser.add_argument('--cgi', action='store_true', 
         help='Run as CGI Server') 
    parser.add_argument('--bind', '-b', default='', metavar='ADDRESS', 
         help='Specify alternate bind address ' 
          '[default: all interfaces]') 
    parser.add_argument('port', action='store', 
         default=8000, type=int, 
         nargs='?', 
         help='Specify alternate port [default: 8000]') 
    args = parser.parse_args() 
    if args.cgi: 
     handler_class = CGIHTTPRequestHandler 
    else: 
     handler_class = SimpleHTTPRequestHandler 
    test(HandlerClass=handler_class, port=args.port, bind=args.bind) 

我的代碼來模擬主:

import argparse 
import http.server 
from http.server import CGIHTTPRequestHandler, SimpleHTTPRequestHandler 
parser = argparse.ArgumentParser() 
parser.add_argument('--cgi', action='store_true', 
        help='Run as CGI Server') 
parser.add_argument('--bind', '-b', default='', metavar='ADDRESS', 
        help='Specify alternate bind address ' 
         '[default: all interfaces]') 
parser.add_argument('port', action='store', 
        default=8000, type=int, 
        nargs='?', 
        help='Specify alternate port [default: 8000]') 
args = parser.parse_args() 
if args.cgi: 
    handler_class = CGIHTTPRequestHandler 
else: 
    handler_class = SimpleHTTPRequestHandler 
http.server.test(HandlerClass=handler_class, port=args.port, bind=args.bind) 

回答

1

這看起來太可怕了,我不知道這是要做到這一點的最佳方式,但下面的代碼似乎啓動服務器沒有太多的困難:

import importlib 
exec(compile(importlib.util.find_spec('http.server').loader.get_source(
    'http.server'), 'server.py', 'exec'), dict(__name__='__main__')) 

更新1:啓動http.server模塊的下一個想法可能沒有多大好處,但它直接利用了http.server模塊,而不必處理importlib模塊。 。

import http.server 
exec(compile(http.server.__loader__.get_source(http.server.__name__), 
      http.server.__file__, 'exec'), dict(__name__='__main__')) 

當然,這可能只是意味着它會更好地創建處理在任何情況下,我們要在運行它們執行模塊效用函數的

import sys 

nvl = lambda value, other: other if value is None else value 

def exec_module(module, globals=None, locals=None): 
    frame = sys._getframe(1) 
    globals = nvl(globals, {}) 
    globals.update(frame.f_globals) 
    locals = nvl(locals, {}) 
    locals.update(frame.f_locals) 
    exec(compile(module.__loader__.get_source(module.__name__), 
       module.__file__, 'exec'), globals, locals) 

# this is how you would use the code up above 

import http.server 

exec_module(http.server, dict(__name__='__main__')) 

更新2:exec_module功能可能應該更像下面的內容,但由於某些原因未能引起我的注意,它似乎沒有按預期工作:

def exec_module(module, globals=None, locals=None): 
    frame = sys._getframe(1) 

    exec_globals = nvl(globals, {}) 
    copy_globals = exec_globals.copy() 
    exec_globals.update(frame.f_globals) 
    exec_globals.update(copy_globals) 

    exec_locals = nvl(locals, {}) 
    copy_locals = exec_locals.copy() 
    exec_locals.update(frame.f_locals) 
    exec_locals.update(copy_locals) 

    exec(compile(module.__loader__.get_source(module.__name__), 
       module.__file__, 'exec'), exec_globals, exec_locals) 

這些更改考慮了兩件事情。首先,如果調用者希望在函數運行後檢查它們的狀態,則保留對全局變量和本地變量的引用。其次,來自調用者的全局變量和本地變量不能覆蓋已通過的全局變量和當地變量中已設置的任何值。

+0

oof。這很聰明!但是,正如你所暗示的那樣,我希望能夠提供一點解決方案。 – 2015-04-03 16:30:46

+0

@StevenWexler有一種替代解決方案完全避免了「importlib」模塊。此外,第二個設計被細化爲一個效用函數,對於用Python編寫的任何模塊可能都是有用的。 – 2015-04-03 17:01:26

+0

我喜歡'exec_module'! – 2015-04-03 17:12:01