Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static variable vs class variable vs instance variable vs local variable

Tags:

oop

python-2.7

Before posting, I read more than a half dozen posts in a search from this site (python variables class static instance local) https://stackoverflow.com/search?q=python+variables+class+static+instance+local

I bookmarked several of the results for future studying, but none of them seemed to clarify to me if my thinking is right or wrong, so I feel I may be missing something about the basics (see below)...

Are the terms 'class variable' and 'static variable' referring to the same thing? After about three Google searches, reading through ~6 articles per search that I could understand, I've reached a conclusion that class and static variables are the same thing. But, since I'm just learning the fundamentals of Python and OOP, this conclusion may be wrong so I want to find any flaws in my reasoning before I continue learning with the wrong mindset. In the code below:

class Variables():
    scVar = 3

    def __init__(self, a, b):
        self.iVar1 = a
        self.iVar2 = b

    def getLocalVar3(self):
        localVar1 = 17
        localVar2 = 100
        localVar3 = localVar1 + localVar2
        return localVar3

Is 'scVar' both a class variable and a static variable ('class' and 'static' variables being synonymns)?

The second question is to clarify my understanding of differentiating class variables, instance variables, and local variables. In the code above, I'm thinking that scVar is a class variable; iVar1 and iVar2 are instance variables; and localVar1, localVar2, and localVar3 are local variables. Is that correct to say, or is there something that I'm missing?


Thanks cirosantilli, That article that you linked to is one I haven't seen yet. I'm going to look that over. I wonder a bit about Python's point of vew that there's not a distinction between class variables and instance variables. Is this point of view one that I should try to understand correctly right up front, as a beginner, or should I just keep the idea in mind and not worry too much about reconciling my current point of view with that one until I become more experienced? That question probably seems overly vague, and dependent upon my current level of understanding Python. Mostly, I've been running commands on class examples similar to what is in the original post; predicting the output before I press the [enter] key and then studying the output when it's not what I predicted. From that, I'm starting to get some grasp of how things work in Python. Basically, I've just recently started getting a glimpse of how OO works in Python - inching forward, slowly but surely.

"However the above are just conventions: from the language point of view there is no distinction between class variables and instance variables." -- Just to help me understand this better, does the part, 'from the language point of view ...' sort of imply that the Python documentation explains this point of view somewhere within it? If so, I'll re-read through the docs and look specifically for this part, and try to conform my thinking process to it. "... between class variables and instance variables." So, even though there's the difference in the way that class and instance variables can be seen and accessed by 'classobj's and 'instance's, Python's point of view is that there is no distinction between them? I'm going to keep this idea in mind during future reading so that I can maybe get rid of some confusion on my part. After I run the *.py in the original post, I get the following outputs in IDLE, using Python 2.7.x (only the last line of the traceback error is included, for better readability):

>>> Variables.scVar
3
>>> Variables.iVar1
AttributeError: class Variables has no attribute 'iVar1'
>>> instance = Variables(5, 15)
>>> instance
<__main__.Variables instance at 0x02A0F4E0>
>>> Variables
<class __main__.Variables at 0x02A0D650>
>>> instance.scVar
3
>>> instance.iVar1
5
>>> instance2 = Variables(25, 35)
>>> instance2.scVar
3
>>> Variables.scVar = Variables.scVar * 100
>>> Variables.scVar
300
>>> instance.scVar
300
>>> instance2.scVar
300
>>> instance.scVar = 9999
>>> Variables.scVar
300
>>> instance.scVar
9999
>>> instance2.scVar
300
>>> type(Variables)
<type 'classobj'>
>>> type(instance)
<type 'instance'>

"However the above are just conventions: from the language point of view there is no distinction between class variables and instance variables." -- By using the code from the original post, is there maybe a sequence of commands that illustrates this point? I don't doubt that you know what you're talking about; I just find it difficult to reconcile my current way of thinking with the above statement. But I get the feeling that if I can start to see the difference between the two perspectives, that something important will 'click'. As an afterthought to the last few sentences, I might be on to seeing things more along the same lines as your statement about 'no distinction between class variables and instance variables', but only if my following assumption is accurate... From the code in the original post (class Variables - 12 lines), are there just the two scopes of global and local involved in that program? Since I've just started to form conclusions about how it all fits together, I think that my limited understanding of scope might be what keeps me from fully grasping the idea that there's no distinction between class variables and instance variables. The only thing I can seem to make of it now is that (only maybe) - 'Python has no distinction between class variables and instance variables; but the differences between global and local scope might make it appear to a novice that there is a distinction between these two types of variables. I don't know, does that statement identify a potential 'hang up' that I could be having about it?


"Everything is an object, including classes and integers:" -- I've read this numerous times. So much so that I take it to be a core belief to understanding OO and Python, but it's not a concept in which I fully realize the implications of yet (I think).

class Foo():
    integer = 10
    float = 6.37
    string = 'hello'
    boolean = True
    idkyet = None

    def __init__(self):
        self.a = 'iv_a'
        self.b = 'iv_b'
        self.c = 'iv_c'

    def Func(self):
        self.g = 'g'
        h = 'h'
        i = 'i'
        return 'g' + 'h' + 'i'

>>> Foo
<class __main__.Foo at 0x02A1D650>
>>> type(Foo.integer)
<type 'int'>
>>> type(Foo.float)
<type 'float'>
>>> type(Foo.string)
<type 'str'>
>>> type(Foo.boolean)
<type 'bool'>
>>> type(Foo.idkyet)
<type 'NoneType'>
>>> type(Foo)
<type 'classobj'>
>>> import os
>>> type(os.getcwd() + '\\Test.py')
<type 'str'>
>>> type(os)
<type 'module'>
>>> f = Foo()
>>> type(f)
<type 'instance'>
>>> type(f.Func)
<type 'instancemethod'>
>>> type(f.Func())
<type 'str'>
>>> f.Func
<bound method Foo.Func of <__main__.Foo instance at 0x02A25AF8>>
>>> Foo.Func
<unbound method Foo.Func>
>>> type(f.a)
<type 'str'>
>>> type(Foo.a)
AttributeError: class Foo has no attribute 'a'
>>> type(Foo.self.a)
AttributeError: class Foo has no attribute 'self'

When I was about half way through this response, leaving off with the 'class Foo():' code above and the commands ran on it below that, I hit a snag and couldn't quite continue with the other follow-up question that I barely had in mind. So, I stepped away from the problem for awhile and started to read that 'cafepy...' link that you posted (by Shalabh Chaturvedi). That's really interesting. I had seen excerpts from that before but I hadn't read the whole thing, but it seems much more understandable now than it would have been just a week ago. I think I will read the whole thing. Don't mind the last half of this post (after the '***') because I still can't pinpoint exactly what I was trying to ask. ...everything is an object...mainly just a difference in object types???... < That is the note that I had jotted down when I almost had in mind how to frame the last question, but it never came to fruition. I'll have to wait until something else 'clicks' and I can see again what I had in mind.

I'll also keep in mind to stop and re-read if I glance across anything related to 'MRO', bound and unbound methods... I have been picking up just a bit of those three terms lately, in a way that it feels like they won't be too far in the future of my learning process.

like image 830
Thaddeus LeBlanc Avatar asked Dec 08 '13 09:12

Thaddeus LeBlanc


People also ask

What is the difference between local variable instance variable and class variable?

Class variables also known as static variables are declared with the static keyword in a class, but outside a method, constructor or a block. Instance variables are created when an object is created with the use of the keyword 'new' and destroyed when the object is destroyed.

What's the difference between a static variable and a class variable?

Class variables are also known as static variables, and they are declared outside a method, with the help of the keyword 'static'. Static variable is the one that is common to all the instances of the class. A single copy of the variable is shared among all objects.


1 Answers

I believe that static and class variables are commonly used as synonyms.

What you say about the variables is correct from the convention point of view: this is how you should think about them most of the time.

However the above are just conventions: from the language point of view there is no distinction between class variables and instance variables.

Python is not like C++ or Java.

Everything is an object, including classes and integers:

 class C(object): pass
 print id(C)
 C.a = 1
 assert C.__dict__['a'] == 1

There is no clear distinction between methods and instance variables: they are just attributes of an object.

Therefore, there is no language level distinction between instance variables and class variables: they are just attributes of different objects:

  • instance variables are attributes of the object (self)
  • class variables are attributes of the Class object.

The real magic happens on the order that the . operator searches for attributes:

  • __dict__ of the object
  • __dict__ of the class of the object
  • MRO up to parent classes

You should read this great article before you get confused in the future.

Also beware of bound vs unbound methods.

EDIT: attempt to address further questions by the OP made in his post.

Wow that was large! I'll try to read everything, but for the future you should try to keep questions more concice. More code, less talk =). You'll get better answers.

should I just keep the idea in mind and not worry too much about reconciling my current point of view with that one until I become more experienced?": I do things.

I do as I feel necessary. When necessity calls, or I can't take magic behaviour anymore, I learn.

sort of imply that the Python documentation explains this point of view somewhere within it?

I don't know about the docs, but the language itself works that way.

Of course, the language was designed to give the impression that syntax works just like in C++ in the common cases, and it adds a thin layer of magic to classes to make it look like so.

But, since that is not how it truly works, you cannot account for all (useful) behaviour by thinking only in terms of C++ class syntax.

By using the code from the original post, is there maybe a sequence of commands that illustrates this point?

I'm not sure it can be illustrated in sequence of commands. The point is: classes are objects, and their attributes are searched by the dot . MRO on the same order as attributes of objects:

class C(object):
    i_static = 0
    def __init__(self):
        self.i = 1

# i is in the __dict__ of object c
c = C()
assert c.__dict__['i'] == 1
assert c.i == 1

# dot finds i_static because MRO looks at class
assert c.__class__.__dict__['i_static'] == 0
assert c.i_static == 0

# i_static is in the __dict__ of object C
assert C.__dict__['i_static'] == 0
assert C.i_static == 0

# __eq__ is in the dict of type, which is the __class__ of C
# By MRO, __eq__ is found. `C,C` because of bound vs unbound.
assert C.__class__.__dict__['__eq__'](C,C)
assert C == C

are there just the two scopes of global and local involved in that program?

This is a point I don't know very clearly.

There is a no global scope in Python, only module level.

Then there is a new local scope inside functions.

The rest is how the . looks for attributes.

can't pinpoint exactly what I was trying to ask

Ask: can I find a difference in syntax between classes, integers or functions?

If you think you have found one, ask: hmmm, how can I make an object with certain attributes that behaves just like that thing which does not look like an object?

You should find an answer every time.

Example:

def f(): pass

class C(object): pass

AHA: f is different than c = C() because I can do f() but notc()`!

But then, no, it is just that the f.__class__.__dict__['__call__'] attribute is defined for f, and can be found via MRO.

But we can do that for c too:

class C(object):
    def __call__(self): pass

and now we can do c().

So they were not different in that aspect.