Válí se ti projekty v šuplíku? Dostaň je mezi lidi a získej cool tričko a body na profi IT kurzy v soutěži ITnetwork summer 2017!
Přidej si svou IT školu do profilu a najdi spolužáky zde na síti :)

12. díl - Magické metody Pythonu - Matematické

Python Objektově orientované programování Magické metody Pythonu - Matematické

Unicorn College ONEbit hosting Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, Magické metody v Pythonu, jsme se věnovali magickým metodám. V tomto Python tutoriálu budeme pokračovat s magickými metodami. Tentokrát si ukážeme speciální metody pro matematické operátory. Na třídě Vector si také ukážeme jejich použití.

Obyčejné operátory

Tyto operátory se volají standardně na objektu a, přičemž objekt a je parametr self a objekt b je parametr other

__add__(self, other)

Sčítání

c = a + b

__sub__(self, other)

Odečítání

c = a - b

__mul__(self, other)

Násobení

c = a * b

__truediv__(self, other)

Pravé dělení

c = a / b

__floordiv__(self, other)

Celočíselné dělení

c = a // b

__mod__(self, other)

Zbytek po dělení - modulo

c = a % b

__divmod__(self, other)

Vrací dvojici (a // b, a % b) pro celá čísla.

Funkce divmod(): https://docs.python.org/…nctions.html#…

c = divmod(a, b)

__pow__(self, other, modulo)

Mocnina. Metoda by měla být schopná brát i třetí, nepovinný argument (modulo). Funkce pow(): https://docs.python.org/…nctions.html#pow

c = a ** b

__lshift__(self, other)

Bitový posun vlevo

c = a << b

__rshift__(self, other)

Bitový posun vpravo

c = a >> b

__and__(self, other)

Logická funkce AND

c = a & b

__xor__(self, other)

Logická funkce XOR (non-ekvivalence)

c = a ^ b

__or__(self, other)

Logická funkce OR

c = a | b

Prohozené operátory

Prohozené (reversed) operátory se zavolají, pokud není poskytnuta jejich implementace na prvním objektu.

Např.

sth = 1 + my_object

Pokud int nepodporuje magickou metodu __add__(), což pravděpodobně ne, je zavolána metoda __radd__() na my_object.

Tyto operátory se volají standardně na objektu b, přičemž objekt b je parametr self a objekt a je parametr other

__radd__(self, other)

Sčítání

c = a + b

__rsub__(self, other)

Odečítání

c = a - b

__rmul__(self, other)

Násobení

c = a * b

__rtruediv__(self, other)

Pravé dělení

c = a / b

__rfloordiv__(self, other)

Celočíselné dělení

c = a // b

__rmod__(self, other)

Zbytek po dělení - modulo

c = a % b

__rdivmod__(self, other)

Vrací dvojici (a // b, a % b) pro celá čísla.

Funkce divmod(): https://docs.python.org/…nctions.html#…

c = divmod(a, b)

__rpow__(self, other, modulo)

Mocnina. Metoda by měla být schopná brát i třetí, nepovinný argument (modulo). Funkce pow(): https://docs.python.org/…nctions.html#pow

c = a ** b

__rlshift__(self, other)

Bitový posun vlevo

c = a << b

__rrshift__(self, other)

Bitový posun vpravo

c = a >> b

__rand__(self, other)

Logická funkce AND

c = a & b

__rxor__(self, other)

Logická funkce XOR (non-ekvivalence)

c = a ^ b

__ror__(self, other)

Logická funkce OR

c = a | b

Operátory in place

Tyto operátory umožňují zkrácenou notaci (na místě). Parametry jsou self a other, ale vrací modifikovaný self. Pokud některá metoda neexistuje, Python se ji pokusí emulovat s využitím definovaných metod.

Příklad:

my_object += 1

Python zavolá metodu __iadd__(). V případě neúspěchu zavolá metodu __add__() tímto způsobem:

# pseudokód
temp = my_object + 1 # zavolá __add__()
my_object = temp

__iadd__(self, other)

Sčítání

a += b

__isub__(self, other)

Odečítání

a -= b

__imul__(self, other)

Násobení

a *= b

__itruediv__(self, other)

Pravé dělení

a /= b

__ifloordiv__(self, other)

Celočíselné dělení

a //= b

__imod__(self, other)

Zbytek po dělení - modulo

a %= b

__ipow__(self, other, modulo)

Mocnina. Metoda by měla být schopná brát i třetí, nepovinný argument (modulo). Funkce pow(): https://docs.python.org/…nctions.html#pow

a **= b

__ilshift__(self, other)

Bitový posun vlevo

a <<= b

__irshift__(self, other)

Bitový posun vpravo

a >>= b

__iand__(self, other)

Logická funkce AND

a &= b

__ixor__(self, other)

Logická funkce XOR (non-ekvivalence)

a ^= b

__ior__(self, other)

Logická funkce OR

a |= b

Další magické metody

__neg__(self)

Unární mínus

-a

__pos__(self)

Unární plus

+a

__abs__(self)

Absolutní hodnota, implementuje chování pro funkci abs()

abs(a)

__invert__(self)

Unární inverze

~a

__complex__(self)

Implementace chování pro funkci complex()

complex(a)

__int__(self)

Implementace chování pro funkci int()

int(a)

__float__(self)

Implementace chování pro funkci float()

float(a)

__round__(self, n)

Implementace chování pro funkci round()

round(a)

__index__(self)

Python tuto metodu používá při konverzi numerických typů na int, například při ořezávání nebo pro použití vestavěných funkcí bin(), hex() a oct(). Tato metoda by měla vracet stejný výsledek jako magická metoda __int__(). A navíc by měla vracet celé číslo (int).

Ukázka některých metod

Nyní se podíváme na třídu Vector a ukážeme si implementaci několika metod.

class Vector:

    def __init__(self, x, y):
        self.x = float(x)
        self.y = float(y)

    def __str__(self):
        return "({0.x}, {0.y})".format(self)

    ...

Začátek je pravděpodobně jasný. V metodě __str__() získáváme ze self atributy x a y.

def __add__(self, other):
    if isinstance(other, Vector):
        return Vector(self.x+other.x, self.y+other.y)
    elif issubclass(type(other), Sequence):
        if len(other) == 2:
            return Vector(self.x+other[0], self.y+other[1])
    raise NotImplemented

Prvně porovnáme, zda je druhý objekt také vektor. Pokud ano, vrátíme součet x-ových a y-ových složek jako nový vektor.

Další větvení je již složitější. Za pomoci vestavěné funkce issubclass() kontrolujeme, jestli je třída druhého objektu podtřídou Sequence z modulu collections.abc. Díky tomu můžeme na objektu použít funkci len() a získat z objektu první a druhý prvek. A to bez obav, že by to daný objekt nepodporoval. Pokud obě větve selžou a nic nevrátí, vyvolá se výjimka NotImplemented.

def __mul__(self, other):
    if issubclass(type(other), Real):
        return Vector(self.x*other, self.y*other)
    raise NotImplemented

Zde kontrolujeme, jestli je other podtřídou třídy Real (reálné číslo) z modulu numbers. Proto můžeme vektor vynásobit intem nebo floatem a vyhnout se zbytečnému větvení a kontrolování typů objektu.

Uvedené třídy z modulů numbers a collections.abc jsou ve skutečnosti abstraktní bázové třídy, tedy třídy, u kterých se "zavazujeme" dodržet určité rozhraní objektů, pokud je zdědíme. O tom ale zase až v příští lekci, Magické metody v Pythonu kolekce a deskriptory.


 

Stáhnout

Staženo 19x (1.87 kB)
Aplikace je včetně zdrojových kódů v jazyce python

 

 

Článek pro vás napsal gcx11
Avatar
Jak se ti líbí článek?
2 hlasů
(^_^)
Aktivity (2)

 

 

Komentáře

Avatar
jan.ruzicka01
Redaktor
Avatar
jan.ruzicka01:13.8.2015 20:20
  1. Máš tam dvakrát "__neg__", přičemž ve druhém případě tam má být "__pos__".
  2. Máš tam dvakrát v kódu "~a", přičemž ve druhém případě tam má být "int(a)".

Jinak super článek (možná bys měl zmínit i "__div__", přeci jen je to staré dobré 'klasické' dělení).

Odpovědět  +2 13.8.2015 20:20
';' je má jediná noční můra...
Avatar
gcx11
Redaktor
Avatar
Odpovídá na jan.ruzicka01
gcx11:13.8.2015 21:28

Ahoj, díky za opravu :)

__div__() je pouze v Pythonu 2, co jsem koukal, v Python 3 se místo něj používá __truediv__()

 
Odpovědět 13.8.2015 21:28
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 2 zpráv z 2.