Obvezni nalogi

Namen obveznih nalog je, da študent z drobno spremembo v lastnem programu pokaže, da pozna svoj izdelek.

Neobčutljivi slovar

Kaj, konkretno, je bilo potrebno spremeniti, je odvisno od posamezne izvedbe rešitve, v osnovi pa bi moralo za reševanje zadoščati, da naredimo preprost search&replace, kjer .lower() zamenjamo z [:4].

Velikost slik

Naloga preverja, ali ste pri reševanju domače naloge razumeli nize za oblikovanje izpisa. Potrebno je bilo le zamenjati vrstni red in poravnati ime na desno: print("{:50} {:>8} x {:<8}".format(fn, w, h)) spremenimo v print("{:>8} x {:<8}{:>50} ".format(w, h, fn)).

Vse po dvakrat

Problem je čista stokrat ponovljena klasika: preštevanje v slovar. Sledi druga klasika, ki smo jo spoznavali, recimo, ob praštevilih: zanka, ki nekaj preverja in vrne False, čim nekaj ni v redu, True pa šele na koncu, ko vidimo, da je vse v redu.

def vse_po_dvakrat(s): poj = {} for c in s: if c == " ": continue if c in poj: poj[c] += 1 else: poj[c] = 1 for p in poj.values(): if p != 2: return False return True

Za oba dela fukcije obstajata v Pythonu okrajšavi. Štejemo lahko z razredom collections.Counter, preverjamo pa z all. Tako dobimo veliko preprostejšo rešitev:

import collections def vse_po_dvakrat(s): pojavitve = collections.Counter(s.replace(" ", "")) return all(x==2 for x in pojavitve.values())

Kamelja imena

Kamelja imena so le vaja iz zankanja in indeksiranja, pa še par funkcij v zvezi z nizi je potrebno poznati.

def brez_grb(s): if s[0].isupper(): return s r = "" for i, c in enumerate(s): if c.isupper() and not s[i-1].isupper(): if i+1 < len(s) and s[i+1].isupper(): r += "_"+c else: r += "_"+c.lower() else: r += c return r

Seštevke

Seštevke zahtevajo, da znamo napisati zanko v zanki. (Temu se lahko izognemo, če smo malo bolj pametni; če smo, pa bi gotovo znali napisati tudi zanko v zanki.) Obenem ob njej vidimo, ali je študenta zanimalo naučiti se Python. Tisti, ki jih spoznavanje novih jezikov ne zanima in so nalogo rešili po Cjevsko (Javansko, C#ovsko ... vse je eno in isto), so tu malo trpeli, saj so morali do števk priti s ponavljanjem deljenja z 10 in opazovanjem ostankov:

def sestevke(a, b): stevke = {} for i in range(a, b+1): v = i while v > 9: k = v v = 0 while k > 0: v += k % 10 k //= 10 if v in stevke: stevke[v].append(i) else: stevke[v] = [i] return stevke

Neizmerno preprosteje je, če vemo, da lahko število pretvorimo v niz in gremo prek števk. Če znamo poleg tega uporabljati še funkcijo za računanje vsote in generatorje, ter slovarje s privzetimi vrednostmi (vse to smo seveda počeli tudi pri predmetu) pristanemo pri takšni rešitvi.

def sestevke(a, b): stevke = collections.defaultdict(list) for i in range(a, b+1): v = i while v > 9: v = sum(int(c) for c in str(v)) stevke[v].append(i) return stevke

Prav pa pride tudi znanje matematike. Vsota števk je "slučajno" enaka ostanku po deljenju z 9, le takrat, kadar je ostanek 0, je vsota števk enaka 9. Tako se znebimo notranje zanke.

def sestevke(a, b): stevke = collections.defaultdict(list) for i in range(a, b+1): stevke[i % 9 or 9].append(i) return stevke

Liki

Naloga preverja osnove osnov objektnega programiranja. Napisati je bilo treba metodo (v kakem drugem jeziku bi rekli virtualno metodo) ploscina. Razrede je bilo potrebno dopolniti, da (poleg metode __init__, ki je podana) vsebujejo še metodo ploscina.

from math import pi, sqrt class Pravokotnik: def ploscina(self): return self.a * self.b class Krog: def ploscina(self): return pi * self.r**2 class Trikotnik: def ploscina(self): s = (self.a + self.b + self.c)/2 return sqrt(s*(s-self.a)*(s-self.b)*(s-self.c))

Črkovalnik

Zadnja naloga preveri še, kako dobro študent razume, katero podatkovno strukturo uporabiti za posamezen problem. Tule, konkretno, mora razumeti, da se mu besede najbolj splača zložiti v množico. (Res pa v tem preprostem primeru povsem enako dobro delujejo tudi seznami in celo slovarji.)

Izpit tipično vsebuje tudi nalogo, ki zahteva branje datoteke v kak slovar ali seznam (kot da je to kaj težkega) in ki jo je veliko preprosteje rešiti z regularnimi izrazi kot brez. Tule je takšna, "preprosta" rešitev.

import re def spell(fname, words_fname): good_words = set(map(str.strip, open(words_fname))) ws = re.findall(r'\w+', open(fname).read()) return [w for w in ws if w.lower() not in good_words]

V prvi vrstici preberemo datoteko s slovarjem, odluščimo znake za novo vrsto in besede zložimo v množico. V drugi preberemo datoteko z besedilom, in iz nje z regularnim izrazom (točno takšega smo videli tudi tu in tam na predavanjih oz. v nalogah) izločimo vse besede. V zadnji vrstici sestavimo in vrnemo seznam besed, ki jih ni v slovarju.

Seveda pa gre tudi na daljši način.

Zadnja sprememba: sreda, 3. oktober 2012, 19.01