Python Introduktion

Her er min idé til hvordan vi lærer Python i løbet af 5 uger.

  1. Hello, World
    Arrays
  2. Filer og strenge
  3. Hash-tabeller
  4. Objekter
  5. Egne moduler

De mest ihærdige studerende kan få sine ECTS-point rapportdokumenterede ved at lave ét af følgende projekter:

  1. Projekt 1: CGI
  2. Projekt 2: .NET
  3. Projekt 3: Client/Server

Hello, World

Mandag den 20. November efter Network Embedded Programming ser vi på Hello World, så bring jeres egen. [løsning]

De efterfølgende 'ugeopgaver' kunne vi vælge at løse til om torsdagen (igen efter Network Embedded Programming), startende fra og med den 23. November. Idéen er, at man laver opgaverne selv og diskuterer løsningerne samlet.

Uge 1: Primtal med Eratosthenes Si (brug af arrays)

Note: I grundlæggende python findes der ikke arrays. I stedet findes der lister, der her tilbyder lignende funktionalitet.

  1. Læs algoritmen, der er beskrevet på Wikipedia
  2. Implementér et script, der spytter alle primtal under n ud på STDOUT (med n som argument). [løsning]
  3. Implementér en algoritme, der bygger på samme principielle egenskab, men som starter med et tomt array og udvider dette. [løsning]
  4. Lav en alternativ udgave af det første script, der spytter resultaterne ud i omvendt rækkefølge ved at fjerne elementerne fra arrayet et af gangen. [løsning]

Uge 2: Data (brug af filer og strenge)

Tag udgangspunkt i filerne uge2.conf og data.txt. Formatet af den første skal tolkes som:

filnavn : Hvorfra data skal læses.
skip : Hvor mange linjer, der skal springes over (fra starten af filen).
cols : De interessante søjler (negative indices tælles bagfra).
navn : De linjer, hvor første ikke-tomme søjle svarer til dette navn er interessante.

Opgaven består i følgende:

  1. Lav et script, der for hver interessant linje, udprinter navnet samt summen af de interessante søjler. [løsning]

Uge 3: Navneliste (brug af hashes)

Tag udgangspunkt i en navneliste som denne.

Note: Python-folk kan godt lide at være centrum for alles opmærksomhed. Derfor bruger man i denne verden dictionaries og tror at hash er noget man ryger når mørket falder på. Som de veluddannede studerende vi er, bærer vi over med dem og accepterer deres særheder.

  1. Lav et script, der læser filen og printer alle unikke navne ud. [løsning]
  2. Lav et script, der undersøger om et bestemt navn (fra et argument) er i listen vha. hash-opslag. [løsning]
  3. Lav et script, baseret på det første, der fjerner et bestemt navn fra listen (hash'en), før den bliver skrevet ud. [løsning]

Uge 4: Dijkstra (brug af objekter)

Denne opgave er markant vanskeligere at implementere end de foregående. Klasser er ikke specielt godt beskrevet. Prøv alligevel selv at finde en løsning før I ser på min løsning, det kan jo være at I finder en bedre.

Note: Et godt udgangspunkt er den officielle dokumentation, selvom sproget er lidt grumset. Pointen er at klasser i Python, er defineret oven på eksisterende datastrukturer, ikke ulig hvordan Objekt Orienterede sprog blev beskrevet i kurset "Programmeringssprog". Denne arv skinner klart igennem når man arbejder med klasser i Python.

  1. Læs algoritmen, der er beskrevet på Wikipedia
  2. Lav klasser for knuder og kanter.
  3. Indlæs en graf fra en fil (begrund valg af format). [eksempel]
  4. Implementér en Dijkstra. [løsning]

Uge 5: (Overdreven) god kodeskik (brug af egne moduler)

Denne opgave er overraskende enkel hvis man finder den rette dokumentation. [hint]

  1. Hvordan fungerer 'import' (se evt. den officielle reference)?.
  2. Omstrukturer løsningen fra sidste opgave således at I får mindst ét modul og en enkelt hoved-fil. [modul] [script]

Projekt 1: CGI

Dette projekt er opdelt i to faser. I første fase implementeres et CGI-script, der genererer et tilfældigt tal mellem to brugerdefinerede grænser. Grænserne skal naturligvis checkes og UI'en skal kune benyttes uden brug af andre HTML-sider. I anden fase skal CGI'en oprette en server-side session og i denne tælle antallet af kørsler. Dette tal skal naturligvis præsenteres for brugeren. [udgangspunkt]

Løsning (fase 1):

Problemet kan løses relativt simpelt, som fx her. Scriptet kan afprøves.

Løsning (fase 2):

Dette problem er en anelse mere interessant. Min løsning bruger modulet 'pickles' til at serialisere objekter til en sessionsfil. Den er hverken sikker (sessionsnøglen hashes) eller stabil (sessions-filen låses ikke under skrivning). Session og user-agent associeres vha. en cookie. Scriptet kan afprøves.

Projekt 2: .NET

Implementér den oprindelige Eratosthenes Si (fra uge 1) i IronPython. Dette er en Python-implementation, der kører oven på '.NET'.

Løsning:

Den lette løsning er simpelthen at skifte fortolker; så virker løsningen fra uge 1. Men eftersom Microsoft's fortolker ikke lader til at være specielt shebang-venlig er vi nødt til at gøre tingene på den kedelige måde:

$ ipy primes1iron1.py 40
Primes below 40:
2
3
5
7
11
13
17
19
23
29
31
37

Her er løsningen blevet strippet for den overflødige shebang. Eftersom løsningen er ren Python kan man vist sagtens kalde den lidt kedelig. I stedet for at bruge Python's indbyggede print kan vi eksempelvis bruge .NET's System.Console.WriteLine. Denne implementation køres på samme måde.

Lidt benchmarking på en 2.0GHz iP4m:

$ time ./primes1.py 10000000 > /dev/null

real 0m47.708s
user 0m45.407s
sys 0m0.632s
$ time ipy primes1iron1.py 10000000 > /dev/null

real 1m0.066s
user 0m54.699s
sys 0m1.804s
$ time ipy primes1iron2.py 10000000 > /dev/null

real 0m56.964s
user 0m53.667s
sys 0m1.620s

Projekt 3: Client/Server

Lav et client/server system, således at klienten fungerer som en remote-promt på serveren. Hver gang man på klientsiden trykker på enter sendes den streng man har skrevet til serveren. Denne eksekverer strengen og returnerer STDOUT (og eventuelt STDERR) til klienten. Herefter kan klienten så give ny ordre.

Løsning:

Implementationen benytter sig af stream-baserede INET sockets. Der er en server og en klient. Eksempel på kørsel følger.

klient-siden:

$ ./remoteshell_client.py localhost 1111
# uptime
00:36:09 up 2:32, 2 users, load average: 0.50, 0.50, 0.34
# echo $PATH
/home/asjo/bin:/opt/ufraw/bin:/opt/matlab/linux/bin:/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games
#
-- interrupted --
$ ./remoteshell_client.py localhost 1111
# echo $HOME
/home/asjo
#
-- interrupted --
$

server-siden:

$ ./remoteshell_server.py 1111
Client connected from 127.0.0.1:4537
cmd[uptime]
cmd[echo $PATH]
Client connected from 127.0.0.1:4539
cmd[echo $HOME]
-- interrupted --
$