2015-11-17 4 views
2

Мы говорим, что classes являются изменяемыми в Python, что означает, что вы можете использовать ссылки, которые мы можем изменить значения, которые будут отражаться в объекте. Например,Почему я не могу изменить атрибут класса в Python

>>> A = [1, 2, 3] 
>>> B = A 
>>> B[2] = 5 
>>> A 
[1, 2, 5] 

Здесь можно изменить значения A объекта с помощью B, потому что list является изменяемым типом. Мой вопрос, почему я не могу изменить атрибуты класса ниже, с использованием той же концепции:

class C: 

    apple = 2 

    def __init__(self): 
     self.dangerous = 2 

D = C# D is pointing to same class C 

D().dangerous = 5 # changing the value of class attribute D 

D().apple = 3 # changing the value of apple here 

print D().apple 

print D().dangerous 

OUTPUT: 
2 
2 

Может кто-нибудь объяснить, почему выход 2 и 2 но не 3 и 5, так как мы говорим, что класс является mutable type.

ОБНОВЛЕНИЕ: Обращаясь к ответу @ zxq9, если вы видите приведенную ниже диаграмму, когда D=C, D фактически указывает на тот же класс, а на новый объект, как вы описали. Не могли бы вы объяснить это:

enter image description here

+1

Что в мире люди downvoting это? ОП задал довольно четкий вопрос, просто не понимал синтаксической разницы между экземплярами объектов и определениями классов. – zxq9

+0

@ zxq9 Можете ли вы увидеть мой обновленный pic? – python

+1

Да, но * вы все еще только назначаете временный экземпляр класса *, а не сам класс. Я буду играть с этим и расширить свой ответ, чтобы покрыть это. Это очень хорошая вещь, чтобы иметь в виду Python. – zxq9

ответ

6

Каждый раз, когда вы поместите скобки после класса, вы строите новый объект экземпляра класса. Итак, все, что вы напечатали, стало бестраншейной новинкой и не отражало краткосрочных заданий, которые вы делали ранее.

Вот пример (расширенный, чтобы покрыть основную ссылку на класс C):

>>> class C: 
... red = 2 
... def __init__(self): 
...  self.blue = 2 
... 
>>> C.red 
2 
>>> C.blue 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: type object 'C' has no attribute 'blue' 
>>> C().red 
2 
>>> C().blue 
2 
>>> #OOOOH! 
... 
>>> z = C() 
>>> z.red 
2 
>>> z.blue 
2 
>>> D = C 
>>> D.red 
2 
>>> D().red 
2 
>>> D().red = "over 9000!" 
>>> D.red 
2 
>>> D.red = "No, really over 9000!" 
>>> D.red 
'No, really over 9000!' 
>>> C.red 
'No, really over 9000!' 
>>> #OOOOOOHHHH! 
... 

Обратите внимание, что мы сделали изменения класс непосредственно, когда я назначил C.apple = 3 - потому что был ссылающийся на класс само определение, а не созданный им экземпляр объекта.

Прогулка пример кода внимательно, обратите внимание на разницу между ссылающийсяClassName и вызоваClassName(). Первый - это ссылка с помощью имени переменной в определение класса - проект для создания экземпляров объектов, который несет с собой конструкторскую функцию __init__(). Второй - это invokation of __init__(), возвращаемое значение которого является экземпляром объекта класса, в котором оно определено.

Это также объясняет, почему вы можете сделать что-то вроде этого:

def some_fun(another_fun, value): 
    another_fun(value) 

def foo(v): 
    return v + v 

def bar(v): 
    return v * v 

some_fun(foo, 5) 
some_fun(bar, 5) 

Эта функция предоставляет Python высокую степень гибкости в построении функциональных абстракций. (Теперь, если только у него было устранение хвостового вызова ...)

+0

Концепция очищена :) Спасибо – python

0

Это интересный пример.

  1. Линия D() опасными = 5 будет изменить атрибут "опасным" из экземпляра D(). Но линия печать D().опасно распечатать атрибут «опасный» ДРУГОЙ пример D().
  2. Линия D(). Яблоко = 3 будет создать атрибут «яблоко» в экземпляре D(), так как этот экземпляр не имеет атрибут «яблоко».
  3. Линии печати D(). Яблоко напечатает атрибут «яблочный» класс D с экземпляром D() не имеет атрибут «яблоко».
  4. Один из способов изменить атрибут «яблоко» класса через своего экземпляра является использование D() .__ класс __. Яблоко = 3