16.7. OOP State

  • Definition: state - data stored in object

  • Methods can access and modify state

16.7.1. Vars

class User:
    def __init__(self, firstname, lastname):
        self.firstname = firstname
        self.lastname = lastname
        self._authenticated = False

mark = User('Mark', 'Watney')

vars(mark)
{'firstname': 'Mark', 'lastname': 'Watney', '_authenticated': False}

16.7.2. Methods Can Access State

  • User.is_authenticated()

class User:
    def __init__(self, firstname, lastname):
        self.firstname = firstname
        self.lastname = lastname
        self._authenticated = False

    def is_authenticated(self):
        if self._authenticated:
            return True
        else:
            return False
mark = User('Mark', 'Watney')

vars(mark)
{'firstname': 'Mark', 'lastname': 'Watney', '_authenticated': False}

mark.is_authenticated()
False

16.7.3. Methods Can Modify State

  • User.login()

  • User.logout()

class User:
    def __init__(self, firstname, lastname):
        self.firstname = firstname
        self.lastname = lastname
        self._authenticated = False

    def login(self):
        self._authenticated = True

    def logout(self):
        self._authenticated = False


mark = User('Mark', 'Watney')
vars(mark)
{'firstname': 'Mark', 'lastname': 'Watney', '_authenticated': False}

mark.login()
vars(mark)
{'firstname': 'Mark', 'lastname': 'Watney', '_authenticated': True}

mark.logout()
vars(mark)
{'firstname': 'Mark', 'lastname': 'Watney', '_authenticated': False}

16.7.4. Use Case - 1

class Car:
    def __init__(self):
        self.engine = 'off'

    def engine_start(self):
        self.engine = 'on'

    def engine_stop(self):
        self.engine = 'off'

    def drive_to(self, location):
        if self.engine != 'on':
            raise RuntimeError('Engine must be turned on to drive')
        else:
            return f'Driving to {location}'


maluch = Car()

maluch.drive_to('Cologne, Germany')
Traceback (most recent call last):
RuntimeError: Engine must be turned on to drive

maluch.engine
'off'

maluch.engine_start()
maluch.engine
'on'

maluch.drive_to('Cologne, Germany')
'Driving to Cologne, Germany'

maluch.engine_stop()
maluch.engine
'off'

16.7.5. Use Case - 2

class Point:
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

    def get_coordinates(self):
        return self.x, self.y, self.z

    def show(self):
        return f'Point(x={self.x}, y={self.y}, z={self.z})'


point = Point(x=1, y=2, z=3)

point.get_coordinates()
(1, 2, 3)

point.show()
'Point(x=1, y=2, z=3)'

16.7.6. Use Case - 3

class Counter:
    def __init__(self):
        self.current_value = 0

    def increment(self):
        self.current_value += 1

    def decrement(self):
        self.current_value -= 1
        if self.current_value < 0:
            raise ValueError('Cannot decrement below zero')

    def show(self):
        return self.current_value


c = Counter()

c.increment()
c.increment()
c.show()
2

c.decrement()
c.decrement()
c.show()
0

c.decrement()
Traceback (most recent call last):
ValueError: Cannot decrement below zero

16.7.7. Assignments

# %% About
# - Name: OOP State Auth
# - Difficulty: easy
# - Lines: 5
# - Minutes: 3

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Modify class `User`
# 2. Add method `is_authenticated` returning:
#    - `True` if field `_authenticated` is True
#    - `False` if field `_authenticated` is False
# 3. Run doctests - all must succeed

# %% Polish
# 1. Zmodyfikuj klasę `User`
# 2. Dodaj metodę `is_authenticated` zwracającą:
#    - `True` jeśli pole `_authenticated` jest True
#    - `False` jeśli pole `_authenticated` jest False
# 3. Uruchom doctesty - wszystkie muszą się powieść

# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> from inspect import isclass, ismethod

>>> assert isclass(User)
>>> mark = User('Mark', 'Watney')
>>> assert ismethod(mark.is_authenticated)
>>> assert hasattr(mark, '_authenticated')
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
from typing import Callable
User: type
is_authenticated: Callable[[object], bool]

# %% Data

# %% Result
class User:
    def __init__(self, firstname, lastname):
        self.firstname = firstname
        self.lastname = lastname
        self._authenticated = False

# %% About
# - Name: OOP State Login/Logout
# - Difficulty: easy
# - Lines: 4
# - Minutes: 3

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Modify class `User`
# 2. Add method `login`, setting field `_authenticated` to `True`
# 3. Add method `logout`, setting field `_authenticated` to `False`
# 4. Run doctests - all must succeed

# %% Polish
# 1. Zmodyfikuj klasę `User`
# 2. Dodaj metodę `login`, ustawiającą pole `_authenticated` na `True`
# 3. Dodaj metodę `logout`, ustawiającą pole `_authenticated` na `False`
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> from inspect import isclass, ismethod

>>> assert isclass(User)
>>> mark = User('Mark', 'Watney')
>>> assert ismethod(mark.login)
>>> assert ismethod(mark.logout)
>>> assert hasattr(mark, '_authenticated')
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
from typing import Callable
User: type
login: Callable[[object], None]
logout: Callable[[object], None]

# %% Data

# %% Result
class User:
    def __init__(self, firstname, lastname):
        self.firstname = firstname
        self.lastname = lastname
        self._authenticated = False

# %% About
# - Name: OOP State EditProfile
# - Difficulty: easy
# - Lines: 5
# - Minutes: 3

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Modify class `User`
# 2. Add method `edit_profile()`:
#    - Arguments: `firstname`, `lastname`
#    - Method checks if user is authenticated
#    - If yes, set instance fields values
#    - If not, raise `PermissionError` with message `User is not authenticated`
# 3. Run doctests - all must succeed

# %% Polish
# 1. Zmodyfikuj klasę `User`
# 2. Dodaj metodę `edit_profile()`:
#    - Argumenty: `firstname`, `lastname`
#    - Metoda sprawdza czy użytkownik jest uwierzytelniony
#    - Jeśli tak, to ustawia wartości pól instancji
#    - Jeśli nie, podnieś `PermissionError` z komunikatem `User is not authenticated`
# 3. Uruchom doctesty - wszystkie muszą się powieść

# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> from inspect import isclass, ismethod

>>> assert isclass(User)
>>> mark = User('Mark', 'Watney')
>>> assert ismethod(mark.login)
>>> assert ismethod(mark.logout)
>>> assert hasattr(mark, '_authenticated')
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
from typing import Callable
User: type
edit_profile: Callable[[object, str, str], None]

# %% Data

# %% Result
class User:
    def __init__(self, firstname, lastname):
        self.firstname = firstname
        self.lastname = lastname
        self._authenticated = False

    def login(self):
        self._authenticated = True

    def logout(self):
        self._authenticated = False

    def is_authenticated(self):
        if self._authenticated:
            return True
        else:
            return False