世界上什么是python中的属性“__class__”

时间:2011-11-09 05:30:58

标签: python class

我在python中有一个关于__class__的问题。

文档说__class__是类实例所属的类。所以我进行了一系列实验:

class counter:
    count = 0
    def __init__(self):
            self.__class__.count += 1

NewCounter1 = counter()
print NewCounter1.count   #The result is 1
NewCounter2 = counter()
print NewCounter2.count   #The result is 2
print NewCounter2.__class__.count is NewCounter2.count  #result: True

一切顺利。

然后我按如下方式输入代码:

NewCounter2.__class__.count = 3

print NewCounter1.count                    #result:3
print NewCounter1.__class__.count      #result:3
print NewCounter2.count                    #result:3
print NewCounter2.__class__.count      #result:3
print NewCounter2.__class__.count is NewCounter2.count      #result: True

从上面的代码中,我认为可能NewCounter1.count等于NewCounter1__class__.count,但以下代码让我感到惊讶:

NewCounter2.count = 5

print NewCounter1.count                 #result:3
print NewCounter1.__class__.count   #result:3
print NewCounter2.count                 #result:5
print NewCounter2.__class__.count   #result:3
print NewCounter2.__class__.count is NewCounter2.count       #result: False

为什么NewCounter2.count已更改但NewCounter2.__class__.count仍为3?更重要的是,当我更改NewCounter2.count时,NewCounter2.__class__.count is NewCounter2.count变为False。属性__class__是什么?

4 个答案:

答案 0 :(得分:21)

  

“从上面的代码中,我认为NewCounter1.count可能等于NewCounter1。_class_.count”

问题在于,在你的问题中这句话的那一刻,在唯一的指示之后:

NewCounter1 = counter()
NewCounter2 = counter()
NewCounter2.__class__.count = 3

创建 NewCounter1 NewCounter2
并修改了类属性 counter.count
 没有对象 NewCounter1.count ,也没有 NewCounter2.count ,然后“equals”没有实际意义。

查看 NewCounter1 的创建,然后查看:

class counter:
    count = 0
    def __init__(self):
        self.__class__.count += 1

print 'counter.count BEFORE ==',counter.count  # The result is 0
NewCounter1 = counter()
print '\nNewCounter1.__dict__ ==',NewCounter1.__dict__  # The result is {}
print 'NewCounter1.count    ==',NewCounter1.count # The result is 1
print 'counter.count AFTER  ==',counter.count  # The result is 1

NewCounter ._ dict _ 是实例 NewCounter1 的命名空间 print NewCounter1.count打印的内容与print counter.count相同 但是,'count'(字符串'count')不在 NewCounter1 的命名空间中,也就是说在创建的命名空间中没有属性 count 实例!

怎么可能?

那是因为创建的实例没有分配 _ init _ 中的'count'标识符 - >在 NewCounter1 中没有任何属性作为字段的真实创建,也就是说没有创建INSTANCE属性。

结果是指示时 print 'NewCounter1.count ==',NewCounter1.count
在评估时,解释器在 NewCounter1 的命名空间中找不到实例属性,然后转到实例的类以在此类的命名空间中搜索键'count';在那里它找到'count'作为CLASS属性的键,并且可以将对象 counter.count 的VALUE作为值来显示以响应该指令。

  

一个类实例有一个名称实现为字典的名称空间   搜索属性引用的第一个位置。当一个   在那里找不到属性,并且实例的类有一个   通过该名称的属性,搜索继续该类   属性。   http://docs.python.org/reference/datamodel.html#the-standard-type-hierarchy

所以,NewCounter1.count equals NewCounter1.__class__.count这里意味着NewCounter1.count的VALUE,即使这个实际上不存在,也是类属性 NewCounter1的值。 .Count之间的即可。这里的“是”是英语动词,而不是测试两个对象身份的语言 的特征,它意味着'被认为有'

执行NewCounter2.__class__.count = 3时,只会影响类属性 counter.count NewCounter1 NewCounter2 的命名空间保持为空,并且遵循与查找 counter.count 值的类相同的机制。< / p>

最后,当NewCounter2.count = 5执行时,这次创建INSTANCE属性 count 作为 NewCounter2 对象中的字段,并出现'count'在 NewCounter2 的命名空间中。
它不会覆盖任何内容,因为实例__dict__中没有任何内容 没有其他更改会影响 NewCounter1 counter.count

以下代码更明确地显示了执行期间的基础事件:

from itertools import islice

class counter:
    count = 0
    def __init__(self):
        print ('  |  counter.count   first == %d  at  %d\n'
               '  |     self.count   first == %d  at  %d')\
               % (counter.count,id(counter.count),
                  self.count,id(self.count))

        self.__class__.count += 1 # <<=====

        print ('  |  counter.count  second == %d  at  %d\n'
               '  |     self.count  second == %d  at  %d\n'
               '  |  id(counter) == %d   id(self) == %d')\
               % (counter.count,id(counter.count),
                  self.count,id(self.count),
                  id(counter),id(self))



def display(*li):
    it = iter(li)
    for ch in it:
        nn = (len(ch)-len(ch.lstrip('\n')))*'\n'
        x = it.next()
        print '%s ==  %s %s' % (ch,x,'' if '__dict__' in ch else 'at '+str(id(x)))



display('counter.count AT START',counter.count)


print ('\n\n----- C1 = counter() ------------------------')
C1 = counter()
display('C1.__dict__',C1.__dict__,
        'C1.count ',C1.count,
        '\ncounter.count ',counter.count)


print ('\n\n----- C2 = counter() ------------------------')
C2 = counter()
print ('  -------------------------------------------') 
display('C1.__dict__',C1.__dict__,
        'C2.__dict__',C2.__dict__,
        'C1.count ',C1.count,
        'C2.count ',C2.count,
        'C1.__class__.count',C1.__class__.count,
        'C2.__class__.count',C2.__class__.count,
        '\ncounter.count ',counter.count)


print '\n\n------- C2.__class__.count = 3 ------------------------\n'
C2.__class__.count = 3
display('C1.__dict__',C1.__dict__,
        'C2.__dict__',C2.__dict__,
        'C1.count ',C1.count,
        'C2.count ',C2.count,
        'C1.__class__.count',C1.__class__.count,
        'C2.__class__.count',C2.__class__.count,
        '\ncounter.count ',counter.count)


print '\n\n------- C2.count = 5 ------------------------\n'
C2.count = 5
display('C1.__dict__',C1.__dict__,
        'C2.__dict__',C2.__dict__,
        'C1.count ',C1.count,
        'C2.count ',C2.count,
        'C1.__class__.count',C1.__class__.count,
        'C2.__class__.count',C2.__class__.count,
        '\ncounter.count ',counter.count)

结果

counter.count AT START ==  0 at 10021628


----- C1 = counter() ------------------------
  |  counter.count   first == 0  at  10021628
  |     self.count   first == 0  at  10021628
  |  counter.count  second == 1  at  10021616
  |     self.count  second == 1  at  10021616
  |  id(counter) == 11211248   id(self) == 18735712
C1.__dict__ ==  {} 
C1.count  ==  1 at 10021616

counter.count  ==  1 at 10021616


----- C2 = counter() ------------------------
  |  counter.count   first == 1  at  10021616
  |     self.count   first == 1  at  10021616
  |  counter.count  second == 2  at  10021604
  |     self.count  second == 2  at  10021604
  |  id(counter) == 11211248   id(self) == 18736032
  -------------------------------------------
C1.__dict__ ==  {} 
C2.__dict__ ==  {} 
C1.count  ==  2 at 10021604
C2.count  ==  2 at 10021604
C1.__class__.count ==  2 at 10021604
C2.__class__.count ==  2 at 10021604

counter.count  ==  2 at 10021604


------- C2.__class__.count = 3 ------------------------

C1.__dict__ ==  {} 
C2.__dict__ ==  {} 
C1.count  ==  3 at 10021592
C2.count  ==  3 at 10021592
C1.__class__.count ==  3 at 10021592
C2.__class__.count ==  3 at 10021592

counter.count  ==  3 at 10021592


------- C2.count = 5 ------------------------

C1.__dict__ ==  {} 
C2.__dict__ ==  {'count': 5} 
C1.count  ==  3 at 10021592
C2.count  ==  5 at 10021568
C1.__class__.count ==  3 at 10021592
C2.__class__.count ==  3 at 10021592

counter.count  ==  3 at 10021592

有趣的事情是添加指令
self.count = counter.count
在线之前
self.__class__.count += 1 # <<=====
观察结果的变化

总之,关键点不是__class__,而是搜索属性的机制,这种机制在被忽略时会产生误导。

答案 1 :(得分:10)

这一行:

NewCounter2.__class__.count = 3

更改count的静态counter,但在此处:

NewCounter2.count = 5

NewCounter2现在有自己的count属性隐藏静态count;
这条线对NewCounter1没有影响。
这也是NewCounter2.__class__.count != NewCounter2.count

的原因

答案 2 :(得分:3)

重新绑定(即分配)对象上的属性,该属性与类上的属性同名,影响类的属性。始终首先检查对象的属性,然后检查MRO顺序中的类。

答案 3 :(得分:0)

NewCounter2.count = 5

创建NewCounter2的新实例级属性。之后,您访问了两个不同的属性(NewCounter2.count - 实例级别attr和NewCounter2.__class__.count - 类级别attr),这导致了“奇怪”的问题。行为&#39;