Egor Egorov
Egor Egorov

Reputation: 312

Why class variable read from method and outside are different?

So, i created Some class

class Some:
    @classmethod
    def __init__(cls, somevar):
        cls.somevar = somevar

    @classmethod
    def read(cls):
        return cls.somevar

Now I tried to set variable outside and read it from class:

instance = Some([1, 2, 3])
instance.somevar = [4, 5, 6]
print(instance.read())

>>>> [1, 2, 3]

But calling same named variable outside class give me expected output instead,

print(instance.somevar)
>>>> [4, 5, 6]

What is my misunderstanding about the OOP?

EDIT

My goal is to create multiple instances of Some that will have their own values.

Upvotes: 2

Views: 80

Answers (4)

scharette
scharette

Reputation: 9977

In fact, you misunderstood what a class variable is. When you're using

instance.somevar = [4, 5, 6]

it doesn't mutate the value that you think. Instead, what you'd need to do is change the actual class variable like so,

instance = Some([1, 2, 3])
instance.somevar = [4, 5, 6]
print(instance.read())
instance2 = Some([4, 5, 6])
print(instance.read())

>>>>
[1, 2, 3]
[4, 5, 6]

Indeed, don't forget that by using the @classmethod decorator, cls is actually the class itself. Therefore, in your case, cls.somevar will be shared across all classes. Also, since you decorated your __init__, you'll be changing the value of that variable every time you will instantiate the class as shown empirically in my above example.


Note that this is probably not the implementation you are looking for. You probably want to be using self like this instead,

class Some:
    def __init__(self, somevar):
        self.somevar = somevar

    def read(self):
        return self.somevar

instance = Some([1, 2, 3])
print(instance.read())
instance.somevar = [4, 5, 6]
print(instance.read())

>>>>
[1, 2, 3]
[4, 5, 6]

Upvotes: 5

tripleee
tripleee

Reputation: 189467

You probably need to better understand the difference between a class and an instance. Perhaps the following code will help.

class Some():
    classvar = 123

    def __init__ (self, value):
        self.instvar = value

    def read_instvar (self):
        return self.instvar

    def read_classvar (self):
        return self.__class__.classvar

    @classmethod
    def update_classvar(cls, value):
        cls.classvar = value

So now we can create several objects and see how they interact.

>>> first = Some(12)
>>> second = Some(34)
>>> second.update_classvar(456)
>>> first.read_classvar()
456
>>> first.read_instvar()
12
>>> second.read_instvar()
34
>>> second.read_classvar()
456

Observe how instvar is the attribute of each instance; so first has a value which is distinct from that of second. Notice however how classvar is shared between these instances, because they belong to the same class, and the class variable is a property of that class, not of any one instance. Concretely, even though we changed the class variable via second, the change is also visible in first.

Upvotes: 1

DFE
DFE

Reputation: 136

It is more like a scope problem.

instance = Some([1, 2, 3])
instance.somevar = [4, 5, 6]
print(instance.read())

>> [1, 2, 3]

Some.somevar = [4, 5, 6]
print(instance.read())

>> [4, 5, 6]

All is based on the fact that in Python, 2 variables with same name can be used in a instance scope and in a class scope and have different values.

Upvotes: 0

Jelle
Jelle

Reputation: 808

Use print(instance.somevar) to get the somevar value, but you change it inside your function, not globally

Upvotes: 1

Related Questions