Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I change attribute of a class in Python

We say classes are mutable in Python which means you can using references we can change the values that will be reflected in object. For example,

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

Here I can change the values of A object using B because list is a mutable type. My question is why can't I change the attributes of a class below using same concept:

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

Could anyone explain why the output is 2 and 2 but not 3 and 5 since we are saying that the class is a mutable type.

UPDATE : Referring to the answer by @zxq9, if you see the below diagram when do D=C, D is actually pointing to the same class rather a new object as you have described. Could you explain this:

enter image description here

like image 221
python Avatar asked Nov 17 '15 04:11

python


People also ask

How do you change a class attribute in Python?

But be careful, if you want to change a class attribute, you have to do it with the notation ClassName. AttributeName. Otherwise, you will create a new instance variable.

How do you modify attributes in Python?

If you want your method to modify any attribute, you can pass its name as a string. You can then use getattr() and setattr() to get and set the attribute.

Can not set attribute Python?

How is it possible? The explanation you are getting this error is that you are naming the setter method mistakenly. You have named the setter method as set_x which is off base, this is the reason you are getting the Attribute Error.

Can class attributes be modified?

While you can access the class attributes using the instance for read purposes, you cant modify them. To modify class attribute you need to access the attribute using class name.


1 Answers

Each time you place parens after a class, you are constructing a new instance object of the class. So the things you printed were brand-spanking new and did not reflect the short-lived assignments you had made previously.

Here is an example (expanded to cover the underlying reference to class 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!
...

Note that we did change the class directly when I assigned D.red = "No, really over 9000!" -- because that was referencing the class definition itself, not an instantiated object created from it. Note also that assigning an attribute of D (a copy) changed the attribute of C (the original) because in many (but not all) cases Python makes such assignments by reference, meaning that D is really an alias of C, not copy of the underlying structure. Read up on Python's deepcopy() method for more about that particularly startling detail.

Walk through the example code carefully, note the difference between referencing ClassName and calling ClassName(). The first is a reference via a variable name to a class definition -- a blueprint for generating instance objects that carries a constructor function __init__() with it. The second is an invokation of __init__() whose return value is an instance object of the class within which it is defined.

This is also why you can do things like this:

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)

This feature lends Python a high degree of flexibility in building functional abstractions. (Now if only it had tail-call elimination...)

like image 78
zxq9 Avatar answered Sep 21 '22 23:09

zxq9