我正在尝试基于Python中的字符串调用方法,类似于Tornado基于URL路由请求的方式。所以例如,如果我有字符串“/ 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的路由功能?
答案 0 :(得分: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的部分内容保存为命名或位置组。例如,请查看django,python-routes是如何做到的。
希望有所帮助。
答案 1 :(得分: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()