View Single Post
Sitat av Pope Vis innlegg
Og hvorfor kan jeg ikke definere variabler for URLs før dictionary defineres? Altså, dict henter ikke inn forhåndsdefinerte variabler.
Vis hele sitatet...
Jeg skjønner ikke helt hvorfor du skulle ønske det. Det virker som det du vil ikke er helt ulikt å definere en variabel først, også bruke det samme navnet til å definere en til med det samme innholdet. En dict består av elementer, hvor hvert element har en nøkkel og et innhold. Du kan like greit definere nøkkelen direkte heller enn å definere en variabel og så ønske å duplisere navn og innhold i dicten.

Det sagt, så ser jeg ikke helt nytten av en dict i dette tilfellet uansett.

Jeg er også enig i at evige løkker – selv om de kan være både nyttige og riktige – som regel bør unngås. Du får en bedre flyt i koden om du allerede ved definisjonen av løkka ser betingelsen for at løkka skal fortsette eller avbrytes.

Når det gjelder bruk av funksjoner, så er det en fordel å bruke når det er mulig å gjenbruke kode – så du slipper å skrive nærmest identisk kode flere ganger i samme program – og for å korte ned veldig lange funksjoner. Men også, vil jeg hardnakket påstå, er det en fordel å bryte ut semantisk separate blokker til funksjoner av flere grunner. I stedet for å ha tre-fire linjer med kode som må forklares med en kommentar på en egen linje, kan du like gjerne bryte den ut til en egen funksjon som er navngitt slik at det er selvsagt nok hva den gjør til at kommentaren blir overflødig. Det gjør at når du leser den opprinnelige kodeblokken trenger du ikke å forholde deg til hvordan det gjøres, bare at det gjøres. Det innfører en "mikro-abstraksjon" som gjør koden enklere å fordøye. Det gjør den mer lesbar, og økt lesbarhet minsker sannsynligheten for å innføre bugs og øker sannsynligheten for å identifisere bugs når noe ikke virker.

Så for å overføre noe av dette til konkrete ting i koden din. (Noe av dette er påpekt og foreslått av andre også.)

Vi kan begynne på toppen. Der har du definert en rekke URLer som hver sin variabel, hvor variablene er nummerert i navnet. Det antyder normalt at en liste eller et array er bedre egnet. Det er også verdt å legge merke til allerede her at dine to modi – Lite og Full – er overlappende i hvilke URLer de skal åpne. Full == Lite + noen_flere. Det kan du utnytte deg av på en måte som gjør det mer oversiktlig og enklere å legge til flere lenker senere. Her ville jeg brukt to lister, en for Lite og en for de som skal legges til i Full:

Kode

urls_basic = ["http://www.freak.no",
              "http://www.vg.no"]

urls_extra = ["http://www.facebook.com",
              "http://www.db.no",
              "http://www.yr.no"]
Det neste du gjør, er å be brukeren om input. Nå kan man diskutere hvor mye hensikt det har å trekke ut dette som egen funksjon, men det gir full mening å gjøre det selv om koden ikke skal gjenbrukes, fordi det å be brukeren om å velge modus for programmet er en semantisk frittstående oppgave som gir mening i seg selv. Og siden du ikke fikk det til, kan vi jo gjøre det her. (Jeg var frekk nok til å bytte version til mode, siden jeg synes det klaffet bedre med hensikten.)

Kode

def prompt_mode():
    user_input = ''
    while user_input not in ['f', 'l', 'x']:
        user_input = input("Velg versjon (f)ull / (l)ite: \nLukk programmet ved å skrive e(x)it ").lower()
    if user_input == 'x':
        print("Programmet lukkes")
        sys.exit()
    return user_input
Det første vi gjør der, er å definere variabelen user_input til en tom streng. Det er fordi vi trenger at den finnes til den skal brukes i while-løkkens betingelse. Deretter setter vi opp løkken: while user_input not in ['f', 'l', 'x'] betyr at så lenge innholdet i user_input ikke er å finne i den lille listen over muligheter vi satte opp, så skal løkka gjenta seg. Så ber vi brukeren om input og gjør det i samme slengen om til lower case for enklere sammenlikning.

Før vi returnerer det brukeren skrev inn, sjekker vi om det var 'x'. Var det 'x' avslutter vi programmet der og da med sys.exit() – men dette krever at vi importerer sys lenger opp. Vi trenger ikke å pakke return user_input inn i en else, fordi det vil aldri kjøre dersom det var 'x', siden programmet da vil avslutte i linjen over.

For å få brukerens input i den generelle kodeblokka, kan vi for eksempel lagre det i en variabel: mode = prompt_mode().

Deretter må vi åpne URLene, og hvilke avhenger av hvilken modus brukeren valgte. Det kan gjøres på flere måter. Det som kanskje er mest rett frem er å sette sammen en ny liste basert på input, slik:

Kode

if mode == 'l':
    urls = urls_basic
elif mode == 'f':
    urls = urls_basic + urls_extra
Og deretter loope gjennom alle elementene i listen og åpne dem. Men det er andre måter å skrive dette på også, for eksempel:

Kode

urls = urls_basic
if mode == 'f':
    urls += urls_extra
# eller ...
urls = urls_basic if mode == 'l' else urls_basic + urls_extra
Videre må man gå gjennom alle elementene for å åpne dem, gjerne da slik:

Kode

for url in urls:
    webbrowser.get(chrome_path).open(url)
Man kan også bli fancy og trekke sammen kode, for eksempel ved å bytte "urls" i for-løkke-uttrykket med uttrykket for urls over, slik:

Kode

for url in urls_basic if mode == 'l' else urls_basic + urls_extra:
Og eventuelt bytte "mode" med funksjonskallet for mode, så det blir slik:

Kode

for url in urls_basic if prompt_mode() == 'l' else urls_basic + urls_extra:
Men det krever litt erfaring i Python før man kan kalle det like lesbart som alternativene. Så i oppsummeringen har jeg valgt den "enklere" metoden:

Kode

import webbrowser
import sys

chrome_path = "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe %s"

urls_basic = ["http://www.freak.no",
              "http://www.vg.no"]

urls_extra = ["http://www.facebook.com",
              "http://www.db.no",
              "http://www.yr.no"]

def prompt_mode():
    user_input = ''
    while user_input not in ['f', 'l', 'x']:
        user_input = input("Velg versjon (f)ull / (l)ite: \nLukk programmet ved å skrive e(x)it ").lower()
    if user_input == 'x':
        print("Programmet lukkes")
        sys.exit()
    return user_input


mode = prompt_mode()

if mode == 'l':
    urls = urls_basic
elif mode == 'f':
    urls = urls_basic + urls_extra

for url in urls:
    webbrowser.get(chrome_path).open(url)