初学者问题在这里!前段时间,我问过这个问题: 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)
此处,变量title
为Post
的每个实例保存个别数据,尽管未在__init__
函数中定义。
我的基本问题是为什么或 title
与个别班级对象的关系,而不是的共同点每个类对象,v
中的ClassOne
位于上方?
如果我理解这一点,这意味着Django类的解释与普通的Python类不同?但是,这个结论没有意义......
我希望有人可以帮助我理解这一点。之前我的假设是,通过在Django应用程序中使用它的类和例程,可以将python代码(例如,数据分析或科学模型)构建到基于Web的服务中。如果两个不同类的实现不同,那么这将非常困难!
这可能已在其他地方得到解答。我不熟悉Django jango,所以不知道该搜索什么。
答案 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章还讨论了描述符。
希望我是正确的,可以为您提供帮助。