{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## [Objektumorientált programozás](https://docs.python.org/3/tutorial/classes.html), nulladik közelítésben\n", "\n", "Az objektumorientált programozás(OOP) olyan programozási módszertan, ahol az egymással kapcsolatban álló programegységek hierarchiájának megtervezése áll a középpontban.\n", "- A korábban uralkodó procedurális megközelítés a műveletek megalkotására fókuszált.\n", "- OOP esetén adatokat és az őket kezelő függvényeket egységbezárjuk (encapsulation).\n", "- Az OOP másik fontos sajátossága az öröklődés (inheritance)." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "10 20\n" ] } ], "source": [ "# Példa: téglalap osztály.\n", "\n", "class Rectangle:\n", " def __init__(self, a, b): # konstruktor\n", " self.a = a\n", " self.b = b\n", " \n", " def calc_area(self): # területszámító metódus definiálása\n", " return self.a * self.b\n", "\n", " def calc_perimeter(self): # kerületszámító metódus definiálása\n", " return (self.a + self.b) * 2\n", " \n", "r1 = Rectangle(10, 20) # téglalap objektum létrehozása\n", "print(r1.a, r1.b)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "200" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "r1.calc_area() # metódus meghívása" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "200" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# A Python a metódushívást a színfalak mögött függvényhívássá alakítja át.\n", "Rectangle.calc_area(r1)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# ...ez a beépített típusokra is igaz.\n", "(1).__add__(1)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "int.__add__(1, 1)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "314.1592653589793\n", "125.66370614359172\n" ] } ], "source": [ "# Példa: kör osztály.\n", "\n", "import math\n", "\n", "class Circle:\n", " def __init__(self, r): # konstruktor\n", " self.r = r\n", " \n", " def calc_area(self): # területszámító metódus definiálása\n", " return self.r**2 * math.pi\n", "\n", " def calc_perimeter(self): # kerületszámító metódus definiálása\n", " return 2 * self.r * math.pi\n", " \n", "c1 = Circle(10)\n", "c2 = Circle(20)\n", "print(c1.calc_area())\n", "print(c2.calc_perimeter())" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "# A kerület-terület arány kiszámítása téglalapok és körök esetén ugyanúgy történik.\n", "# Hozzunk létre egy egy síkidom ősosztályt, származtassuk ebből a téglalapot és a kört!\n", "# A kerület-terület arány számítást az ősosztályba tegyük!\n", "\n", "class Shape:\n", " def calc_pa_ratio(self):\n", " return self.calc_perimeter() / self.calc_area()\n", "\n", "class Rectangle(Shape): # a téglalap a síkidomból származik\n", " def __init__(self, a, b): # konstruktor\n", " self.a = a\n", " self.b = b\n", " \n", " def calc_area(self): # területszámító metódus definiálása\n", " return self.a * self.b\n", "\n", " def calc_perimeter(self): # kerületszámító metódus definiálása\n", " return (self.a + self.b) * 2\n", "\n", "class Circle(Shape): # a kör a síkidomból származik\n", " def __init__(self, r): # konstruktor\n", " self.r = r\n", " \n", " def calc_area(self): # területszámító metódus definiálása\n", " return self.r**2 * math.pi\n", "\n", " def calc_perimeter(self): # kerületszámító metódus definiálása\n", " return 2 * self.r * math.pi" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.6\n", "1.6666666666666667\n", "0.19999999999999998\n" ] } ], "source": [ "shapes = [Rectangle(10, 5), Rectangle(2, 3), Circle(10)]\n", "for s in shapes:\n", " print(s.calc_pa_ratio())" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "def solve_quadratic(a, b, c):\n", " '''Solve quadratic equation a*x^2 + b*x + c = 0,\n", " and return solutions in a list.'''\n", " \n", " # diszkrimináns kiszámítása\n", " d = b**2 - 4 * a * c\n", "\n", " # elágazás\n", " if d > 0: # 2 megoldás\n", " x1 = (-b + d**0.5) / (2 * a)\n", " x2 = (-b - d**0.5) / (2 * a)\n", " return [x1, x2]\n", " elif d == 0: # 1 megoldás\n", " return [-b / (2 * a)]\n", " else:\n", " return []" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "# Feladat: Készítsünk másodfokú egyenlet megoldó osztályt!\n", "class QuadraticEquation:\n", " def __init__(self, a, b, c):\n", " self.a = a\n", " self.b = b\n", " self.c = c\n", "\n", " def _calc_d(self):\n", " return self.b**2 - 4 * self.a * self.c\n", " \n", " def nsolutions(self):\n", " d = self._calc_d()\n", " if d > 0: return 2\n", " elif d == 0: return 1\n", " else: return 0\n", " \n", " def solve(self):\n", " '''Solve quadratic equation a*x^2 + b*x + c = 0,\n", " and return solutions in a list.'''\n", " \n", " a, b, c = self.a, self.b, self.c\n", "\n", " # diszkrimináns kiszámítása\n", " d = self._calc_d()\n", "\n", " # elágazás\n", " if d > 0: # 2 megoldás\n", " x1 = (-b + d**0.5) / (2 * a)\n", " x2 = (-b - d**0.5) / (2 * a)\n", " return [x1, x2]\n", " elif d == 0: # 1 megoldás\n", " return [-b / (2 * a)]\n", " else:\n", " return []" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[-1.0, -2.0]" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "QuadraticEquation(1, 3, 2).solve()" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[-1.0]" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "QuadraticEquation(1, 2, 1).solve()" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "QuadraticEquation(1, 1, 3).solve()" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2\n", "[-1.0, -2.0]\n" ] } ], "source": [ "eq = QuadraticEquation(1, 3, 2)\n", "print(eq.nsolutions())\n", "print(eq.solve())" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "# Feladat: \"Éhes kutyák\".\n", "\n", "class Dog:\n", " def __init__(self, name, is_hungry=False):\n", " self.name = name\n", " self.is_hungry = is_hungry\n", "\n", " def eat(self):\n", " self.is_hungry = False\n", " \n", "dogs = [\n", " Dog('Borzas', True),\n", " Dog('Vadász', False),\n", " Dog('Nokedli'),\n", " Dog('Cézár', True),\n", " Dog('Csibész', True)\n", "]" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Borzas\n", "Cézár\n", "Csibész\n" ] } ], "source": [ "# Nézzük meg, hogy kik éhesek!\n", "for d in dogs:\n", " if d.is_hungry:\n", " print(d.name)" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "# Etessük meg az összes éhes kutyát!\n", "for d in dogs:\n", " if d.is_hungry:\n", " d.eat()" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Borzas False\n", "Vadász False\n", "Nokedli False\n", "Cézár False\n", "Csibész False\n" ] } ], "source": [ "# Nézzük meg, hogy mi az etetés eredmény!\n", "for d in dogs:\n", " print(d.name, d.is_hungry)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "# Éhezzenek meg a kutyák!\n", "for d in dogs:\n", " d.is_hungry = True" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Borzas\n", "Vadász\n", "Nokedli\n", "Cézár\n", "Csibész\n" ] } ], "source": [ "# Újra nézzük meg, hogy kik éhesek!\n", "for d in dogs:\n", " if d.is_hungry:\n", " print(d.name)" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Borzas\n", "Cézár\n", "Csibész\n" ] } ], "source": [ "# Oldjuk meg az \"éhes kutyák\" feladatot osztályok használata nélkül!\n", "dogs = [\n", " {'name': 'Borzas', 'is_hungry': True},\n", " {'name': 'Vadász', 'is_hungry': False},\n", " {'name': 'Nokedli', 'is_hungry': False},\n", " {'name': 'Cézár', 'is_hungry': True},\n", " {'name': 'Csibész', 'is_hungry': True}\n", "]\n", "\n", "for d in dogs:\n", " if d['is_hungry']:\n", " print(d['name'])\n", " \n", "# ..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Speciális (\"dunder\") [attribútumok](https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy) és [metódusok](https://docs.python.org/3/reference/datamodel.html#special-method-names)\n", "\n", "- `__doc__`, `__class__`, `__init__()`, `__hash__()`, `__code__`, ...\n", "- attribútumtárolásra: `__dict__`, `__dir__()`\n", "- kiírásra: `__repr__()`, `__str__()`\n", "- műveletvégzésre: `__add__()`, `__mul__()`, ...\n", "- indexelésre: `__getitem__()`, `__setitem__()`, `__len__()`\n", "- iterálásra: `__iter__()`, `__next__()`\n", "- kontextuskezelésre: `__enter__()`, `__exit__()`\n", "- ..." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "# Példa: __repr__ metódussal rendelkező osztály.\n", "class Student:\n", " def __init__(self, name, neptun):\n", " self.name = name\n", " self.neptun = neptun\n", " \n", " def __repr__(self):\n", " return f\"Student('{self.name}', '{self.neptun}')\"" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Student('Gipsz Jakab', 'ABC123')" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Student('Gipsz Jakab', 'ABC123')" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[10, 20, 30]\n" ] } ], "source": [ "# A __repr__ metódus a beépített osztályokra is meg van valósítva.\n", "l = [10, 20, 30]\n", "print(l.__repr__())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Gyakorlás\n", "\n", "Készítsünk vektor osztályt, amely támogatja a vektorok közötti elemenkénti alapműveleteket (+, -, *, /), a vektor elemszámának lekérdezését, a haladó indexelést valamint a vektor sztringgé alakítását! Elvárt működés:\n", "```\n", "v1 = Vector([1.0, 2.0, 3.0])\n", "v2 = Vector([4.0, 5.0, 6.0])\n", "print(len(v1), v1[0], v1[:2]) # => 3 1.0 [1.0, 2.0]\n", "print(v1 + v2) # => Vector([5.0, 7.0, 9.0])\n", "print(v1 * v2) # => Vector([4.0, 10.0, 18.0]\n", "```" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [], "source": [ "class Vector:\n", " def __init__(self, data):\n", " self.data = data\n", " \n", " def __repr__(self):\n", " return f'Vector({str(self.data)})'\n", " \n", " def __add__(self, other):\n", " return Vector([x + y for x, y in zip(self.data, other.data)])\n", "\n", " def __sub__(self, other):\n", " return Vector([x - y for x, y in zip(self.data, other.data)])\n", "\n", " def __mul__(self, other):\n", " return Vector([x * y for x, y in zip(self.data, other.data)])\n", "\n", " def __truediv__(self, other):\n", " return Vector([x / y for x, y in zip(self.data, other.data)])\n", " \n", " def __len__(self):\n", " return len(self.data)\n", " \n", " def __getitem__(self, idx):\n", " return self.data[idx]" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "# 2 vektor létrehozása\n", "v1 = Vector([1.0, 2.0, 3.0])\n", "v2 = Vector([4.0, 5.0, 6.0])" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Vector([1.0, 2.0, 3.0])" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v1" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Vector([5.0, 7.0, 9.0])" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# műveletek\n", "v1 + v2" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Vector([-3.0, -3.0, -3.0])" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v1 - v2" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Vector([4.0, 10.0, 18.0])" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v1 * v2" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Vector([0.25, 0.4, 0.5])" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v1 / v2" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# elemszám lekérdezés\n", "len(v1)" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# indexelés\n", "v1[0]" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1.0, 2.0]" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# haladó indexelés\n", "v1[:2]" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Vector([5.0, 7.0, 9.0])" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# A műveletek a háttérben egyszerű függvényhívássá alakulnak át.\n", "v1 + v2" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Vector([5.0, 7.0, 9.0])" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Vector.__add__(v1, v2)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.3" } }, "nbformat": 4, "nbformat_minor": 2 }