{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 8. előadás\n", "_Tartalom:_ osztályok, objektum orientált programozás\n", "\n", "\n", "A Python objektum orientált programozást a 2D-s pontok osztályának elkészítésén keresztül mutatjuk be _(Nagyban támaszkodni fogunk Siki Zoltán könyvére)_. A Python nyelvben minden osztály (például a lista vagy a szótár is, de a függvények is). \n", "Kezdjük is el az osztály kódjának elkészítését.\n", "\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Siki Zoltán\n", "class Point2D(object): # object a bázis osztály\n", " \"\"\" kettő dimenziós pontok osztálya\n", " \"\"\"\n", " def __init__(self, east = 0, north = 0): # __init__ a konstruktor\n", " \"\"\" Initialize point\n", " :param east: első koordináta\n", " :param north: második koordináta\n", " \"\"\"\n", " #self.east = east # tagváltozó létrehozása\n", " self.setEast(east)\n", " #self.north = north\n", " self.setNorth(north)\n", " def abs(self):\n", " \"\"\" calculate length of vector (absolute value)\n", " :returns: absolute value\n", " \"\"\"\n", " return (self._east**2 + self._north**2)**0.5\n", " def __str__(self):\n", " \"\"\" String representation of the 2D point\n", " :returns: point coordinates as string (e.g. 5; 3)\n", " \"\"\"\n", " return \"*%.3f; %.3f*\" % (self._east, self._north)\n", " def __add__(self, p):\n", " \"\"\" Add two point\n", " :param p: point to add\n", " :returns: the sum of the two point (vector)\n", " \"\"\"\n", " return Point2D(self._east + p.getEast(), self._north + p.getNorth())\n", " def setEast(self, east):\n", " self._east = east\n", " def getEast(self):\n", " return self._east\n", " def setNorth(self, north):\n", " if north < 400000:\n", " self._north = north\n", " else:\n", " raise ValueError('north must be less than 400000') \n", " def getNorth(self):\n", " return self._north " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A `self` változó az osztály minden (nem statikus vagy osztály) metódusának az első paramétere és az objektum példányt jelenti, ezen keresztül hivatkozhatunk az objektum elemeire pl. `self.east`. A többsoros megjegyzés a sphinx programnak megfelelően készült, hogy automatikusan lehessen dokumentációt generálni a kódból.\n", "Próbáljuk ki a kódunkat." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [], "source": [ "p0 = Point2D() # példányosítás, 2, 0 pont\n", "p1 = Point2D(0) # példányosítás, 0, 0 pont\n", "p2 = Point2D(2, -2) # példányosítás, 2,–2 pont" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Írassuk ki az egyes pontok tagváltozóit, abszolút értékét." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 0, 0] abs: 0.00\n", "[ 0, 0] abs: 0.00\n", "[ 2,-2] abs: 2.83\n" ] } ], "source": [ "pontok = [p0, p1, p2]\n", "for pont in pontok:\n", " print(\"[%2d,%2d] abs: %.2f\" % (pont.getEast(), pont.getNorth(), pont.abs()))" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "p2 east tagváltozó értéke: 2\n", "p2 north tagváltozó értéke: -2\n", "p2 abs() függvény értéke: 2.8284271247461903\n", "p2.__dict__: {'_east': 2, '_north': -2}\n", "p2: *2.000; -2.000*\n" ] } ], "source": [ "print(\"p2 east tagváltozó értéke: \", p2.getEast())\n", "print(\"p2 north tagváltozó értéke: \", p2.getNorth())\n", "print(\"p2 abs() függvény értéke: \", p2.abs())\n", "print(\"p2.__dict__:\", p2.__dict__)\n", "print(\"p2:\", p2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Az egyes osztályokhoz speciális függvényeket definiálhatunk (mint pl. az `__init__`), ezek jellemzője, hogy két aláhúzás karakterrel kezdődik és végződik a nevük. \n", "\n", "Az `__init__` függvény az úgynevezett **konstruktor**, ez fut le a példányok létrehozásakor, itt biztosíthatjuk, hogy ne legyen inicializálatlan tagváltozónk. \n", "\n", "A **destruktor**t a `__del__` függvény implementálásával valósíthatjuk meg. A dinamikus tárfoglalás hiányában a Pythonban erre\n", "ritkábban van szükség.\n", "\n", "A print utasítás az osztály `__str__` metódusát hívja meg. A fenti példában ennek alapértelmezett változatának eredményét láthattuk az object osztályból. " ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "<__main__.Point2D at 0x28b29bc06d8>" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p2" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "*2.000; -2.000*\n" ] } ], "source": [ "print(p2)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "*10.000; 300000.000*\n" ] } ], "source": [ "p3 = Point2D(10, 300000) \n", "print(p3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A pont osztály egy példányának a koordinátáit közvetlenül nem változtathatjuk meg amennyiben:\n", "``` python\n", "self.east = east\n", "```\n", "helyett a \n", "``` python\n", "self.setEast(east)\n", "```\n", "módon hozzuk létre tagváltozóinkat. \n", "Ha a pont osztály egy példányának a koordinátáit közvetlenül megváltoztathatjuk, ez azzal a következménnyel járhat, hogy:\n", "1. a példány tagváltozóit az osztály felhasználója egy programhibából következően is átírhatja,\n", "2. a példány tagváltozóit ellenőrzés nélkül is felül lehet írni.\n", "\n", "Ennek kivédésére privát tagváltozókat (`_` karakterrel kezdődő név) és getter/setter metódusokat használhatunk. Írjuk át az osztályunkat, hogy egy-egy metóduson keresztül lehessen megváltoztatni a tagváltozókat. A Python osztályok privát tagváltozóinak neve aláhúzás karakterrel kezdődik. A két aláhúzással kezdődő és végződő nevek a Python nyelv elemei.\n", "\n", "A következő kódrészlet\n", "``` python\n", " def setNorth(self, north):\n", " if north < 400000:\n", " self._north = north\n", " else:\n", " raise ValueError('north must be less than 400000')\n", "```\n", "miatt a \n", "\n", "``` python\n", "p3.setNorth(400000) \n", "```\n", "illetve \n", "``` python\n", "p9 = Point2D(10, 400001) \n", "```\n", "\n", "esetén a következő hibába botlanánk:\n", "``` python\n", "ValueError Traceback (most recent call last)\n", "ValueError: north must be less than 400000\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A Python nyelvben az osztályokhoz további speciális függvényekkel műveleteket is definiálhatunk. A pontokat mint helyvektorokat is használhatjuk, készítsük el a helyvektorok összeadását.\n", "\n", "``` python\n", " def __add__(self, p):\n", " \"\"\" Add two point\n", " :param p: point to add\n", " :returns: the sum of the two point (vector)\n", " \"\"\"\n", " return Point2D(self.east + p.east, self._north + p._north)\n", "```\n", "\n", "Próbáljuk ki:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "*2.000; -2.000*\n", "*10.000; 300000.000*\n", "Összegük: *12.000; 299998.000*\n" ] } ], "source": [ "print(p2)\n", "print(p3)\n", "print(\"Összegük: \", p2 + p3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### _Used sources_ / Felhasznált források\n", "- [Shannon Turner: Python lessons repository](https://github.com/shannonturner/python-lessons) MIT license (c) Shannon Turner 2013-2014\n", "- [Siki Zoltán: Python mogyoróhéjban](http://www.agt.bme.hu/gis/python/python_oktato.pdf) GNU FDL license (c) Siki Zoltán" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.6.0" } }, "nbformat": 4, "nbformat_minor": 2 }