Подтвердить что ты не робот

Что в мире есть атрибут "__class__" в python

У меня вопрос о __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

Все идет хорошо.

Затем введите код следующим образом:

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__?

4b9b3361

Ответ 1

"Из приведенных выше кодов я думал, что, возможно, 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 пример!

Как это возможно?

Это потому, что экземпляр создается без присвоения идентификатора 'count' внутри _init _
- > нет реального создания какого-либо атрибута в качестве поля в NewCounter1, т.е. никакого создания атрибута INSTANCE.

Следствием этого является то, что когда инструкция print 'NewCounter1.count ==',NewCounter1.count
, интерпретатор не находит атрибут экземпляра в пространстве имен NewCounter1, а затем переходит к классу экземпляра для поиска ключа "count" в этом пространстве имен этого класса; там он находит "count" как ключ атрибута CLASS и может принимать значение VALUE объекта counter.count как VALUE для отображения в ответ на инструкцию.

Экземпляр класса имеет пространство имен, реализованное как словарь, который первое место, в котором выполняется поиск ссылок атрибутов. Когда атрибут там не найден, а класс экземпляров имеет атрибут по этому имени, поиск продолжается с классом атрибутов. http://docs.python.org/reference/datamodel.html#the-standard-type-hierarchy

Итак, NewCounter1.count equals NewCounter1.__class__.count здесь означает, что значение VALUE для NewCounter1.count, даже если это действительно не существует, является значением VALUE атрибута класса NewCounter1. class.count. Здесь "есть" - это английский глагол, а не языка, который проверяет идентичность двух объектов, а это означает, что "считается имеющим"

Когда NewCounter2.__class__.count = 3 выполняется, затрагивается только атрибут класса counter.count. Пространства имен NewCounter1 и NewCounter2 остаются пустыми и выполняется тот же механизм перехода к классу, чтобы найти значение counter.count.

.

В конце, когда выполняется 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__, а механизм поиска атрибута, и этот механизм вводит в заблуждение при игнорировании.

Ответ 2

Эта строка:

NewCounter2.__class__.count = 3

изменяет статический count counter, но здесь:

NewCounter2.count = 5

NewCounter2 теперь имеет свой собственный атрибут count, который скрывает статический count;
так что линия не влияет на NewCounter1.
Вот почему NewCounter2.__class__.count != NewCounter2.count.

Ответ 3

Переадресация (то есть назначение) атрибута объекта с тем же именем, что и атрибут класса, придает атрибуту класса. Сначала объект всегда проверяется на атрибуты, а затем классы в порядке MRO.

Ответ 4

Линия

NewCounter2.count = 5

Создает новый атрибут уровня экземпляра NewCounter2. После этого вы получаете доступ к двум различным атрибутам (NewCounter2.count - уровень уровня attr и NewCounter2.__class__.count - уровень уровня attr), которые вызывают "странное поведение".