Difference Between Class and Instance Attributes

What is the difference between class and instance attributes?

There is a significant semantic difference (beyond performance considerations):

  • when the attribute is defined on the instance (which is what we usually do), there can be multiple objects referred to. Each gets a totally separate version of that attribute.
  • when the attribute is defined on the class, there is only one underlying object referred to, so if operations on different instances of that class both attempt to set/(append/extend/insert/etc.) the attribute, then:
    • if the attribute is a builtin type (like int, float, boolean, string), operations on one object will overwrite (clobber) the value
    • if the attribute is a mutable type (like a list or a dict), we will get unwanted leakage.

For example:

>>> class A: foo = []
>>> a, b = A(), A()
>>> a.foo.append(5)
>>> b.foo
[5]
>>> class A:
... def __init__(self): self.foo = []
>>> a, b = A(), A()
>>> a.foo.append(5)
>>> b.foo
[]

Difference between Class Attributes, Instance Attributes, and Instance Methods in Python

Class attributes are same for all instances of class whereas instance attributes is particular for each instance. Instance attributes are for data specific for each instance and class attributes supposed to be used by all instances of the class.

"Instance methods" is a specific class attributes which accept instance of class as first attribute and suppose to manipulate with that instance.

"Class methods" is a methods defined within class which accept class as first attribute not instance(that's why the are class methods).

You can easily see class attributes by accessing A.__dict__:

class A:
class_attribute = 10
def class_method(self):
self.instance_attribute = 'I am instance attribute'

print A.__dict__
#{'__module__': '__main__', 'class_method': <function class_method at 0x10978ab18>, 'class_attribute': 10, '__doc__': None}

And instance attributes as A().__dict__:

a = A()
a.class_method()
print a.__dict__
# {'instance_attribute': 'I am instance attribute'}

Some useful links from official python documentation and SO, which i hope won't confuse you more and give clearer understanding...

  • Python Classes
  • Dive into python, 5.8. Introducing Class Attributes
  • Definition of python getattr and setattr
  • What are Class methods in Python for?
  • Difference between Class and Instance methods

Difference between class attribute and instance variable with default value

Are there any differences between a class variable and an instance variable with a default value?

Well, yes obviously: a class attribute (not "variable") belongs to the class, an instance attribute belongs to the instance.

In what context should I use which version?

Use class attributes when you want the attribute to be shared by all instances of the class, and instance attributes when you want the attribute to be specific to this exact instance. In practice, you'll seldom have a need for class attributes.

Note that if you define the same attribute for both the class and the instance, the one on the instance will shadow the class's one.

nb: the above is a very very crude simplification, but else I'd need to explain the whole Python object model, and this deserves a full book

Take these two classes as an example (...) no matter what version you choose, when you run the code below, you'll get the same result

Yes, that's to be expected for this code snippet.

For a:

In the first case, when you first print a.d, a doesn't have an instance attribute d so you're getting the class attribute value. Then you create the instance attribute a.d by assigning to it, and from then on it shadows the class attribute.

In the second case, a.d initially has it's default value, then you rebind it to another value... quite ordinary stuff.

For a2:

In the first case, a2.a will always be 4 because you haven't shadowed it with an instance attribute, so it's getting the value from the class.

In the second case it will always be 4 because you didn't rebind the instance attribute so it's still the default value.

Now try the same thing with a list as attribute, and appending to the list instead of rebinding it:

class A:
d = []

class B:
def __init__(self):
self.d = []


def test(cls):
print("test {}".format(cls.__name__))
a = cls()
print(a.d)
a.d.append(2)
print(a.d)
a2 = cls()
print(a2.d)

if __name__ == "__main__":
test(A)
test(B)

As a last note: you may have seen (or you may one day see) code using class attributes as default values for instances - or you may be tempted in doing so yourself (hence the mention of a 'default' value for the instance attribute) -, as in your first example. This is bad practice. It's confusing at best, and can lead to wrong behaviour if the attribute is of a mutable type.

Class Attributes and Instance Attributes

I am trying to learn the difference between the instance attributes and class attributes and attributes.

there should be two attributes, class attribute, instance attribute. or instance attribute&none-instance attribute for convenience.

instance attribute

  • these are things activated only when __init__ has been called.
  • you can only access thenm after Class is initialized, which commonly seen as self.xxx.
  • and methods in class with self as its first parameter(normally), these functions are instance methods, and you can only access after you initialized the Class.
  • and methods in class with @property deco, they are instance attributes
common seen instance attribute 

class Name(object):
def __init__(self):
self.age = 100
def func(self):
pass
@property
def age(self):
return self.age

class attribute

non-instance attribute or static attribute, whatever you call it

  • these things stay activated along with Class.
  • which means you can access them whenever you need to, like __init__, even in __new__.
  • they can be called by both Class and instance.
common seen class attribute 

class Name(object):
attr = 'Im class attribute'

there is something else you may should know, class method, which stay activated along with Class but the difference is class method can't be called by instance but only Class. example here

class Name(object)
attr = 'Im class attribute'
@classmethod
def get_attr(cls):
return cls.attr

Conclusion

"class attribute" can be called by both instance and Class

"instance attribute" can only called by instance.

What is the difference between class and instance variables?

When you write a class block, you create class attributes (or class variables). All the names you assign in the class block, including methods you define with def become class attributes.

After a class instance is created, anything with a reference to the instance can create instance attributes on it. Inside methods, the "current" instance is almost always bound to the name self, which is why you are thinking of these as "self variables". Usually in object-oriented design, the code attached to a class is supposed to have control over the attributes of instances of that class, so almost all instance attribute assignment is done inside methods, using the reference to the instance received in the self parameter of the method.

Class attributes are often compared to static variables (or methods) as found in languages like Java, C#, or C++. However, if you want to aim for deeper understanding I would avoid thinking of class attributes as "the same" as static variables. While they are often used for the same purposes, the underlying concept is quite different. More on this in the "advanced" section below the line.

An example!

class SomeClass:
def __init__(self):
self.foo = 'I am an instance attribute called foo'
self.foo_list = []

bar = 'I am a class attribute called bar'
bar_list = []

After executing this block, there is a class SomeClass, with 3 class attributes: __init__, bar, and bar_list.

Then we'll create an instance:

instance = SomeClass()

When this happens, SomeClass's __init__ method is executed, receiving the new instance in its self parameter. This method creates two instance attributes: foo and foo_list. Then this instance is assigned into the instance variable, so it's bound to a thing with those two instance attributes: foo and foo_list.

But:

print instance.bar

gives:

I am a class attribute called bar

How did this happen? When we try to retrieve an attribute through the dot syntax, and the attribute doesn't exist, Python goes through a bunch of steps to try and fulfill your request anyway. The next thing it will try is to look at the class attributes of the class of your instance. In this case, it found an attribute bar in SomeClass, so it returned that.

That's also how method calls work by the way. When you call mylist.append(5), for example, mylist doesn't have an attribute named append. But the class of mylist does, and it's bound to a method object. That method object is returned by the mylist.append bit, and then the (5) bit calls the method with the argument 5.

The way this is useful is that all instances of SomeClass will have access to the same bar attribute. We could create a million instances, but we only need to store that one string in memory, because they can all find it.

But you have to be a bit careful. Have a look at the following operations:

sc1 = SomeClass()
sc1.foo_list.append(1)
sc1.bar_list.append(2)

sc2 = SomeClass()
sc2.foo_list.append(10)
sc2.bar_list.append(20)

print sc1.foo_list
print sc1.bar_list

print sc2.foo_list
print sc2.bar_list

What do you think this prints?

[1]
[2, 20]
[10]
[2, 20]

This is because each instance has its own copy of foo_list, so they were appended to separately. But all instances share access to the same bar_list. So when we did sc1.bar_list.append(2) it affected sc2, even though sc2 didn't exist yet! And likewise sc2.bar_list.append(20) affected the bar_list retrieved through sc1. This is often not what you want.


Advanced study follows. :)

To really grok Python, coming from traditional statically typed OO-languages like Java and C#, you have to learn to rethink classes a little bit.

In Java, a class isn't really a thing in its own right. When you write a class you're more declaring a bunch of things that all instances of that class have in common. At runtime, there's only instances (and static methods/variables, but those are really just global variables and functions in a namespace associated with a class, nothing to do with OO really). Classes are the way you write down in your source code what the instances will be like at runtime; they only "exist" in your source code, not in the running program.

In Python, a class is nothing special. It's an object just like anything else. So "class attributes" are in fact exactly the same thing as "instance attributes"; in reality there's just "attributes". The only reason for drawing a distinction is that we tend to use objects which are classes differently from objects which are not classes. The underlying machinery is all the same. This is why I say it would be a mistake to think of class attributes as static variables from other languages.

But the thing that really makes Python classes different from Java-style classes is that just like any other object each class is an instance of some class!

In Python, most classes are instances of a builtin class called type. It is this class that controls the common behaviour of classes, and makes all the OO stuff the way it does. The default OO way of having instances of classes that have their own attributes, and have common methods/attributes defined by their class, is just a protocol in Python. You can change most aspects of it if you want. If you've ever heard of using a metaclass, all that is is defining a class that is an instance of a different class than type.

The only really "special" thing about classes (aside from all the builtin machinery to make them work they way they do by default), is the class block syntax, to make it easier for you to create instances of type. This:

class Foo(BaseFoo):
def __init__(self, foo):
self.foo = foo

z = 28

is roughly equivalent to the following:

def __init__(self, foo):
self.foo = foo

classdict = {'__init__': __init__, 'z': 28 }

Foo = type('Foo', (BaseFoo,) classdict)

And it will arrange for all the contents of classdict to become attributes of the object that gets created.

So then it becomes almost trivial to see that you can access a class attribute by Class.attribute just as easily as i = Class(); i.attribute. Both i and Class are objects, and objects have attributes. This also makes it easy to understand how you can modify a class after it's been created; just assign its attributes the same way you would with any other object!

In fact, instances have no particular special relationship with the class used to create them. The way Python knows which class to search for attributes that aren't found in the instance is by the hidden __class__ attribute. Which you can read to find out what class this is an instance of, just as with any other attribute: c = some_instance.__class__. Now you have a variable c bound to a class, even though it probably doesn't have the same name as the class. You can use this to access class attributes, or even call it to create more instances of it (even though you don't know what class it is!).

And you can even assign to i.__class__ to change what class it is an instance of! If you do this, nothing in particular happens immediately. It's not earth-shattering. All that it means is that when you look up attributes that don't exist in the instance, Python will go look at the new contents of __class__. Since that includes most methods, and methods usually expect the instance they're operating on to be in certain states, this usually results in errors if you do it at random, and it's very confusing, but it can be done. If you're very careful, the thing you store in __class__ doesn't even have to be a class object; all Python's going to do with it is look up attributes under certain circumstances, so all you need is an object that has the right kind of attributes (some caveats aside where Python does get picky about things being classes or instances of a particular class).

That's probably enough for now. Hopefully (if you've even read this far) I haven't confused you too much. Python is neat when you learn how it works. :)

Difference between accessing an instance attribute and a class attribute

No, these are two different things.

In Python, everything is an object. Classes are objects, functions are objects and instances are objects. Since everything is an object, everything behaves in a similar way. In your case, you create a class instance (== an object with the type "Class") with the name "pytest". That object has two attributes: i and fuc. i is an instance of "Integer" or "Number", fuc is an instance of "Function".

When you use "pytest.j", you tell python "look up the object pytest and when you have it, look up i". "pytest" is a class instance but that doesn't matter.

When you create an instance of "pytest" (== an object with the type "pytest"), then you have an object which has "defaults". In your case, a is an instance of pytest which means that anything that can't be found in a will be searched in pytest, next.

So a.j means: "Look in a. When it's not there, also look in pytest". But j doesn't exist and Python now has to give you a meaningful error message. It could say "class pytest has no attribute 'j'". This would be correct but meaningless: You would have to figure out yourself that you tried to access j via a. It would be confusing. Guido won't have that.

Therefore, python uses a different error message. Since it does not always have the name of the instance (a), the designers decided to use the type instead, so you get "pytest instance...".



Related Topics



Leave a reply



Submit