0

I am working on a Django project and have some instances of a class. I cached instance A with key 'A', and create a new instance B in another request. The thing is instance B now has data of instance A. When I change instance B's data and get instance 'A' from cache, instance A's data changes too.

I guess this has something to do with python's reuse mechanism. Anyone know how to fix this problem?

Edit 1: This is how I create a class using its name:

def create_model_by_name(name):
    name = name.capitalize()
    klass = globals()[name]
    instance = klass()
    return instance

I use django.core.cache.cache to cache objects.

This is some data I store in my class. I have some classes inherited from Abstract.

class Abstract:
    class_name = 'unknown'
    prev_text = []
    props = {}
    waiting_state = ''
    output = ''
    props_alias = {}

2 Answers2

1

Here:

class Abstract:
    class_name = 'unknown'
    prev_text = []
    props = {}
    waiting_state = ''
    output = ''
    props_alias = {}

all those attributes are class attributes - they belong to the class itself, not instances, and are shared amongst all instances of the class (unless shadowed by an instance attribute).

If you want instance attributes, you have to define them in the __init__ method, ie:

class Abstract:
    def __init__(self):
        self.class_name = 'unknown'
        self.prev_text = []
        self.props = {}
        self.waiting_state = ''
        self.output = ''
        self.props_alias = {}

Trying to use Django if you don't properly learn Python first might prove to be very frustrating, and assuming that Python's object model is anything like Java or PHP is a sure way to disaster. So do yourself a favour and learn Python first.

bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118
  • Thanks. I have just switched from C++ to python and this is my first project. Maybe that's my problem. Thank you for pointing this out for me. I think you are right that I should learn python more carefully. Thank you again. – duy_sau_rom Aug 01 '18 at 16:51
0

I suppose your problems are things like prev_text = [], props_alias = {} since these lists and dicts are shared across all instances. Try to move them into __init__ method like:

class Abstract:
    class_name = 'unknown'
    prev_text = None
    props = None
    waiting_state = ''
    output = ''
    props_alias = None

    def __init__(self):
        self.prev_text = []
        self.props = {}
        self.props_alias = {}
Andrii Zarubin
  • 2,165
  • 1
  • 18
  • 31
  • Having both a class and and instance attributes by the same name is confusing at best. If you want something to be an instance attribute, only define it as an instance attribute. – bruno desthuilliers Aug 01 '18 at 11:09
  • Listing attributes as class properties is useful because of two reasons: 1. it becomes clear what's used in the class so you don't need to read through the methods 2. you won't get attribute error, thus, going forward, you can check your attrs like `if self.prev_text is not None` rather than `hasattr(self, 'prev_text')` which is much cleaner. – Andrii Zarubin Aug 01 '18 at 11:13
  • "1. it becomes clear what's used in the class so you don't need to read through the methods" => False. What every pythoneer expects is to have instance attributes defined in the initializer, and class attributes defined at the class level. Your "solution" only makes things confusing, and forces me to double check each attribute to find out whether it's really supposed to be a class or instance attribute. – bruno desthuilliers Aug 01 '18 at 11:17
  • " 2. you won't get attribute error, thus, going forward, you can check your attrs like if self.prev_text is not None" Wrong again - if you correctly initialize your instance attributes in the initializer - which, once again, is THE proper way to define instance attributes, period -, you will NOT get any AttributeError. – bruno desthuilliers Aug 01 '18 at 11:18
  • TL;DR : you are doing it wrong and advising what is considered as a bad practice. – bruno desthuilliers Aug 01 '18 at 11:19
  • Oh and yes: in Python "property" has a very specific definition: the builtin `property` type, which is a generic descriptor providing support for one-off computed attributes. So don't use it as equivalent to "attribute", it's another source of confusion. – bruno desthuilliers Aug 01 '18 at 11:21