3

Tornado が URL に基づいてリクエストをルーティングする方法と同様に、Python で文字列に基づいてメソッドを呼び出そうとしています。たとえば、"/hello" という文字列がある場合、あるクラスでメソッド "hello" を呼び出したいとします。私はPython Routesを見てきましたが、次の解決策を思いつきました:

from routes import Mapper

class Test():
    def hello(self):
        print "hello world"

map = Mapper()
map.connect(None, '/hello', controller=Test(), action='hello')

match = map.match("/hello")
if match != None:
    getattr(match['controller'], match['action'])()

ただし、文字列の一部を引数としてメソッドに渡す機能を追加したいと思います。たとえば、"hello/5" という文字列を呼び出したいとしますhello(5)(これも Tornado のルーティングと非常によく似ています)。これは、任意の数の引数に対して機能するはずです。誰かがこれに良いアプローチを持っていますか? リクエスト URL ではない文字列に対して Tornado のルーティング機能を使用することはできますか?

4

2 に答える 2

1

まず第一に、このような「ローカル」ルーティング システムを作成する動機、ユース ケース、最初のタスクが何であるかを知っておくとよいでしょう。

あなたの例に頼って、1つの方法は実際に自分で何かを構築することです。

非常に基本的な例を次に示します。

class Test():
    def hello(self, *args):
        print args


urls = ['hello/', 'hello/5', 'hello/5/world/so/good']
handler = Test()

for url in urls:
    parts = url.split('/')
    method = parts[0]
    if hasattr(handler, method):
        getattr(handler, method)(*parts[1:])

プリント:

('',)
('5',)
('5', 'world', 'so', 'good')

正規表現を使用して、URL の一部を名前付きまたは位置グループとして保存することもできます。例として、 djangopython-routesがどのようにそれを行っているかを見てください。

それが役立つことを願っています。

于 2014-03-09T06:01:24.427 に答える
1

同じ考え、違う方法。コードは次のとおりです。

class Xroute(tornado.web.RequestHandler):
    def get(self,path):
        Router().get(path,self)
    def post(self,path):
        Router().post(path,self)

class Router(object):
    mapper={}
    @classmethod
    def route(cls,**deco):
        def foo(func):
            url = deco.get('url') or '/'
            if url not in cls.mapper:
                method = deco.get('method') or 'GET'
                mapper_node = {}
                mapper_node['method'] = method
                mapper_node['call'] = func
                cls.mapper[url] = mapper_node
            return func
        return foo

    def get(self,path,reqhandler):
        self.emit(path,reqhandler,"GET")

    def post(self,path,reqhandler):
        self.emit(path,reqhandler,"POST")

    def emit(self,path,reqhandler,method_flag):
        mapper = Router.mapper
        for urlExp in mapper:
            m = re.match('^'+urlExp+'$',path)
            if m:
                params = (reqhandler,)
                for items in m.groups():
                    params+=(items,)
                mapper_node = mapper.get(urlExp)
                method = mapper_node.get('method')
                if method_flag not in method:
                    raise tornado.web.HTTPError(405)
                call = mapper_node.get('call')
                try:
                    call(*params)
                    break
                except Exception,e:
                    print e
                    raise tornado.web.HTTPError(500)
        else:
            raise tornado.web.HTTPError(404)

@Router.route(url=r"hello/([a-z]+)",method="GET")
def test(req, who):
    #http://localhost:8888/hello/billy
    req.write("Hi," + who)

@Router.route(url=r"greetings/([a-z]+)",method="GET|POST")
def test2(req, who):
    #http://localhost:8888/greetings/rowland
    test(req, who)

@Router.route(url=r"book/([a-z]+)/(\d+)",method="GET|POST")
def test3(req,categories,bookid):
    #http://localhost:8888/book/medicine/49875
    req.write("You are looking for a " + categories + " book\n"+"book No. " + bookid)

@Router.route(url=r"person/(\d+)",method="GET|POST")
def test4(req, personid):
    #http://localhost:8888/person/29772
    who = req.get_argument("name","default")
    age = req.get_argument("age",0)
    person = {}
    person['id'] = personid
    person['who'] = who
    person['age'] = int(age)
    req.write(person)

if __name__=="__main__":
    port = 8888
    application = tornado.web.Application([(r"^/([^\.|]*)(?!\.\w+)$", Xroute),])
    application.listen(port)
    tornado.ioloop.IOLoop.instance().start()
于 2014-03-14T07:16:17.680 に答える