2013-03-12 47 views
1

我想拼凑一些示例代码,我遇到了一点,这对我来说并不合适。如果不包括整个资料来源,我会尝试将我认为重要的部分作为目标,并希望我能完成所有工作。子类化字典,类变量

在这里,他声明了一个自定义的dict子类,我认为应该是类变量'customer'和'film'。 (如,从一个类中设置这些,应该在所有情况下对其进行更新,是吗?)

class Payment(dict): 
    customer = film = None 

而且这里是他使用的付款...

columns = [item[0] for item in cursor.description] 
payments = [] 
for row in cursor.fetchall(): 
    payment = Payment(zip(columns, row)) #I believe this is where he loads dict items 
    payment.customer = customers[payment["customer_id"]] #This is where he assigns 'class variable' 
    payment.film = films[payment["film_id"]] 
    payments.append(payment) 

在最后的名单,不应该所有的'支付'具有相同的值(这是另一个字典)吗?这是我的困惑所在。事实证明,这两个属性在整个董事会都有独特的价值。这是否与子类Dict有关?这些值是被复制而不是被引用的(所以在技术上它们是类变量,但是因为它们被复制,所以它们仍然是唯一的)。

就在我以为我明白了简单的OO机制,这将引发我...

回答

4

在下面:

payment.customer = customers[payment["customer_id"]] #This is where he assigns 'class variable' 
payment.film = films[payment["film_id"]] 

你不改变payment.customerpayment.film值。相反,你是重新绑定他们,使他们特定于该类的实例

请看下面的例子:

class X(object): 
    val = ['orig'] 

x1 = X() 
x2 = X() 
x3 = X() 
x1.val = ['rebound']  # rebind 
x2.val[0] = 'modified' # modify in place 
print x1.val, id(x1.val) 
print x2.val, id(x2.val) 
print x3.val, id(x3.val) 

这将打印

['rebound'] 2907552 
['modified'] 2771544 
['modified'] 2771544 

观察如何x1.val成为一个完全独立的变量,一旦它已经反弹,而x2.valx3.val继续都指向同一个列表。

2

当Python在对象上查找属性时,它首先查看实例,然后查看该类,然后查看超级类。

payment = Payment(zip(columns, row)) #I believe this is where he loads dict items 

后,您可以检查payment.__dict__customerfilm

没有条目如果您尝试访问(GETATTR)payment.film,因为实例没有film属性,你会得到payment.__class__.film

始终指定属性(除非它是描述符)将在实例dict中创建条目,因此它与所有其他实例隔离。

还有一些有趣的解释:

>>> class C(dict): 
... foo = "class foo" 
... 
>>> c = C() 
>>> c.__dict__ 
{} 
>>> c.foo 
'class foo' 
>>> c.foo = "instance foo" 
>>> c.__dict__ 
{'foo': 'instance foo'} 
>>> c.foo 
'instance foo' 
>>> del c.foo 
>>> c.foo 
'class foo' 

顺便说一句,因为在您的示例代码不访问这些类的属性,这将很好的工作:

class Payment(dict): 
    pass 

作者可能喜欢由于某种原因“声明”这些属性,但在这种情况下,并不需要(也可能令人困惑)。

+0

我见过这种技术用于创建实例并不总是初始化所有实例属性的情况。在这种情况下,它可能是一种有用的方法,可以将实例属性的默认值赋给可能或可能不会在实例中初始化的实例属性。 '金字塔'使用这种风格相当多。 – Duncan 2013-03-12 11:10:28

+0

NPE的答案有所帮助,但是这个更好地说明了属性查找。我认为我很困惑,因为通常来自实例的类变量访问通常是只读的。我只写过静态方法的类变量。 – user2097818 2013-03-12 14:24:28

+0

如果我真的想在我的实例中显式地将'foo'作为类变量(如你的例子),我需要从我的实例方法中使用C.foo吗? (假设变量是一个整数) – user2097818 2013-03-12 14:28:04