Procvičování: instance objektů

Příklad. Zkuste najít hodnoty x a y, pro které platí x == y, ale neplatí x is y. (Zkuste vymyslet co nejrůznější možnosti.)

Řešení. x = 2.718281828 y = 2.718281828 # nebo například x = {"a":0, "b":1} y = {"a":0, "b":1}
Dovedete najít nějakou hodnotu, pro kterou to platí naopak? Tedy x a y takové, že x is y, ale neplatí x == y? Zkuste zavzpomínat, s jak obludnými čísly a jakoby-čísly umí počítač zacházet.

Příklad. Následující funkce dostane jeden seznam a měla by z něj vyrobit seznam se stejnými hodnotami v opačném pořadí. Proč nefunguje?

def prehod(seznam): delka = len(seznam) pozpatku = seznam for i in range(delka): pozpatku[i] = seznam[delka - i - 1] return pozpatku Řešení (pomocí jednoho cyklu). # Příklad je pod tématem "instance objektů", tak nepřekvapí, že problém je v používání jednoho seznamu dvakrát tam, kde potřebujeme dva seznamy. # Protože proměnné 'pozpatku' a 'seznam' jsou úplně totéž, v druhé půlce budeme číst hodnoty, které jsme už napsali na začátek. # Problém se dá vyřešit tak, že původní seznam zkopírujeme: def prehod(seznam): delka = len(seznam) pozpatku = list(seznam) for i in range(delka): pozpatku[i] = seznam[delka - i - 1] return pozpatku # Anebo ještě lépe a přehledněji, že začneme od prázdného seznamu a budeme do něj přidávat: def prehod(seznam): delka = len(seznam) pozpatku = list() for i in range(delka): pozpatku.append(seznam[delka - i - 1]) return pozpatku
Jak funkci přepsat tak, aby nenavracela nic, ale změnila přímo seznam, který dostane? To znamená, když ji zavoláte někde v kódu na libovolný seznam, aby v něm doopravdy změnila pořadí položek?

Odbočka, která se bude hodit: prvočíselný rozklad

Příklad. Napište funkci, která rozloží zadané číslo na součin prvočísel a ta navrátí jako seznam. Rozmyslete si, jak se taková funkce napíše pomocí rekurze (volání sebe samotné), jak s využitím dvou cyklů (jeden ve druhém) a jak ji zapsat jediným cyklem. První dvě možnosti budou v písemce.

Řešení (pomocí jednoho cyklu). def rozklad(n): vysledek = list() i = 2 while i <= n: if n % i == 0: # to, co nám zůstalo po dělení, je dělitelné hodnotou 'i' vysledek.append(i) n = n // i else: # dělitelné není, tak zkusíme vyšší 'i' i += 1 return vysledek
Pro ověření, jak kódu řešení rozumíte: v jakém pořadí budou čísla ve výsledném seznamu? Když vynecháte některý řádek, kdy program navrátí nesmysl, kdy se zasekne a kdy nebude ani syntakticky správně napsaný?

Cvičení do hodiny: jak rozdělit čtrnáctilitrový demižon vína napůl pomocí kanystru na benzín a sudu od piva?

def prelij(objemy, stav, odkud, kam):
	mnozstvi = min(stav[odkud], objemy[kam] - stav[kam])
	vysledek = list(stav)
	vysledek[odkud] -= mnozstvi
	vysledek[kam] += mnozstvi
	return tuple(vysledek)

def reseni(objemy, stav, cil, kroky, nejde_rychleji):
	if stav == cil:
		return [stav]
	elif kroky == 0:
		return False
	for odkud in range(len(stav)):
		for kam in range(len(stav)):
			vysledek = prelij(objemy, stav, odkud, kam)
			if vysledek not in nejde_rychleji or nejde_rychleji[vysledek] <= kroky - 1:
				pokus = reseni(objemy, vysledek, cil, kroky - 1, nejde_rychleji)
				if pokus:
					pokus.append(stav)
					return pokus
				else:
					nejde_rychleji[vysledek] = kroky
	return False

reseni((14, 9, 5), (14, 0, 0), (7, 7, 0), 13, dict())[::-1]