Django和“普通”Python中的类成员和实例成员之间的区别?

时间:2014-01-01 15:19:10

标签: python django class definition

初学者问题在这里!前段时间,我问过这个问题: Parse CSV records into a list of Classes,在技术上也得到了更好的回答:How do I avoid having class data shared among instances?

我了解到,在Python类中,需要在__init__(self)函数中声明将基于每个对象定义的变量。

所以:

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

变量v将为ClassOne的所有实例保存相同的数据,而对于:

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

变量v包含 ClassTwo的每个实例的个别数据。

然而,在Django(我现在正在学习)中,我再次看到变量的“正常”(更像C ++)行为:

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

此处,变量titlePost的每个实例保存个别数据,尽管未在__init__函数中定义。

我的基本问题是为什么 title个别班级对象的关系,而不是的共同点每个类对象v中的ClassOne位于上方?

如果我理解这一点,这意味着Django类的解释与普通的Python类不同?但是,这个结论没有意义......

我希望有人可以帮助我理解这一点。之前我的假设是,通过在Django应用程序中使用它的类和例程,可以将python代码(例如,数据分析或科学模型)构建到基于Web的服务中。如果两个不同类的实现不同,那么这将非常困难!

这可能已在其他地方得到解答。我不熟悉Django jango,所以不知道该搜索什么。

4 个答案:

答案 0 :(得分:3)

title属性不是数据。它仅包含模型描述;对象描述 title字段应包含的信息类型。

因此它是类定义的一部分; Post类的各个实例将具有title属性,该属性符合类中models.CharField()实例中设置的约束。

您需要构建这样的模型来向Django描述如何构建表单字段以及如何为Post实例构建SQL表;两者都是需要比Python通常本身需要更多类型信息的概念。

Post的个别实例也会获得title属性 。该属性然后屏蔽类属性:

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

Python首先直接查看实例;如果具有title属性,则查找将移至类对象。但是这里不需要,因为实例本身具有Post.title属性,所以找不到title属性。

在Python本身,顺便说一下,'数据'和方法之间没有绝对的区别。 Python中的 Everything 是一个对象,包括类和方法。因此,在实例上查找属性也可以在那里找到一个对象,包括方法。如果属性查找失败,那么Python将在类和基类上查找属性,如果失败,查找甚至会回退到元类。

这是可变属性的来源;查找ClassOne().v在实例上失败,但在课程上取得了成功。操作该列表然后改变ClassOne.v类属性,再次在其他实例上查找v将找到class属性。这就是类属性的共享方式,就像类中的方法一样。

答案 1 :(得分:2)

Django不会改变语言规则。然而,它确实创造性地使用了该语言。就像class ClassTwo(...): v = []创建一个列表并将其存储在类中一样,class Post(...): title = something创建一个something并将其存储在类中。在这种情况下,所说的某些 不是像"foo"那样的char字段值,它是一个表示char的概念的对象max_length为255的字段。

Django收集表示数据库类型的这些对象,并创建(在许多其他事物中)__init__方法,为Post 实例提供相同名称的属性(< em> 包含实际的字符串值)。这个实现非常先进,但是在Python语言的规则范围内 - 你和我可以创建我们自己的Python库做类似的事情。无论如何,由于实例属性为shadow class属性,因此您从未注意到Post.title只存在一次,实际上并不是标题字符串。 a_post_object.title始终为您提供实例属性。

答案 2 :(得分:1)

作为类和实例变量之间关系的稍微更一般的解释,请考虑以下与django模型无关的示例:

>>> 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

我认为有两件事值得注意。首先,可以存在同名的单独的类和实例变量。如果没有相同名称的实例变量,则只能直接从实例访问类变量。这是django模型的工作方式,类变量是字段(它们是实例变量的描述),实例变量是特定实例的值。对类和实例变量使用相同的名称可能会造成混淆,并且不能轻易完成。在django模型的情况下,我认为它的效果非常好,但仍然会引起一些麻烦(当我第一次使用django时我有类似的问题)。

需要注意的第二件事是,您可以在任何地方为实例分配变量,它不必在__init__函数中,甚至在实例类的方法中,它可以在任何地方。这并不是说在__init__函数中定义所有实例变量是一个坏主意。在许多情况下,这是一个好主意。

答案 3 :(得分:0)

这是一个非常老的线程。当我刚接触Django时,我碰到同样的问题。 “ title”类是models.CharField,它似乎是python描述符。根据描述符定义,“ title”是一个类变量。 p.title ='xxx',没有实例'title'。上面的语句调用类变量title来为实例创建一个隐藏的标题。 print(p.title)只会调用类变量title来返回实例的不可见标题。

https://docs.python.org/3.7/howto/descriptor.html Python食谱第8.6章还讨论了描述符。

希望我是正确的,可以为您提供帮助。