Search code examples
pythontornado

In python's Tornado framework, instance variable and class variable confusion


I have a handler in Tornado which has a get() and post() method. The get method grabs some DB information and renders it with the html. The post method is for ajax calls once the page is loaded and needs to use the DB data collected by the get() method.

My problem is that if I set the variables that need to be shared between get() and post() as instance variables (i.e. set self.variable = "foobar" in get() method), then the post() method does not recognize that those instance variables exist. The only workaround I've found is if I set those variables as global class variables and reset them with MyHandler.variable = "foobar" in get(). But this seems like a hackish solution.

Works:

class AdminHandler(BaseHandler):

file_count = 0
mw_count = 0
bw_count = 0
unknown_count = 0
files = []
origins = {}
file_dicts = []

def get(self): 
    AdminHandler.file_count = 0
    AdminHandler.mw_count = 0
    AdminHandler.bw_count = 0
    AdminHandler.unknown_count = 0
    AdminHandler.files = []
    AdminHandler.origins = {}
    AdminHandler.file_dicts = []

    .... 

def post(self):
    (access class variables)
    ....

Does not work:

class AdminHandler(BaseHandler):

def get(self): 
    self.file_count = 0
    self.mw_count = 0
    self.bw_count = 0
    self.unknown_count = 0
    self.files = []
    self.origins = {}
    self.file_dicts = []

    .... 

def post(self):
    (access instance variables)
    ....

Solution

  • If information that you want to store must be available for all requests (not per user..) then you can implement a class that will hold this information for you. For example:

    from threading import Lock 
    class MyDataStore:
    
      _instance = None
      _lock = Lock()
    
      @classmethod
      def instance(cls):
          with cls._lock:
              if cls._instance is None:
                  cls._instance = MyDataStore()
              return cls._instance
    
      def store_data(self, file_count, mw_count, ...):
          self.file_count = file_count
          self.mw_count = mw_count
    
            .......
    MyDataStore.instance().store_data(file_count, mw_count)
    

    In this way you will have only one instance of your store class that will hold information for you.

    Instead of store_data method you can implement your own method which will process your required information (You can do it by using init method). Also you can add a method which will tell you if data already exists or is it required to update it.

    In case you need to save data individually for each user you can create a separate class UserDataStore in way I wrote before but without lock and instance() methods. For example:

    class UserDataStore:
    
      def __init__(self, user_id, file_count, mw_count, ....):
          self.user_id = user_id
          self.file_count = file_count
          self.mw_count = mw_count
    
          .........
    

    In this way you will have different instances for each user.

    Another solution that you can use is to use Redis to store your data. Just store your data dictionary under key 'db_data' and retrieve it whenever you want. (In case of data by users you can use key 'db_data:').