Accessors and mutators in Python

The concept of object-oriented programming is related to the concept of encapsulation, i.e. hiding class fields and making only public methods (public API) available to read or change the values ​​of these fields. In Java, for example, it is solved at the language level using the private access modifier.

Python does not support such encapsulation. Using private variables like: _variable is just a matter of convention.

Consider the following example where we create a class to represent an employee:

class Employee:
	def __init__(self, name, salary, phone):
	    self.name = name
	    self.salary = salary
	    self.phone = phone

In Java, you should declare the name, salary, and phone variables private and refer to them via the getters and setters . In Python, it is not recommended to write accessor whose sole purpose is to return an attribute value or mutator to set an attribute value. Instead, you can refer to these fields directly. This has many advantages, but the advantages of encapsulating e.g.

johnDoe = Employee('John Doe', 8000, '555 111 22 33')
johnDoe.salary = 9000
print(johnDoe.salary)

The use of direct access to class attributes is a problem when it is necessary to make changes, e.g. introducing correctness control of the entered data.

Based on the code of the previously created Employee class, let’s assume that we would like to validate the entered telephone number, i.e. whether it has the appropriate number of digits, and at the same time remove unnecessary characters that are not digits.

To do this, we don’t need to change the way we communicate with the phone variable. We can still refer directly to the variable name. This is possible thanks to the @property decorator.

class Employee:

    def __init__(self, name, salary, phone):
        self.name = name
        self.salary = salary
        self.phone = phone
    @property
        def phone(self):
           return self._phone
    @phone.setter
        def phone(self, value):
            phone = ''.join(filter(lambda x: x.isdigit(), value))
            if len(phone) != 10:
                raise ValueError('Wrong phone number!')
            self._phone = phone

Calling the class’s constructor sets individual class attributes, while assigning the phone argument to the self.phone attribute causes the mutator to be called and thus validating the entered phone number at the time of creating the Employee class object.

Similarly, assigning a new value to the phone attribute will call the appropriate validation method, i.e.

johnDoe = Employee('John Doe', 8000, "555 111 22 33")
johnDoe.phone = '000' # raises ValueError - incorrect number length

Basics of Exception Handling in Python #3

It is also worth mentioning the optional else procedure, which is executed only when there is no exception in the related try , i.e.

  • if an else procedure is present, it must follow except procedure
  • there can be only one else procedure (or none)

Use the else proc. if you don’t want a certain piece of code to be contained in a try part. If you put all the code in a try procedure instead, the cause of the exception would be potentially more difficult to locate.

Another optional procedure is a finally proc., which executes whether or not there is an exception:

  • if there is a finally proc. it must be placed after except and else (if present).
  • there can be only one finally proc. (or none)

The finally block is mainly used for releasing access to external resources eg. databases.

Basics of Exception Handling in Python #2

Of course, we can also use the syntax in which the exception description is assigned to a variable and we can then display it in the handling procedure, e.g.

except NameError as e:
    print('Message:', e)

You can create a common handler for several exceptions by putting class names in a tuple, e.g.

except (ZeroDivisionError, NameError):
    # Here we put the handler for these two exceptions

What you should pay attention to is that exceptions that are child classes in the hierarchy of exception classes are handled before the classes from which they inherit. The wrong order will result in the exception being handled by the more general procedure that came first, i.e.

except Exception:
    print('It catches all exceptions!')
except NameError:
    print('NameError exception')

In the above example, NameError will be handled by the procedure in the first except block. Despite the NameError exception, the following message will be displayed: It catches all exceptions! and the routine that specifically handles this exception (and displays NameError exception in this case) will not be executed.

>>part three<<

Basics of Exception Handling in Python #1

Errors that show up during the execution of the program and are not syntax errors belong to the so-called exceptions. The list of exceptions is quite extensive >>see<<

We can handle these exceptions by putting code that can cause an exception in a try block, i.e.

ry:
    # Here we put code that can raise an exception or exceptions

and the code to handle the exception in the except block (equivalent to Java catch), i.e.

except:
    # Here we put the exception handling code

It is more useful to react to specific exceptions than to handle all of them “in bulk”. The except statement itself without specifying the name of the error class can be useful if you want to catch an exception that has not yet been handled by an earlier except block, e.g.

except ZeroDivisionError:
    # Here we put the code to handle the ZeroDivisionError exception

except NameError:
    # Here we put the code to handle the NameError exception

except:
    # Here we catch the remaining unhandled exceptions

>>part 2<<

Simple calendar display tool


This program is a simple equivalent of the console tool cal, which displays a calendar for a given year and month in the console.

If no arguments are given, it prints the calendar for the current year and month by default. /screenshot/

#!/usr/bin/env python

from datetime import datetime

from calendar import monthrange, weekheader, weekday

from sys import stdout


def cal(year=datetime.today().year, month=datetime.today().month):
    """
    Prints month calendar for given year and month.
    """

    this_year = year
    this_month = month

    # number of all days in month
    days_in_month = monthrange(this_year, this_month)[1]

    # which week day is the first day of month
    first_day_of_month = weekday(this_year, this_month, 1)

    # prints header of calendar (width 5)
    print(weekheader(5))

    # positioning loop
    # for proper position of the first element
    for i in range(first_day_of_month):
        stdout.write(6 * ' ')

    i = 1
    while i <= days_in_month:
        stdout.write(' {:>2}   '.format(i))
        # new line if sunday
        if weekday(this_year, this_month, i) == 6:
            print('')
        i += 1
    print('')

if __name__ == '__main__':
    cal()