Python generate custom class and add custom method

  Recently, I am going to be a simple web server and implement a custom API by configuring properties such as url method header. The framework considers Tornado and PyRestful. Then there is a problem, the number of APIs is dynamically generated, and the request method of each API is different. If pure PyRestful is not enough.

import pyrestful.rest
import tornado.ioloop
from pyrestful import mediatypes
from pyrestful.rest import get, post

class Book(object):
    isbn = int
    title = str

class BookResource(pyrestful.rest.RestHandler):
    @get(_path="/books/json/{isbn}", _types=[int], _produces=mediatypes.APPLICATION_JSON)
    def getBookJSON(self, isbn):
        book = Book()
        book.isbn = isbn
        book.title = "My book for isbn " + str(isbn)

        return book
  

  Therefore, it is necessary to dynamically generate the method of class and claas. Fortunately, Python has a corresponding syntax: Metaclass

  Override the __new__(cls, name, bases, attrs) method by inheriting type

class RestHandleMetaclass(type):    

    def __new__(cls, name, bases, attrs):
	    # do something ,such as redefinition attrs
	    # ps: attr is a tuple
        return type.__new__(cls, name, (RestHandler,), attrs)

 

  Then I encountered the second problem, how to add @get(_path="/books/json/{isbn}", _types=[int], _produces=mediatypes.APPLICATION_JSON) to the method. At first, I thought the @ symbol was an annotation, and I took a lot of detours. Later, I learned that @ is used to deal with Decorators in Python. (Reference: A B ). Since the element in attrs is a method, how to generate a method, which has been processed by the decorator, can modify the parameters in @get(), and finally return a method becomes the third problem. Fortunately pyrestful.rest.get inspired me

def get(*params, **kwparams):
	""" Decorator for config a python function like a Rest GET verb	"""
	def method(f):
		return config(f,'GET',**kwparams)
	return method

  Method in Python can define Method and return Method. At the same time, after trying, it is found that the internally defined Method can be added with @get, and finally returns to the method after the decorator is processed.

class RestHandleMetaclass(type):
    @staticmethod
    def dynamicDecorator(data):
        _path = "/books/json/" + str(data) + "/{isbn}"
        _types = [int]
        _produces = mediatypes.APPLICATION_JSON

        @get(_path=_path, _types=_types, _produces=_produces)
        def getBookJSON(self, isbn):
            book = Book()
            book.isbn = isbn
            book.title = "My book for isbn " + str(isbn)
            return book

        return getBookJSON

    def __new__(cls, name, bases, attrs):
        for x in range(5):
            attrs["getBookIsbn_" + str(x)] = RestHandleMetaclass.dynamicDecorator(x)
        return type.__new__(cls, name, (RestHandler,), attrs)

  Finally add the relevant code.

class TestA(object, metaclass=RestHandleMetaclass):
    pass

if __name__ == '__main__':
    try:
        print("Start the service")
        app = pyrestful.rest.RestService([TestA])
        app.listen(8080)
        tornado.ioloop.IOLoop.instance().start()
    except KeyboardInterrupt:
        print("\nStop the service")


    

  


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325926027&siteId=291194637