Today we'll take a look at some examples of object-oriented code in Python.
As I'm learning this topic almost in the same time I'm writing this, I'll do lot of mistakes - especially because some topics seem different than C++/Java/C# style I'm used to.
Ok, let's begin with creating a class with one method, creating an object of this class and calling this method.
# !/usr/bin/python3
class ClassWithMethod:
def say_something(self):
print("Elementary!")
def main():
objectWithMethod = ClassWithMethod()
objectWithMethod.say_something()
if __name__ == "__main__":
main()
We define a class ClassWithMethod, with one method: say_something(self) simply printing some text. self param is, as we will see, the reference to the calling object. For now, we just instantiate the class:
objectWithMethod = ClassWithMethod()
...and call the method:
objectWithMethod.say_something()
The result of running this code is:
Elementary!
Now let's define other class with one field (or attribute).
class ClassWithField:
def __init__(self, name):
self.name = name
To instantiate and use it we can add the following lines to main function:
objectWithField = ClassWithField("Lestrade")
print(objectWithField.name)
As we can see, __init__(self, name) works as a constructor with one parameter. The code now prints:
What about a method? Well, take a look at another class:
class ClassWithFieldAndMethod:
def tellName(self):
print(self.name)
If we instantiate it, and set field name to something, we can call our method (in main!):
objectWithFieldAndMethod = ClassWithFieldAndMethod()
objectWithFieldAndMethod.name = "John Watson"
objectWithFieldAndMethod.tellName()
Giving result:
John Watson
What's interesting, we can add fields to a class object on the fly, without declaring them. Add this to main:
objectWithFieldAndMethod2 = ClassWithFieldAndMethod()
objectWithFieldAndMethod2.name = "Sherlock Holmes"
objectWithFieldAndMethod2.tellName()
# you can add field on the fly...
# ... to the object!
objectWithFieldAndMethod2.age = 33
# you can do this only if field has been added:
print(objectWithFieldAndMethod2.age)
We create another object (objectWithFieldAndMethod2), add the field named age to it (simply by initializing it) and then we can access it. The code execution result becomes:
Elementary!
Lestrade
John Watson
Sherlock Holmes
33
Please note we've added the age field to our object, not class. It means that if we try to get to this field on our previous object, we get error.
def main():
objectWithMethod = ClassWithMethod()
objectWithMethod.say_something()
objectWithField = ClassWithField("Lestrade")
print(objectWithField.name)
objectWithFieldAndMethod = ClassWithFieldAndMethod()
objectWithFieldAndMethod.name = "John Watson"
objectWithFieldAndMethod.tellName()
objectWithFieldAndMethod2 = ClassWithFieldAndMethod()
objectWithFieldAndMethod2.name = "Sherlock Holmes"
objectWithFieldAndMethod2.tellName()
# you can add field on the fly...
# ... to the object!
objectWithFieldAndMethod2.age = 33
# you can do this only if field has been added:
print(objectWithFieldAndMethod2.age)
# this results in error!
print(objectWithFieldAndMethod.age)
...gives:
Elementary!
Lestrade
John Watson
Sherlock Holmes
33
Traceback (most recent call last):
File "d:\Projekty\Python\controlflow.py", line 71, in <module>
main()
File "d:\Projekty\Python\controlflow.py", line 50, in main
print(objectWithFieldAndMethod.age)
AttributeError: 'ClassWithFieldAndMethod' object has no attribute 'age'
What about private fields? We define it by preceding initialized field name with double underscore:
class ClassWithPrivateFieldAndMethod:
def setName(self, name):
self.__name = name
We can create an object of this class and call the method to set field __name:
objectWithPrivateField = ClassWithPrivateFieldAndMethod()
objectWithPrivateField.setName("Mary Watson")
..but we can't do this:
print(objectWithPrivateField.__name)
... as the program will behave as such attribute doesn't exist:
File "d:\Projekty\Python\controlflow.py", line 71, in <module>
main()
File "d:\Projekty\Python\controlflow.py", line 55, in main
print(objectWithPrivateField.__name)
AttributeError: 'ClassWithPrivateFieldAndMethod' object
has no attribute '__name'
BUT in fact, we can access this field - as "private" in Python does not mean the attribute is unaccesible - it rather means it should not be accessed. So we can access this attrbute using the following syntax: objectName._ClassName__field_name (please note the underscores, one before class name and two before field name):
print(objectWithPrivateField._ClassWithPrivateFieldAndMethod__name)
This gives us:
Mary Watson
Now let's take a look at a param passed in the constructor.
The following class:
class ClassWithParamaterInConstructor:
def __init__(self, name):
self.name = name
...can be created like this:
objectConstructedWithParam = ClassWithParamaterInConstructor("Moriarty")
We can then normally access the name field, so:
print(objectConstructedWithParam.name)
...gives us this ominous result:
Moriarty
The last thing: static (class) fields. They're defined simply in class body, not in the methods:
class ClassWithStaticField:
field = 40
But beware: they can be accessed with both class name and object name. In the first case, they behave like static. In hte latter - they're simply fields, initialized with given value.
An example should give us more light on this:
stat1 = ClassWithStaticField()
stat2 = ClassWithStaticField()
stat2.field = 41
print(stat1.field) # object's field default value is 40
print(stat2.field) # this object's field value is 41
print(ClassWithStaticField.field) # static field value is still 40!
... which code gives us:
We create two objects of class ClassWithStaticField, stat1 and stat2. Then we assign value 41 to the field field of the first object. It changes this instance's value, but the field field of object stat1 stays the same! What's more - the ClassWithStaticField.field is also another reference. We can change it, of course, by calling:
ClassWithStaticField.field = 42
So the code:
stat1 = ClassWithStaticField()
stat2 = ClassWithStaticField()
stat2.field = 41
print(stat1.field) # object's field default value is 40
print(stat2.field) # this object's field value is 41
print(stat1.field) # object's field default value is 40
print(ClassWithStaticField.field) # static field value is still 40!
ClassWithStaticField.field = 42
print(ClassWithStaticField.field) # not anymore!
results in:
Confusing? Well, for me it certainly is ;D The full program listing illustrating the concepts above looks as follows:
... and gives the following result:
Elementary!
Lestrade
John Watson
Sherlock Holmes
33
Mary Watson
Moriarty
40
41
40
40
42
I hope it happens to be useful for some of you :)