16.10. OOP Method About

  • Methods are functions in the class

  • Prevents copy-paste code

  • Improves readability

  • Improves refactoring

  • Decomposes bigger problem into smaller chunks

method

Functions in the class which takes instance as first argument (self)

self

Instance on which method was called.

16.10.1. Define

  • At definition - self should always be a first parameter

>>> class User:
...     def login(self):
...         print(f'Logged in')
...
>>>
>>> mark = User()
>>> mark.login()
Logged in

16.10.2. Self

  • At definition - self should always be a first parameter

  • When called Python will pass an instance as self

  • You don't do that manually

  • Later you will learn more advanced things like static methods etc.

>>> class User:
...     def login(self):
...         print(f'Logged in')
>>> mark = User()
>>> mark.login()
Logged in
>>> User.login()
Traceback (most recent call last):
TypeError: User.login() missing 1 required positional argument: 'self'
>>> User.login(mark)
Logged in

16.10.3. Return

>>> class User:
...     def login(self):
...         return 'Logged in'
...
>>>
>>> mark = User()
>>> result = mark.login()
>>>
>>> print(result)
Logged in

16.10.4. Exceptions

>>> class User:
...     def login(self):
...         raise PermissionError
...
>>>
>>> mark = User()
>>> mark.login()
Traceback (most recent call last):
PermissionError

16.10.5. Use Case - 0x01

>>> class User:
...     def __init__(self, firstname, lastname):
...         self.firstname = firstname
...         self.lastname = lastname
...
...     def say_hello(self):
...         return f'Hello {self.firstname} {self.lastname}'
...
...     def say_goodbye(self):
...         return f'Goodbye {self.firstname} {self.lastname}'
>>> mark = User('Mark', 'Watney')
>>> melissa = User('Melissa', 'Lewis')
>>>
>>>
>>> mark.say_hello()
'Hello Mark Watney'
>>>
>>> melissa.say_hello()
'Hello Melissa Lewis'
>>>
>>>
>>> vars(mark)
{'firstname': 'Mark', 'lastname': 'Watney'}
>>>
>>> vars(melissa)
{'firstname': 'Melissa', 'lastname': 'Lewis'}

16.10.6. Use Case - 0x02

>>> class User:
...     firstname: str
...     lastname: str
...     is_authenticated: bool
...
...     def __init__(self, firstname, lastname):
...         self.firstname = firstname
...         self.lastname = lastname
...         self.is_authenticated = False
...
...     def login(self, username, password):
...         if username == 'mwatney' and password == 'nasa':
...             self.is_authenticated = True
...         else:
...             raise PermissionError('Invalid username and/or password')
...
...     def logout(self):
...         self.is_authenticated = False
...
>>> mark = User('Mark', 'Watney')
>>> melissa = User('Melissa', 'Lewis')
>>>
>>>
>>> mark.is_authenticated
False
>>>
>>> melissa.is_authenticated
False
>>>
>>>
>>> vars(mark)
{'firstname': 'Mark', 'lastname': 'Watney', 'is_authenticated': False}
>>>
>>> vars(melissa)
{'firstname': 'Melissa', 'lastname': 'Lewis', 'is_authenticated': False}
>>> mark.login(username='mwatney', password='nasa')
>>>
>>>
>>> mark.is_authenticated
True
>>>
>>> melissa.is_authenticated
False
>>>
>>>
>>> vars(mark)
{'firstname': 'Mark', 'lastname': 'Watney', 'is_authenticated': True}
>>>
>>> vars(melissa)
{'firstname': 'Melissa', 'lastname': 'Lewis', 'is_authenticated': False}
>>> melissa.login('mlewis', 'nasa')
Traceback (most recent call last):
PermissionError: Invalid username and/or password
>>>
>>>
>>> mark.is_authenticated
True
>>> melissa.is_authenticated
False
>>>
>>>
>>> vars(mark)
{'firstname': 'Mark', 'lastname': 'Watney', 'is_authenticated': True}
>>>
>>> vars(melissa)
{'firstname': 'Melissa', 'lastname': 'Lewis', 'is_authenticated': False}
>>> mark.logout()
>>>
>>>
>>> mark.is_authenticated
False
>>> melissa.is_authenticated
False
>>>
>>>
>>> vars(mark)
{'firstname': 'Mark', 'lastname': 'Watney', 'is_authenticated': False}
>>>
>>> vars(melissa)
{'firstname': 'Melissa', 'lastname': 'Lewis', 'is_authenticated': False}

16.10.7. Use Case - 0x01

>>> def add(a, b):
...     return a + b
>>>
>>> def sub(a, b):
...     return a - b
>>>
>>> def mul(a, b):
...     return a * b
>>>
>>> def div(a, b):
...     return a / b
>>>
>>> def say_hello():
...     return 'hello'
>>>
>>> def say_goodbye():
...     return 'goodbye'
>>>
>>> def login(username, password):
...     return 'logged-in'
>>>
>>> def logout():
...     return 'logged-out'
>>> class Calculator:
...     def add(self, a, b):
...         return a + b
...
...     def sub(self, a, b):
...         return a - b
...
...     def mul(self, a, b):
...         return a * b
...
...     def div(self, a, b):
...         return a / b
>>>
>>>
>>> class User:
...     def say_hello(self):
...         return 'hello'
...
...     def say_goodbye():
...         return 'goodbye'
...
...     def login(self, username, password):
...         return 'logged-in'
...
...     def logout(self):
...         return 'logged-out'

16.10.8. Use Case - 0x02

  • Staticmethod

>>> class Calculator:
...     def add(self, a, b):
...         return a + b
...
...     def sub(self, a, b):
...         return a - b
...
...     def mul(self, a, b):
...         return a * b
...
...     def div(self, a, b):
...         return a / b
>>>
>>> Calculator.add(a=1, b=2)
Traceback (most recent call last):
TypeError: Calculator.add() missing 1 required positional argument: 'self'
>>>
>>> calc = Calculator()
>>> calc.add(a=1, b=2)
3
>>> class Calculator:
...     def add(a, b):
...         return a + b
...
...     def sub(a, b):
...         return a - b
...
...     def mul(a, b):
...         return a * b
...
...     def div(a, b):
...         return a / b
>>>
>>> Calculator.add(a=1, b=2)
3
>>>
>>> calc = Calculator()
>>> calc.add(a=1, b=2)
Traceback (most recent call last):
TypeError: Calculator.add() got multiple values for argument 'a'
>>> class Calculator:
...     @staticmethod
...     def add(a, b):
...         return a + b
...
...     @staticmethod
...     def sub(a, b):
...         return a - b
...
...     @staticmethod
...     def mul(a, b):
...         return a * b
...
...     @staticmethod
...     def div(a, b):
...         return a / b
>>>
>>> Calculator.add(1,2)
3
>>>
>>> calc = Calculator()
>>> calc.add(a=1, b=2)
3

16.10.9. Use Case - 0x03

>>> class User:
...     def create(self, username, password):
...         self.username = username
...         self.password = password
...         return self
...
...     def login(self):
...         return 'logged-in'
...
...     def logout(self):
...         return 'logged-out'
>>> mark = User.create(username='mwatney', password='nasa')
Traceback (most recent call last):
TypeError: User.create() missing 1 required positional argument: 'self'
>>> mark = User().create(username='mwatney', password='nasa')
>>>
>>> mark.login()
'logged-in'
>>>
>>> mark.logout()
'logged-out'

16.10.10. Use Case - 0x04

>>> class User:
...     @staticmethod
...     def create(username, password):
...         user = object.__new__(User)
...         user.username = username
...         user.password = password
...         return user
...
...     def login(self):
...         return 'logged-in'
...
...     def logout(self):
...         return 'logged-out'
>>> mark = User.create(username='mwatney', password='nasa')
>>>
>>> mark.login()
'logged-in'
>>>
>>> mark.logout()
'logged-out'

16.10.11. Use Case - 0x05

>>> class User:
...     @classmethod
...     def create(cls, username, password):
...         user = object.__new__(cls)
...         user.username = username
...         user.password = password
...         return user
...
...     def login(self):
...         return 'logged-in'
...
...     def logout(self):
...         return 'logged-out'
>>> mark = User.create(username='mwatney', password='nasa')
>>>
>>> mark.login()
'logged-in'
>>>
>>> mark.logout()
'logged-out'

16.10.12. Use Case - 0x06

>>> class TextInput:
...     def __init__(self, name):
...         self.name = name
...
...     def display(self):
...         print(f'Displaying {self.name} text field')
...
>>>
>>> class Button:
...     def __init__(self, name):
...         self.name = name
...
...     def display(self):
...         print(f'Displaing {self.name} button')
...
>>>
>>> login_window = [
...     TextInput('username'),
...     TextInput('password'),
...     Button('submit'),
... ]
>>>
>>> for obj in login_window:
...     obj.display()
...
Displaying username text field
Displaying password text field
Displaing submit button

16.10.13. Use Case - 0x07

>>> class Car:
...     name: str
...     engine: str
...
...     def __init__(self, name):
...         self.name = name
...         self.engine = 'off'
...
...     def start_engine(self):
...         self.engine = 'on'
...
...     def stop_engine(self):
...         self.engine = 'off'
...
...     def drive(self, destination):
...         if self.engine == 'off':
...             raise RuntimeError('Cannot drive while engine is off')
...         else:
...             print(f'Driving to: {destination}')
...
>>>
>>> maluch = Car('Fiat 126p')
>>>
>>> vars(maluch)
{'name': 'Fiat 126p', 'engine': 'off'}
>>>
>>> maluch.drive('Kraków')
Traceback (most recent call last):
RuntimeError: Cannot drive while engine is off
>>>
>>> maluch.start_engine()
>>>
>>> vars(maluch)
{'name': 'Fiat 126p', 'engine': 'on'}
>>>
>>> maluch.drive('Kraków')
Driving to: Kraków
>>>
>>> maluch.stop_engine()
>>>
>>> vars(maluch)
{'name': 'Fiat 126p', 'engine': 'off'}
>>>
>>> maluch.drive('Kraków')
Traceback (most recent call last):
RuntimeError: Cannot drive while engine is off
>>> tesla = Car('Model S')
>>>
>>> tesla.start_engine()
>>>
>>> tesla.drive('Warszawa')
Driving to: Warszawa
>>>
>>>
>>> maluch.drive('Warszawa')
Traceback (most recent call last):
RuntimeError: Cannot drive while engine is off

16.10.14. Use Case - 0x08

>>> class List:
...     def __init__(self, values):
...         self.values = values
...
...     def sort(self):
...         self.values.sort()
...
...     def setitem(self, index, newvalue):
...         self.values[index] = newvalue
...
...     def getitem(self, index):
...         return self.values[index]
...
>>>
>>>
>>> data = List(['a', 'b', 'c'])
>>> data.getitem(0)
'a'
>>> data.getitem(1)
'b'
>>> data.getitem(2)
'c'
>>> data.setitem(1, 'x')
>>>
>>> data.getitem(0)
'a'
>>> data.getitem(1)
'x'
>>> data.getitem(2)
'c'
>>> data.sort()
>>>
>>> data.getitem(0)
'a'
>>> data.getitem(1)
'c'
>>> data.getitem(2)
'x'
>>> vars(data)
{'values': ['a', 'c', 'x']}
>>> data2 = List(['A', 'B', 'C'])
>>>
>>> vars(data)
{'values': ['a', 'c', 'x']}
>>>
>>> vars(data2)
{'values': ['A', 'B', 'C']}
>>> data1 = ['a', 'b', 'c']
>>> data2 = ['A', 'B', 'C']
>>>
>>> data1.__getitem__(0)
'a'
>>> data1.__getitem__(1)
'b'
>>> data1.__getitem__(2)
'c'
>>>
>>> data1.__setitem__(1, 'x')
>>>
>>> data1.__getitem__(0)
'a'
>>> data1.__getitem__(1)
'x'
>>> data1.__getitem__(2)
'c'
>>>
>>> data1
['a', 'x', 'c']
>>>
>>> data2
['A', 'B', 'C']
>>>
>>>
>>> data1.sort()
>>>
>>> data1.__getitem__(0)
'a'
>>> data1.__getitem__(1)
'c'
>>> data1.__getitem__(2)
'x'
>>> data1 = ['a', 'b', 'c']
>>> data2 = ['A', 'B', 'C']
>>>
>>> data1[0]
'a'
>>> data1[1]
'b'
>>> data1[2]
'c'
>>>
>>> data1[1] = 'x'
>>>
>>> data1[0]
'a'
>>> data1[1]
'x'
>>> data1[2]
'c'
>>>
>>> data1
['a', 'x', 'c']
>>>
>>> data2
['A', 'B', 'C']
>>>
>>>
>>> data1.sort()
>>>
>>> data1[0]
'a'
>>> data1[1]
'c'
>>> data1[2]
'x'

16.10.15. Use Case - 0x09

>>> class List:
...     def __init__(self, values):
...         self.values = values
...
...     def sort(self):
...         self.values.sort()
...
...     def __setitem__(self, index, newvalue):
...         self.values[index] = newvalue
...
...     def __getitem__(self, index):
...         return self.values[index]
...
>>>
>>> data = List(['a', 'b', 'c'])
>>> data[0]
'a'
>>> data[1]
'b'
>>> data[2]
'c'
>>> data[1] = 'x'
>>>
>>> data[0]
'a'
>>> data[1]
'x'
>>> data[2]
'c'

16.10.16. Use Case - 0x0A

>>> class Car:
...     name: str
...     engine: str
...     windows: str
...     speed: int
...
...     def accelerate(self, value):
...         self.speed += value
...
...     def slowdown(self, value):
...         self.speed -= value