Python Tutorial_ Class vs. Instance Attributes
Python Tutorial_ Class vs. Instance Attributes
Home Python 2 Tutorial Python 3 Tutorial Advanced Topics Numerical Programming Machine Learning Tkinter Tutorial Contact
"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.)
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:
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())
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())
$ python3 static_methods4.py
<class '__main__.Robot'>, 0)
<class '__main__.Robot'>, 1)
<class '__main__.Robot'>, 2)
<class '__main__.Robot'>, 2)
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):
@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)
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()
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()
© 2011 - 2018, Bernd Klein, Bodenseo; Design by Denise Mitchinson adapted for python-course.eu by Bernd Klein