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

Sea*_*ene 31 python class

__class__在python中有一个问题.

文档说这__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
Run Code Online (Sandbox Code Playgroud)

一切顺利.

然后我输入如下代码:

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
Run Code Online (Sandbox Code Playgroud)

从上面的代码中,我认为可能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
Run Code Online (Sandbox Code Playgroud)

为什么NewCounter2.count改变但NewCounter2.__class__.count仍保持在3?更重要的是,当我改变时NewCounter2.count,NewCounter2.__class__.count is NewCounter2.count变成了False.这个属性在世界上是__class__什么?

eyq*_*uem 21

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

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

NewCounter1 = counter()
NewCounter2 = counter()
NewCounter2.__class__.count = 3
Run Code Online (Sandbox Code Playgroud)

创建了NewCounter1NewCounter2
并修改了类属性counter.count后,
没有对象 NewCounter1.countNewCounter2.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
Run Code Online (Sandbox Code Playgroud)

NewCounter._ 字典 _是实例的名称空间NewCounter1
print NewCounter1.count 打印一样print counter.count
.然而,"计数"(字符串"计数")未在命名空间NewCounter1,也就是说没有属性在命名空间创建的实例!

这怎么可能 ?

那是因为创建实例时没有分配_ 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的VALUE .class .count.这里的"被"是英文动词,而不是功能用于测试两个对象的身份的语言,它的意思是"被认为具有"

NewCounter2.__class__.count = 3被执行时,只有类属性counter.count受到影响.NewCounter1NewCounter2的名称空间保持为空,并且遵循与查找counter.count值的类相同的机制.

.

最后,当NewCounter2.count = 5执行时,这次将INSTANCE属性 计数创建为NewCounter2对象中的字段,并且'count'出现在NewCounter2的命名空间中 .
它不会覆盖任何内容,因为实例中__dict__
没有任何内容没有其他更改会影响NewCounter1counter.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)
Run Code Online (Sandbox Code Playgroud)

结果

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
Run Code Online (Sandbox Code Playgroud)

.

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

.

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

  • 非常感谢你的耐心和热情.我不知道该说什么,但谢谢你.我真的知道这个机制.你说的非常详细.再次感谢! (2认同)
  • 谢谢.我喜欢详细研究一些事情,我喜欢写一些东西试图产生一个尽可能少含糊不清和模糊措辞的明文.第一个提高了一个人的理解力,第二个允许测试这种理解力是否稳固.祝你在美好时光. (2认同)

cho*_*own 10

这一行:

NewCounter2.__class__.count = 3
Run Code Online (Sandbox Code Playgroud)

改变静态countcounter,但在这里:

NewCounter2.count = 5
Run Code Online (Sandbox Code Playgroud)

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

  • 混淆似乎是因为你可以在`counter`的实例上_get_属性`counter.count`,你不能直接在`counter`的实例上设置`counter.count`属性. (5认同)