Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
3 views

Python Tutorial_ Class vs. Instance Attributes

The document provides an overview of class and instance attributes in Python, explaining the differences between them and how to use them effectively. It includes examples of defining class attributes, modifying them, and the use of static and class methods. Additionally, it highlights the importance of understanding these concepts for effective object-oriented programming in Python.

Uploaded by

Sentinel
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

Python Tutorial_ Class vs. Instance Attributes

The document provides an overview of class and instance attributes in Python, explaining the differences between them and how to use them effectively. It includes examples of defining class attributes, modifying them, and the use of static and class methods. Additionally, it highlights the importance of understanding these concepts for effective object-oriented programming in Python.

Uploaded by

Sentinel
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 1

Python Course

Home Python 2 Tutorial Python 3 Tutorial Advanced Topics Numerical Programming Machine Learning Tkinter Tutorial Contact

Previous Chapter: Object Oriented Programming


Next Chapter: Properties vs. getters and setters

Class and Instance Attributes

Follow Bernd Klein,


the author of this
Class Attributes website, at Google+:
Bernd Klein on
Python 3
Google
Tutorial Instance attributes are owned by the specific instances of a class. This means for two different instances the instance attributes are usually different. You should by
now be familiar with this concept which we introduced the previous chapter.
Bernd Klein on
The Origins of Facebook
We can also define attributes at the class level. Class attributes are attributes which are owned by the class itself. They will be shared by all the instances of the
Python
class. Therefore they have the same value for every instance. We define class attributes outside of all the methods, usually they are placed at the top, right below
Starting with
the class header.
Python: The Search this website:
Interactive Shell We can see in the following interactive Python session that the class attribute "a" is the same for all instances, in our example "x" and "y". Besides this, we see that
Executing a we can access a class attribute via an instance or via the class name: Go
Script
Indentation This topic in German
>>> class A: / Deutsche
Data Types and ... a = "I am a class attribute!"
Variables Übersetzung:
...
Klassen- und
Operators >>> x = A()
>>> y = A() Instanzattribute
Sequential Data
>>> x.a
Types: Lists and 'I am a class attribute!' Classroom
Strings >>> y.a
'I am a class attribute!'
Training
List
>>> A.a Courses
Manipulations
'I am a class attribute!'
Shallow and >>> The goal of this
Deep Copy website is to provide
Dictionaries 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. We demonstrate this in the following educational material,
Sets and Frozen example: allowing you to learn
Sets Python on your own.
>>> class A:
An Extensive ... a = "I am a class attribute!" Nevertheless, it is
Example Using ... faster and more
>>> x = A() efficient to attend a
Sets
>>> y = A() "real" Python course
input via the >>> x.a = "This creates a new instance attribute for x!" in a classroom, with
keyboard >>> y.a an experienced
Conditional 'I am a class attribute!' trainer. So why not
Statements >>> A.a
attend one of the live
'I am a class attribute!'
Loops, while >>> A.a = "This is changing the class attribute 'a'!" Python courses in
Loop >>> A.a Strasbourg, Paris,
For Loops "This is changing the class attribute 'a'!" Luxembourg,
Difference
>>> y.a Amsterdam, Zürich /
"This is changing the class attribute 'a'!" Zurich, Vienna /
between >>> # but x.a is still the previously created instance variable: Wien, London, Berlin,
interators und ...
Munich, Hamburg,
Iterables >>> x.a
'This creates a new instance attribute for x!' Frankfurt or Lake
Output with Print Constance by Bernd
>>>
Formatted output Klein, the author of
with string Python's class attributes and object attributes are stored in separate dictionaries, as we can see here: this tutorial?
modulo and the
>>> x.__dict__
format method
{'a': 'This creates a new instance attribute for x!'}
Functions >>> y.__dict__
Onsite Training
Recursion and {} Courses
Recursive >>> A.__dict__
dict_proxy({'a': "This is changing the class attribute 'a'!", '__dict__': <attribute '__dict__' of 'A' objects>, '__module__': '__main__', '__weakref__': <attribute Let us come to your
Functions
'__weakref__' of 'A' objects>, '__doc__': None}) company,
Parameter >>> x.__class__.__dict__
organization or
Passing in dict_proxy({'a': "This is changing the class attribute 'a'!", '__dict__': <attribute '__dict__' of 'A' objects>, '__module__': '__main__', '__weakref__': <attribute
'__weakref__' of 'A' objects>, '__doc__': None}) institute and train
Functions your employees, as
>>>
Namespaces we've done it many
Global and Local times in Amsterdam
Variables (The Netherlands),
Decorators Berlin (Germany),
Memoization with Bern (Switzerland),
Example with Class Attributes
Decorators Basel (Switzerland),
Zurich (Switzerland),
Read and Write Isaac Asimov devised and introduced the so-called "Three Laws of Robotics" in 1942. The appeared in his story "Runaround". His three laws have been picked up by many science fiction writers. As we have started
Locarno
Files manufacturing robots in Python, it's high time to make sure that they obey Asimovs three laws. As they are the same for every instance, i.e. robot, we will create a class attribute Three_Laws. This attribute is a
(Switzerland), Den
Modular tuple with the three laws.
Haag (The Hague),
Programming Hamburg (Germany),
and Modules class Robot: Frankfurt (Germany),
Packages in Toronto (Canada),
Python Three_Laws = ( Edmonton (Canada),
Regular """A robot may not injure a human being or, through inaction, allow a human being to come to harm.""", Munich (Germany)
"""A robot must obey the orders given to it by human beings, except where such orders would conflict with the First Law.,""", and many other
Expressions """A robot must protect its own existence as long as such protection does not conflict with the First or Second Law.""" cities. We do training
Regular )
courses in England,
Expressions, Switzerland,
def __init__(self, name, build_year):
Advanced Liechtenstein,
self.name = name
Lambda self.build_year = build_year Austria, Germany,
Operator, Filter, France, Belgium, the
Reduce and Map # other methods as usual Netherlands,
List Luxembourg, Poland,
Comprehension UK, Italy and other
As we mentioned before, we can access a class attribute via instance or via the class name. You can see in the following that we need no instance: locations in Europe
Iterators and
and in Canada.
Generators
Exception >>> from robot_asimov import Robot
This way you will get
>>> for number, text in enumerate(Robot.Three_Laws):
Handling a perfect training up
... print(str(number+1) + ":\n" + text)
Tests, DocTests, ... to your needs and it
UnitTests 1: will be extremely cost
Object Oriented A robot may not injure a human being or, through inaction, allow a human being to come to harm. efficient as well.
2: Contact us so we can
Programming
A robot must obey the orders given to it by human beings, except where such orders would conflict with the First Law., define and find the
Class and 3:
best course
Instance A robot must protect its own existence as long as such protection does not conflict with the First or Second Law.
>>> curriculum to meet
Attributes your needs, and
Properties vs. schedule course
getters and sessions to be held at
We demonstrate in the following example, how you can count instance with class attributes. All we have to do is
setters your location.
Inheritance to create a class attribute, which we call "counter" in our example
Multiple to increment this attribute by 1 every time a new instance will be create
Inheritance to decrement the attribute by 1 every time an instance will be destroyed Skilled Python
Magic Methods Programmers
and Operator
Overloading You are looking for
class C: experienced Python
OOP, Inheritance
developers or
Example
counter = 0 programmers? We
Slots can help you, please
Classes and def __init__(self): contact us.
Class Creation type(self).counter += 1
Road to def __del__(self): Quote of the
Metaclasses type(self).counter -= 1 Day:
Metaclasses
Metaclass Use if __name__ == "__main__":
We can only see a
x = C()
Case: Count print("Number of instances: : " + str(C.counter)) short distance ahead,
Function Calls y = C() but we can see
Abstract Classes print("Number of instances: : " + str(C.counter)) plenty there that
del x needs to be done.
print("Number of instances: : " + str(C.counter)) Alan Turing
del y
Object-oriented print("Number of instances: : " + str(C.counter))
Programming

"Certainly not every Principially, we could have written C.counter instead of type(self).counter, because type(self) will be evaluated to "C" anyway. But we will see later, that type(self) makes sense, if we use such a class as a
good program is superclass.
Data Protection
object-oriented, and Declaration
not every object- If we start the previous program, we will get the following results:
oriented program is
Data Protection
good."
$ python3 counting_instances.py Declaration
(Bjarne Stroustrup,
Number of instances: : 1
Danish computer Number of instances: : 2
scientist, best known Number of instances: : 1
for the creation and Number of instances: : 0
the development of
the widely used C++
programming
language.)

"Object-oriented Static Methods


programming is an
exceptionally bad
We used class attributes as public attributes in the previous section. Of course, we can make public attributes private as well. We can do this by adding the double underscore again. If we do so, we need a
idea which could only
possibility to access and change these private class attributes. We could use instance methods for this purpose:
have originated in
California."
(Edsger Dijkstra, class Robot:
(Dutch computer __counter = 0
Scientist, 1930-2002)
def __init__(self):
Dijkstra also said: type(self).__counter += 1
"... what society
def RobotInstances(self):
overwhelmingly asks return Robot.__counter
for is snake oil. Of
course, the snake oil
has the most if __name__ == "__main__":
impressive names - x = Robot()
otherwise you would print(x.RobotInstances())
y = Robot()
be selling nothing -
print(x.RobotInstances())
like "Structured
Analysis and Design",
"Software
This is not a good idea for two reasons: First of all, because the number of robots has nothing to do with a single robot instance and secondly because we can't inquire the number of robots before we haven't
Engineering",
created an instance.
"Maturity Models",
If we try to invoke the method with the class name Robot.RobotInstances(), we get an error message, because it needs an instance as an argument:
"Management
Information >>> Robot.RobotInstances()
Systems", Traceback (most recent call last):
"Integrated Project File "<stdin>", line 1, in <module>
Support TypeError: RobotInstances() takes exactly 1 argument (0 given)
Environments"
"Object-Orientation"
and "Business The next idea, which still doesn't solve our problem, consists in omitting the parameter "self":
Process Re-
engineering"
class Robot:
__counter = 0

def __init__(self):
This website is type(self).__counter += 1
supported by:
def RobotInstances():
return Robot.__counter
Linux and Python
Courses and
Seminars Now it's possible to access the method via the class name, but we can't call it via an instance:

>>> from static_methods2 import Robot


>>> Robot.RobotInstances()
0
>>> x = Robot()
>>> x.RobotInstances()
Traceback (most recent call last):

File "<stdin>", line 1, in <module>


TypeError: RobotInstances() takes no arguments (1 given)
>>>

The call "x.RobotInstances()" is treated as an instance method call and an instance method needs a reference to the instance as the first parameter.

So, what do we want? We want a method, which we can call via the class name or via the instance name without the necessity of passing a reference to an instance to it.

The solution consists in static methods, which don't need a reference to an instance.
It's easy to turn a method into a static method. All we have to do is to add a line with "@staticmethod" directly in front of the method header. It's the decorator syntax.

You can see in the following example that we can now use our method RobotInstances the way we wanted:

class Robot:
__counter = 0

def __init__(self):
type(self).__counter += 1

@staticmethod
def RobotInstances():
return Robot.__counter

if __name__ == "__main__":
print(Robot.RobotInstances())
x = Robot()
print(x.RobotInstances())
y = Robot()
print(x.RobotInstances())
print(Robot.RobotInstances())

We will get the following output:

0
1
2
2

Class Methods

Static methods shouldn't be confused with class methods. Like static methods class methods are not bound to instances, but unlike static methods class methods are bound to a class. The first parameter of a class
method is a reference to a class, i.e. a class object. They can be called via an instance or the class name.

class Robot:
__counter = 0

def __init__(self):
type(self).__counter += 1

@classmethod
def RobotInstances(cls):
return cls, Robot.__counter

if __name__ == "__main__":
print(Robot.RobotInstances())
x = Robot()
print(x.RobotInstances())
y = Robot()
print(x.RobotInstances())
print(Robot.RobotInstances())

The output looks like this:

$ python3 static_methods4.py
<class '__main__.Robot'>, 0)
<class '__main__.Robot'>, 1)
<class '__main__.Robot'>, 2)
<class '__main__.Robot'>, 2)

The use cases of class methods:

the are used in the definition of the so-called factory methods, which we will not cover here.
They are often used, where we have static methods, which have to call other static methods. To do this, we would have to hard code the class name, if we had to use static methods. This is a problem, if we
are in a use case, where we have inherited classes.

The following program contains a fraction class, which is still not complete. If you work with fractions, you need to be capable of reducing fractions, e.g. the fraction 8/24 can be reduced to 1/3. We can reduce a
fraction to lowest terms by dividing both the numerator and denominator by the Greatest Common Divisor (GCD).

We have defined a static gcd function to calculate the greatest common divisor of two numbers. the greatest common divisor (gcd) of two or more integers (at least one of which is not zero), is the largest positive
integer that divides the numbers without a remainder. For example, the 'GCD of 8 and 24 is 8. The static method "gcd" is called by our class method "reduce" with "cls.gcd(n1, n2)". "CLS" is a reference to
"fraction".

class fraction(object):

def __init__(self, n, d):


self.numerator, self.denominator = fraction.reduce(n, d)

@staticmethod
def gcd(a,b):
while b != 0:
a, b = b, a%b
return a

@classmethod
def reduce(cls, n1, n2):
g = cls.gcd(n1, n2)
return (n1 // g, n2 // g)

def __str__(self):
return str(self.numerator)+'/'+str(self.denominator)

Using this class:

>>> from fraction1 import fraction


>>> x = fraction(8,24)
>>> print(x)
1/3
>>>

We will demonstrate in our last example the usefulness of class methods in inheritance. We define a class "Pets" with a method "about". This class will be inherited in a subclass "Dogs" and "Cats". The method
"about" will be inherited as well. We will define the method "about" as a "staticmethod" in our first implementation to show the disadvantage of this approach:

class Pets:
name = "pet animals"

@staticmethod
def about():
print("This class is about {}!".format(Pets.name))

class Dogs(Pets):
name = "'man's best friends' (Frederick II)"

class Cats(Pets):
name = "cats"

p = Pets()
p.about()
d = Dogs()
d.about()
c = Cats()
c.about()

We get the following output:

This class is about pet animals!


This class is about pet animals!
This class is about pet animals!

Especially, in the case of c.about() and d.about(), we would have preferred a more specific phrase! The "problem" is that the method "about" doesn't know that it has been called by an instance of the Dogs or Cats
class.
We decorate it now with a classmethod decorator instead of a staticmethod decorator:

class Pets:
name = "pet animals"

@classmethod
def about(cls):
print("This class is about {}!".format(cls.name))

class Dogs(Pets):
name = "'man's best friends' (Frederick II)"

class Cats(Pets):
name = "cats"

p = Pets()
p.about()

d = Dogs()
d.about()

c = Cats()
c.about()

The output is now like we wanted it to be:

This class is about pet animals!


This class is about 'man's best friends' (Frederick II)!
This class is about cats!

Previous Chapter: Object Oriented Programming


Next Chapter: Properties vs. getters and setters

© 2011 - 2018, Bernd Klein, Bodenseo; Design by Denise Mitchinson adapted for python-course.eu by Bernd Klein

You might also like