其他答案大多是正确的,但错过了一件关键的事情。
如果你定义一个这样的类:
class Foo(object):
a = 5
和一个例子:
myinstance = Foo()
然后Foo.a
和myinstance.a
是相同的变量。更改一个将更改另一个,如果您创建多个实例Foo
,则.a
每个实例的属性将是相同的变量。这是因为 Python 解析属性访问的方式:首先它在对象的字典中查找,如果在那里找不到,它在类的字典中查找,依此类推。
这也有助于解释考虑到变量的共享性质,为什么赋值不能按您期望的方式工作:
>>> bar = Foo()
>>> baz = Foo()
>>> Foo.a = 6
>>> bar.a = 7
>>> bar.a
7
>>> baz.a
6
这里发生的情况是,当我们分配给时,它修改了所有实例在您请求时通常解析Foo.a
的变量。但是当我们分配给 时,Python 在该实例上创建了一个名为 的新变量,它现在掩盖了类变量 - 从现在开始,该特定实例将始终看到它自己的本地值。Foo
instance.a
bar.a
a
如果你希望你的类的每个实例都有一个单独的变量初始化为 5,那么通常的方法是这样的:
class Foo(object);
def __init__(self):
self.a = 5
也就是说,您定义了一个带有构造函数的类,该构造函数将a
新实例上的变量设置为 5。
最后,App Engine 正在做的是一种完全不同的黑魔法,称为描述符。简而言之,Python 允许对象定义特殊的__get__
和__set__
方法。当定义这些特殊方法的类的实例附加到一个类,并且您创建该类的实例时,尝试访问该属性将不是设置或返回实例或类变量,而是调用特殊__get__
和__set__
方法. 可以在这里找到更全面的描述符介绍,但这里有一个简单的演示:
class MultiplyDescriptor(object):
def __init__(self, multiplicand, initial=0):
self.multiplicand = multiplicand
self.value = initial
def __get__(self, obj, objtype):
if obj is None:
return self
return self.multiplicand * self.value
def __set__(self, obj, value):
self.value = value
现在您可以执行以下操作:
class Foo(object):
a = MultiplyDescriptor(2)
bar = Foo()
bar.a = 10
print bar.a # Prints 20!
描述符是大量 Python 语言背后的秘密武器。例如,property
使用描述符实现,方法、静态方法和类方法以及一堆其他东西也是如此。