Beginner question here! Some time ago, I asked this question: Parse CSV records into a list of Classes, which was also answered more technically here: How do I avoid having class data shared among instances?

I learned that, in Python classes, variables that will be defined on a per-object basis need to be declared in the __init__(self) function.

So for:

class ClassOne:
    def __init__(self, datetime):
        self.datetime = datetime
    v = []

the variable v will hold the same data for all instances of ClassOne, whereas for:

class ClassTwo:
    def __init__(self, datetime):
        self.datetime = datetime
        self.v = []

variable v holds individual data for each instance of ClassTwo.

However, in Django (which I'm learning now), I see the "normal" (more C++ like) behavior again for the variables:

class Post(models.Model):
    title = models.CharField(max_length = 255)

Here, the variable title holds individual data for each instance of Post, despite not being defined in the __init__ function.

My basic question is Why or How does title pertain to individual class objects instead of being common to every class object, as v in ClassOne is above?

If I'm understanding this right, this means that Django classes are interpreted differently than normal Python classes? However, that conclusion doesn't make sense...

I hope that someone can help me understand this. It was my assumption previously that python code (say, a data analysis or a scientific model) could be built into a web-based service by using it's classes and routines in a Django app. If the implementation of the two different classes is different, then this would be quite difficult!

This may have been answered elsewhere. I'm not well versed in Django jango, so don't know what to search for.

有帮助吗?

解决方案

The title attribute is not data. It holds a model description only; an object describing what type of information the title field should hold.

As such it is part of the class definition; individual instances of the Post class will have a title attribute that conforms to the constraints set in the models.CharField() instance on the class.

You need to build such a model to describe to Django how to build form fields and how to build a SQL table for the Post instances; both are concepts that need to have more type information than what Python normally itself needs.

Individual instances of Post are given a title attribute as well. That attribute then masks the class attribute:

p = Post(title='Some title')
print p.title  # prints 'Some title'

Python looks at the instance directly first; if it does not have a title attribute, lookup would then move to the class object. But that's not needed here, the Post.title attribute is not found as the instance has a title attribute itself.

In Python itself, there is no absolute distinction between 'data' and methods, by the way. Everything in Python is an object, including classes and methods. As such, looking up an attribute on an instance can find an object there too, including methods. If an attribute lookup there fails, then Python will look for the attribute on the class and base classes, and if that fails, lookup falls back to the metaclass even.

This is where mutable attributes come in; looking up ClassOne().v fails on the instance, but succeeds on the class. Manipulating that list then alters ClassOne.v the class attribute, and looking up v on other instances once again will find the class attribute. This is how class attributes are shared, just like the methods on the class.

其他提示

Django does not change the rules of the language. It does however use the language creatively. Just like class ClassTwo(...): v = [] creates one list and stores it in the class, class Post(...): title = something creates one something and stores it in the class. In this case, said something is not a char field value like "foo", it's an object which represents the concept of a char field with a max_length of 255.

Django gathers these objects representing database types, and creates (among many other things) an __init__ method that gives Post instances an attribute of the same name (which does contain an actual string value). The implementation of this is quite advanced, but firmly within the rules of the Python language - you and I can create our own Python libraries doing something similar. Anyway, since instance attributes shadow class attributes, you never notice that Post.title exists only once and isn't actually a title string. a_post_object.title always gives you the instance attribute.

As a slightly more general explanation of the relationship between class and instance variables, consider the following example that is unrelated to django models:

>>> class A(object):
...     x = 2
...     y = 1
...
...     def __init__(self):
...         self.x = 3
... 
>>> A.x
2
>>> instance = A()
>>> instance.x 
3
>>> instance.y
1
>>> instance.y = 4
>>> instance.y
4
>>> A.y
1

There are 2 things that I think are worth noting here. Firstly, a separate class and instance variable of the same name can exist. The class variable is only accessible directly from an instance if there is no instance variable of the same name. This is how the django models work, the class variables are fields (which are descriptions of the instance variables), the instance variables are the values for the specific instances. Using the same name for class and instance variables can be confusing, and isn't something to be done lightly. In the case of django models I think it works really well, but still can cause some headaches (I had similar questions when I first used django).

The second thing to note is that you can assign variables to an instance anywhere, it doesn't have to be in the __init__ function or even in a method of the instance's class, it can be anywhere. That is not to say that making a point of defining all instance variables in the __init__ function is a bad idea. In many cases it is a good idea.

This is a really old thread. I happen to get the same question while I'm just new to Django. Class of 'title' is models.CharField, which seems a python descriptor. According to the Descriptor definition, 'title' is a class variable. p.title = 'xxx', there is no instance 'title'. The above statement calls the class variable title to create a hidden title for the instance. print(p.title) will just call the class variable title to return the invisible title of instance.

https://docs.python.org/3.7/howto/descriptor.html Python cookbook chapter 8.6 also talks about the Descriptor.

Hope I'm correct and could help.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top