' freak.no - Pope sliter med Python
freak.no

freak.no (https://freak.no/forum/index.php)
-   Programmering (https://freak.no/forum/forumdisplay.php?f=49)
-   -   Pope sliter med Python (https://freak.no/forum/showthread.php?t=298988)

Pope 24. august 2017 13:01

Pope sliter med Python
 
Heisan!

I forbindelse med noen nye fag på skolen må jeg lære meg å bruke Python som språk og regneverktøy. Det jeg skal kunne er veldig elementært, men jeg har aldri interessert meg for programmering og er helt blank.

Jeg har kommet et stykke på vei ved å bruke guider på codeacademy, men rett som det er står jeg fast med det ting som skulle vært kjempelett.

Det blir nok en del frustrasjon fremover og jeg lager denne tråden for å samle opp alle mine spørsmål som vitner om udugelighet:rolleyes:
Jeg vil tro at alle som har vært borti dette kan svare på spørsmålene mine.

Nå sitter jeg fast med if, else og elif statements som ikke virker som jeg ønsker. Kan noen påpeke feilen min?

Kode:

age = raw_input("Hvor gammel er du?")

if age >= 18:
    print "Du er myndig"
else:
    print "Du er ikke myndig"

I følge koden min er alle myndige uavhengig av input:confused:

dggr 24. august 2017 13:11

Hva slags datatype er age når du sammenligner i if'n ?

randommm 24. august 2017 13:11

Jeg tror feilen kommer fra den første linjen. Det du skriver som raw_input(på command line) vil bli lagret som en string, ikke et integer. En string er, så vidt jeg vet, alltid større enn en int:

eksempel:

>>> str(2) > 2 True

For å fikse dette kan du for eksempel skrive første linje slik:

age = int(raw_input("Hvor gammel er du?"))

På den måten tvinger du python til å lagre "age" som en integer, og da vil det funke ;)

thedonkeybong 24. august 2017 14:23

Kan jeg spørre hvorfor du lærer Python 2 fremfor 3?

Pope 24. august 2017 16:47

Sitat:

Sitat av thedonkeybong (Innlegg 3396046)
Kan jeg spørre hvorfor du lærer Python 2 fremfor 3?

Det kan du absolutt gjøre. Jeg har en foreleser som har laget skript i python 2 som ikke tar seg tid til å gjøre skriptene kompatible med python 3. Derfor.

Er det stor forskjell på 2 og 3? Hva er i såfall annerledes?

Nytt problem:

Jeg holder på med funksjoner og jeg tror jeg klarer å kalle på funksjonen.
Men hvordan printer jeg ut total sum til slutt?

Jeg antar at jeg har problemer fordi jeg forsøker å kalle på en variabel som kun finnes i den lukkede funksjonen.

Kode:

def hotel_cost(netter):
  total = 140 * netter
          return total
 
hotel_cost(raw_input("Hvor mange netter? "))

print total

edit:
Fant løsningen selv.
Kode:

def hotel_cost(netter):
  total = 140 * netter
  return total
 
total = hotel_cost(int(raw_input("Hvor mange netter? ")))

print total

Er dette en "ryddig måte å gjøre det på?

vidarlo 24. august 2017 17:32

Sitat:

Sitat av Pope (Innlegg 3396052)
edit:
Fant løsningen selv.
Kode:

def hotel_cost(netter):
  total = 140 * netter
  return total
 
total = hotel_cost(int(raw_input("Hvor mange netter? ")))

print total

Er dette en "ryddig måte å gjøre det på?

Det er den ryddige måten å gjere det på. Variabler deklarert i ein funksjon er lokale, og finst ikkje utanfor den funksjonen. Det står garantert i boka.

Return er retur-verdien til ein funksjon - og her tilordner du den til ein verdi. Du kunne like gjerne køyrt print hotel_cost(blablabla), eller tilordna den til variabelen foo.

Xasma 24. august 2017 17:36

Sitat:

Sitat av Pope (Innlegg 3396052)
Kode:

def hotel_cost(netter):
  total = 140 * netter
  return total
 
total = hotel_cost(int(raw_input("Hvor mange netter? ")))

print total

Er dette en "ryddig måte å gjøre det på?

Nei, du burde separere input så det kommer klart frem i egen variabel og fjerne litt unødvendige ting, her har du et fort og gæli forslag:
Kode:

def hotel_cost(netter):
  return 140 * netter

netter = int(raw_input("hvor mange netter?")) 

print hotel_cost(netter)

PS: ja, jeg er fult klar over at dette ikke er absolutt beste måten å løse det på, men gitt at noe særlig mer konvensjonsmas kan bli rotete og uforståelig når man lærer å kode, skriver jeg det sånn.

Pope 24. august 2017 17:47

Takk vidarlo og Xasma :)

Tingen er at jeg har et fag som egentlig krever at jeg har hatt et programmeringsfag tidligere, hvilket jeg ikke har. Litt rotete opplegg fra skolens side, men resultatet er uansett at jeg må lære meg dette på egenhånd for å kunne henge med i det nye faget mitt.
Dette er årsaken til at jeg ikke har noen bestemt bok å slå opp i, vidarlo ;)

En annen ting jeg synes er litt funky er å kalle på funksjoner med flere variabler:

Jeg har tre ulike funksjoner, hver av dem avhengig av hver sin variabel.
Deretter lager jeg en ny funksjon som skal kalle på de tre andre funksjonene og summere totalprisen.

Kode:

def trip_cost(city, days):
  return hotel_cost(days) + plane_ride_cost(city) + rental_car_cost(days)

Guiden sier at det er helt greit å bruke days to ganger, selv om de lukkede funksjonene er avhengig av variabler kalt days, nights og city.

Det kan jeg godta, men hvordan vet funksjonen som egentlig er avhengig av nights at den skal bruke days- og ikke city-verdien?

snippsat 24. august 2017 17:56

Sitat:

Er det stor forskjell på 2 og 3? Hva er i såfall annerledes?
Det har skjedd en god del,som ny bruker er det helt klart en fordel og begynne med Python 3.6.

Er jo greit og skrive om,kan også bruke 2to3 som kommer med Python under Tools/Scripts.
Ser sånn ut,her også med f-string som er nytt for 3.6.
Kode:

def hotel_cost(netter):
    total = 140 * netter
    return total

days = int(input("Hvor mange netter? "))
print(f'{days} netter har en en pris på {hotel_cost(days)}.-')

Output:
Kode:

Hvor mange netter? 5
5 netter har en en pris på 700.-


Pope 24. august 2017 18:04

Stryk det siste spørsmålet mitt. Jeg ser jo at jeg selv bestemmer hvilken variabel jeg bruker når jeg kaller på de ulike funksjonene.

Er overgangen fra 2-3 vanskelig om man lærer seg 2 da? Virker litt meningsløst å bruke tid på dette om jeg må lære mye på nytt når jeg skal bruke 3.

vidarlo 24. august 2017 18:08

Sitat:

Sitat av Pope (Innlegg 3396085)
Er overgangen fra 2-3 vanskelig om man lærer seg 2 da? Virker litt meningsløst å bruke tid på dette om jeg må lære mye på nytt når jeg skal bruke 3.

Kan du programmering handler nye språk seg om å lære syntax. Ein dag gjer mykje.

Viare er ikkje python 2 på dødsleiet akkurat. 3 er nok på frammarsj, men det e rnok en del år til 2 er dødt.

Tommel Totter 24. august 2017 18:30

Ting blir fremdeles skrevet og vedlikeholdt for både Python 2.4, 2.5, 2.6 og 2.7, alt avhengig av hvor gammel installasjon man har (på en produksjonsserver er det ikke helt uhørt at man er begrenset til 2.4 eller 2.5). Python 3 er fint og flott og har mange fordeler, men fremdeles er det noen moduler jeg bruker aktivt som ennå ikke er portet fra 2 til 3, så da er jeg stuck med 2.7, ihvertfall i overskuelig fremtid.

snippsat 24. august 2017 18:41

Sitat:

Sitat av Pope (Innlegg 3396085)
Er overgangen fra 2-3 vanskelig om man lærer seg 2 da? Virker litt meningsløst å bruke tid på dette om jeg må lære mye på nytt når jeg skal bruke 3.

Overgangen er nok grei,
men som ny bruker er det best og bli vant til Python 3.
Det går fint og ha Python 2 og Python 3 installert samtidig.

Som nevnt kan bruke 2to3 for og gjøre Python 2 til Python 3.
Kode:

C:\Python36\Tools\scripts
λ 2to3 -w pope.py

Etter denne ha kjørt ser det sånn ut.
Kode:

def hotel_cost(netter):
    total = 140 * netter
    return total

total = hotel_cost(int(input("Hvor mange netter? ")))
print(total)

Som du ser har print() blitt en funksjon og raw_input() har blitt fjernet,
kun input() i Python 3.

Pope 7. september 2017 00:28

Ny liten nøtt. Mulig dette blir et mer diffust spørsmål, men vi prøver.
Jeg bruker disse linjene:

Kode:

KS = np.zeros((16,16),dtype=float)
KS = add2stiffness(K1,local2global1,KS)   
KS = add2stiffness(K2,local2global2,KS)   
KS = add2stiffness(K3,local2global3,KS)
KS = add2stiffness(K4,local2global4,KS)   
KS = add2stiffness(K5,local2global5,KS)   
KS = add2stiffness(K6,local2global6,KS)

til å kalle på følgende funksjon: (Vet jeg kan bruke for-løkke, men er ikke det som er problemet her).

Kode:

def add2stiffness(ke,local2global,KS):
    [nrow,ncol] = shape(ke) #linjer og kolonner i ke
    for i in range(nrow):
        ig = local2global[i]-1
        for j in range(ncol):
            jg = local2global[j]-1
 
            KS[ig,jg] = KS[ig,jg] + ke[i,j]
 
    return ks

Når jeg kjører koden får jeg følgende feilmelding:
IndexError: index 6 is out of bounds for axis 1 with size 6

Kodesnuttene sier vel ikke så mye uten at dere vet hva variablene er, men variablene som sendes til funksjonen er altså matriser.

Hva kan en slik feilmelding skyldes? Feil matrisedimensjoner?:confused:

Likyhane 7. september 2017 12:13

KS[ig,jg] = KS[ig,jg] + ke[i,j] skal være KS[ig][jg] = KS[ig][jg] + ke[i][j]. Eneste jeg klarer å se, uten at jeg vet mer om hvordan matrisene ser ut.

EDIT: return ks betyr heller ingenting ut fra hva jeg ser. "ks" er ikke definert noe som helst sted.

Pope 7. september 2017 13:56

Det du nevner først har ingen betydning, så vidt jeg vet. Men feilen lå nok i returnen ja ;)
Vet ikke om det virker enda, for resten av skriptet er veldig ufullstendig, men jeg fortsetter.

nicker 7. september 2017 15:47

I python og de fleste andre programmeringspåk så starter indeksering fra null, mens det i mattematikken starter fra 1. Dvs, hvis du skal ha f.eks i,j=6,6 i ett matrise så blir dette i python [5,5].

IndexError: index 6 is out of bounds for axis 1 with size 6
Her har du et array med 6 elementer. Siden indekseringen starter fra 0 vil det siste elementet være indeksert som 5. element 6 er da ikke i arrayet.

Pope 2. februar 2018 14:59

På'n igjen :P
Jeg haltet meg igjennom det forrige kurset og tar nå et annet kurs som i grunnen er mye mer grunnleggende. Nå bruker jeg Python 3.6.

Jeg skal lage et veldig enkelt script som kan konvertere lengder.
Kode:

m = input("Hvor mange meter?")
inch = 39.3700787*m
feet = 12*inch
yard = 3*feet
mile = 1760*yard
print()
print ("{0} meters equals: {1} inch(es), {2} feet, {3} yard(s), {4} mile(s)".format(m, inch, feet, yard, mile))

Jeg får feilmeldingen:TypeError: can't multiply sequence by non-int of type 'float'

Dette tolker jeg som at Python liker ikke at jeg taster inn integer for meter og multipliserer med flyttall ved inch-konverteringen.

Om jeg gjør om 0.0264 til et integer og kjører scriptet så krasjer python fullstendig. Hva er galt?

edit: Endret inch-konvertering
edit2: Hehe, alle konverteringene er feil, men programmet skulle likevel ha virket?

Har oppdaget at feilen som gjør at det krasjer må ligge i input(). Hvorfor er dette et problem?

Realist1 2. februar 2018 15:01

Er det linje 2 du får feilmelding på? Jeg har ikke PC for hånden, så får ikke testet, men min første tanke er at input-funksjonen lagrer input som streng. Prøv m = float(input('...'))

Pope 2. februar 2018 15:02

Dette blir rotete, men her er hvertfall et oppdatert skript som i det minste konverterer riktig vei:

Kode:

m = 100*input("Hvor mange meter?")
inch = m/2.54
feet = inch/12
yard = feet/3
mile = yard/1760
m=m/100
print()
print ("{0} meters equals: {1} inch(es), {2} feet, {3} yard(s), {4} mile(s)".format(m, inch, feet, yard, mile))


moret 2. februar 2018 15:03

Om jeg gjør om 0.0264 til et integer og kjører scriptet så krasjer python fullstendig. Hva er galt?
Jeg kan ikke python, men ville gjort det andre veien. Altså, gjør meter om til et float(eller double eller whatever som er riktig type) og ikke inches til int.

Pope 2. februar 2018 15:05

Sitat:

Sitat av Realist1 (Innlegg 3422135)
Er det linje 2 du får feilmelding på? Jeg har ikke PC for hånden, så får ikke testet, men min første tanke er at input-funksjonen lagrer input som streng. Prøv m = float(input('...'))

Og der var feilen. Jeg må altså tvinge input til å være flyttall.
Har ikke hatt problemer med det tidligere, men da har jeg sikkert ikke forsøkt å multiplisere input med et flyttall heller. Takker og bukker :)

Likyhane 2. februar 2018 15:28

Input i python 3 er det samme som raw_input i python 2 så vidt jeg vet. Da er det automatisk en string. Så du vet det til senere :)

Pope 2. februar 2018 15:47

Sitat:

Sitat av Likyhane (Innlegg 3422144)
Input i python 3 er det samme som raw_input i python 2 så vidt jeg vet. Da er det automatisk en string. Så du vet det til senere :)

Ja, det stemmer at raw_input ble til input i v3. Finnes det andre kommandoer som er bedre egnet for input av integer/float eller er float(input()) beste alternativ?

Likyhane 2. februar 2018 17:13

Sitat:

Sitat av Pope (Innlegg 3422146)
Ja, det stemmer at raw_input ble til input i v3. Finnes det andre kommandoer som er bedre egnet for input av integer/float eller er float(input()) beste alternativ?

Ut fra mine noe begrensede kunnskaper, så er det den enkleste og beste metoden.

Realist1 2. februar 2018 18:31

Ja, float(input()) er standardmetoden, eventuelt caste det der det brukes i stedet. Dvs.:
Kode:

m = input('...')
n = float(m)*2.56

Men som regel, så vil du jo lagre variabelen som en float, og dermed bare kjøre float(input()) direkte. (Evt int(input()) da)
På den måten slipper du å ha tallet ditt lagret som string og caste den hver eneste gang du skal bruke den. Bare gjør det med en gang du tar den inn, så er du ferdig med det. :)

Forøvrig så betyr feilmeldingen du fikk at du kan multiplisere en streng (aka sequence) med en int, men ikke en float. Du vil altså ikke få feilmelding om du multipliserer int og str, men det vil kanskje ikke gi resultatet du ser for deg. Slik går det:
Kode:

>>> m = input('Tall: ')
Tall: 6
>>> m*3
'666'
>>> m*3.5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't multiply sequence by non-int of type 'float'

Så, som du ser, du kan fint ta inn et "tall" med input, og deretter multiplisere det med en int n uten å få feilmelding, men resultatet blir bare en streng der "tallet" ditt er plassert inntil seg selv n ganger.
Altså:
'6' * 3 = '666'
'6' * 3.5 = error

Xasma 2. februar 2018 19:37

Det er feil, realist1. Du blander stringoperasjoner og matematiske operasjoner. Int ganget med en string vil gi oppførselen du beskriver, men det er ikke det samme for input() og andre funksjoner. Jeg fant ikke ut av dette med bruk av input(), men noe annet, jeg tror det var noe i Apache Spark. Uansett, under er det to eksempler.
Kode:

m = 100.0*input()
n = 100*input()

m vil fungere og regne ut tallet du sendte inn fordi float*input() takler python til å bli en float, den skjønner det implisitt. Mens n blir en int*input(), og python gjør ikke automatisk om fra string til int, og det har med konverteringer å gjøre. Hvorfor blir en lang forklaring jeg ærlig talt ikke er sikker på at jeg kan gjøre tilstrekkelig. Her ser vi rett og slett problemet med språk der du ikke deklarerer datatyper, og det kommer fra en python fan.

Men rent kodemessig er det veldig rotete å gjøre input-kall i en multiplikasjon, det kan være greit for leseligheten å gjøre det klart hva som kommer fra input og ha det som en egen variabel. I eksempelet under kan du bare bruke m så mye du vil senere og det kommer helt klart hva som er input.

Kode:

m = float(input("meters: "))
inches = m*2.56
...


Realist1 2. februar 2018 23:08

Litt usikker på hva det er du mener jeg tar feil på. Greit nok at str*int er en stringoperasjon og ikke en matematisk operasjon, men det er syntaktisk kverulering. Jeg prøver bare å vise hva som skjer når resultatet av input()-funksjonen (som er en string) kjøres mot en float/int med en asterisk som operator, og at jeg bruker ordet "multiplisere" selv om det strengt tatt er en stringoperasjon må da være innafor. Alt annet jeg sier stemmer like fullt.

Dine eksempler vil derimot ikke fungere, noe en kjapp test viser:
Kode:

>>> 100.0*input()
5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't multiply sequence by non-int of type 'float'
>>> 100*input()
5
'5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555'

Altså, som sagt:
str*int funker, str*float funker ikke. Men Python skjønner uansett ikke at parameteren som tas inn i input()-funksjonen er noe annet enn en string, og det er vel hele poenget som trådstarter snublet i.

Xasma 3. februar 2018 14:29

Ja, min bom der, jeg presterte å fyre opp python 2.7.12 istedenfor 3.5 i farten, for der funker det.

Pope 12. februar 2018 19:52

Jeg har prøvd meg litt videre og laget et lite program som hjelper meg litt i hverdagen. Det åpner egentlig plex, plexpy, rutorrent og et par torrent trackers, men siden URLene inneholder litt privat info har jeg gjort om disse for demonstrating purposes. Til mitt bruk er dette mye mer nyttig enn å åpne en rekke nettaviser, forumer o.l.

Det vanskeligste for meg her ligger i at jeg ikke vil at skriptet skal kjøres ferdig om brukeren gir ugyldige inputs. Dette løste jeg med en while-løkke som ikke brytes før input == en av de gyldige alternativene. Planen var egentlig å lage skriptet med funksjoner da jeg tror dette er mer stuereint, men det fikk jeg ikke til.
Savner GOTO fra batch-skripting :p

Jeg mistenker at noen brekker seg litt av koden, så jeg ønsker tilbakemeldinger.

Kode:

#Imports
import webbrowser, time

#Definerer URLs
chrome_path = 'C:/Program Files (x86)/Google/Chrome/Application/chrome.exe %s'
url_1 = "http://www.freak.no"
url_2 = "http://www.vg.no"
url_3 = "http://www.facebook.com"
url_4 = "http://www.db.no"
url_5 = "http://www.yr.no"

#Start
print ("""Web Launcher
     
Full versjon:
Freak + VG + FaceBook + DB + YR

Lite versjon:
Freak + VG
""")

while True:
    while True:
        version = input("Velg versjon (f)ull / (l)ite: \nLukk programmet ved å skrive e(x)it ")
        version = version.lower()
        if version in ("f", "l", "x"): #Hvis version enten bærer verdien y, n eller x
            break#                så brytes denne while-løkka. Hvis ikke printes det som står på neste linje og løkka kjøres på nytt.
        print ("Du må velge en gyldig versjon.")
           
    if version == "f":
   
        webbrowser.get(chrome_path).open(url_1)
        webbrowser.get(chrome_path).open(url_2)
        webbrowser.get(chrome_path).open(url_3)
        webbrowser.get(chrome_path).open(url_4)
        webbrowser.get(chrome_path).open(url_5)
        break

    elif version == "l":
        webbrowser.get(chrome_path).open(url_1)
        webbrowser.get(chrome_path).open(url_2)
        break
   
    elif version == "x":
        print("Programmet lukkes")
        time.sleep(2)
        break


steili 12. februar 2018 20:10

Uten å ha kjørt koden, så ser det ut som den skal fungere ved første øyekast. Var det noe spesielt du lurte på?

Pope 12. februar 2018 20:18

Sitat:

Sitat av Pope (Innlegg 3424048)
Jeg mistenker at noen brekker seg litt av koden, så jeg ønsker tilbakemeldinger.

;) titegnkreves

steili 12. februar 2018 20:20

Sitat:

Sitat av steili (Innlegg 3424050)
Uten å ha kjørt koden, så ser det ut som den skal fungere ved første øyekast. Var det noe spesielt du lurte på?

Her er en litt mer komprimert kode. Kanskje du kan få litt inspirasjon fra den (ikke testet, men bør være brukbar)

Kode:

# Imports
import webbrowser, time

# Definerer URLs
chrome_path = 'C:/Program Files (x86)/Google/Chrome/Application/chrome.exe %s'
lite_paths = ["http://www.freak.no", "http://www.vg.no"]
full_paths = ["http://www.freak.no", "http://www.vg.no", "http://www.facebook.com", "http://www.db.no", "http://www.yr.no"]

# Start
print ("""Web Launcher

Full versjon:
Freak + VG + FaceBook + DB + YR

Lite versjon:
Freak + VG
""")

while True:
    version = input("Velg versjon (f)ull / (l)ite: \nLukk programmet ved å skrive e(x)it ").lower()
    if version in ("f", "l", "x"):  # Hvis version enten bærer verdien y, n eller x
        break  # så brytes denne while-løkka. Hvis ikke printes det som står på neste linje og løkka kjøres på nytt.
    print ("Du må velge en gyldig versjon.")
if version in ("f", "l"):
    for p in lite_paths if version == "l" else full_paths:
        webbrowser.get(chrome_path).open(p)

print("Programmet lukkes")
time.sleep(2)

Sitat:

Sitat av Pope (Innlegg 3424053)
;) titegnkreves

Aha, litt for kjapp der! Leste "mistenker at noe brekker" :-)

NAPse 12. februar 2018 22:17

Et par ting som kan være greit å tenke på:
-Ikke importer mer en du har behov for. Begrens det til de delene du faktisk bruker.
-Du har en unødvendig løkke. Og det er generelt god praksis å ikke ha "evige" løkker.

Funkjsoner i et såpass enkelt skript ser jeg ikke den store nytteverdien i, så det mener jeg du ikke trenger. ;)

Forøvrig fungerer skriptet dårlig på min maskin, da den ikke åpner neste fane før jeg lukker hele vinduet.

Mitt løsningsforslag:
SPOILER ALERT! Vis spoiler
Kode:

# -*- coding: cp1252 -*-
#Imports
from time import sleep
from webbrowser import get as chrome
   
#Definerer URLs
chrome_path = 'C:/Program Files (x86)/Google/Chrome/Application/chrome.exe %s'

versions = {"f":#Full
                ["freak.no", "vg.no", "db.no", "facebook.com", "yr.no"],
           
            "l":#Lite
                ["freak.no", "vg.no"],
           
            "pr0n":#Im Twelve Years Old and What is This?
                ["freak.com"]
            }

version = "" #Bare for å ha definert en variabel som kan brukes i while-løkka

#Start
print ("""Web Launcher

Full versjon:
VG + FaceBook + DB + YR

Lite versjon:
Freak + VG
""")
 
while version != 'x':
    version = input("Velg versjon (f)ull / (l)ite: \nLukk programmet ved å skrive e(x)it ").lower()
    if versions.has_key(version): #Hvis dictionary "versions" har gyldig nøkkel ifht. input
        for url in versions.get(version): #For hver url i lista til nøkkel gjør dette...
            chrome(chrome_path).open(url)
            break

print("Programmet lukkes")
sleep(2)



Oops. Den break'en skulle enten ikke vært der i det hele tatt, evt. vært en "indent" bakover. ;)

Pope 12. februar 2018 22:57

Sitat:

Sitat av NAPse (Innlegg 3424084)
Et par ting som kan være greit å tenke på:
-Ikke importer mer en du har behov for. Begrens det til de delene du faktisk bruker.
-Du har en unødvendig løkke. Og det er generelt god praksis å ikke ha "evige" løkker.

Funkjsoner i et såpass enkelt skript ser jeg ikke den store nytteverdien i, så det mener jeg du ikke trenger. ;)

Forøvrig fungerer skriptet dårlig på min maskin, da den ikke åpner neste fane før jeg lukker hele vinduet.

Gode tips :)

Det du nevner om at skriptet fungerer dårlig opplevde jeg ikke i det hele tatt før jeg kompilerte skriptet til .exe. Da dukket den feilen opp hver eneste gang uten at jeg helt skjønner hvorfor :confused:

Jeg tar tipsene deres til meg og forbedrer skriptet.

Så heller ikke hva den tredje "listen" hadde blitt til før jeg begynte i python :p

Dictionary heter det vel kanskje.

Hva betyr dette: AttributeError: 'dict' object has no attribute 'has_key'

Realist1 12. februar 2018 23:02

Sitat:

Sitat av Pope (Innlegg 3424093)
Hva betyr dette: AttributeError: 'dict' object has no attribute 'has_key'

Det betyr at det ikke er noe som heter "has_key" i Python3. Bare bruk "in" i stedet.

Pope 12. februar 2018 23:07

takk. Er det en annen feil her og?
I NAPse sitt skript, på linje 33:

if versions.has_key(version):

Dette gjør jeg om til:

if versions in (version): ?
Men det går rett åt skogen med mindre jeg skriver:

if version in (versions): Mulig jeg tar helt feil?

NAPse 12. februar 2018 23:07

Sitat:

Sitat av Pope (Innlegg 3424093)
Hva betyr dette: AttributeError: 'dict' object has no attribute 'has_key'

Ehh. Ja, jeg lever i oldtiden og kjører fortsatt py 2.7.
Sånn skal det visst gjøres i dette århundret.

Jeg fikla litt till og fikk det til å fungere med å åpne alle fanene rett etter hverandre. Det er nok ikke den optimale måten å gjøre det på, og er systemavhengig. (Egentlig rene windows kommandoer du kune kjørt med et batch skript.)
Du kan ta en titt om du vil.

SPOILER ALERT! Vis spoiler

Kode:

#Imports
from time import sleep
from os import system
   
#Definerer URLs
chrome_path = 'C:/Program Files (x86)/Google/Chrome/Application/chrome.exe'

versions = {"f":#Full
                ["https://freak.no", "https://vg.no", "https://db.no", "https://facebook.com", "https://yr.no"],
           
            "l":#Lite
                ["https://freak.no", "https://vg.no"]
            }

version = "" #Bare for å ha definert en variabel som kan brukes i while-løkka

#Start
print ("""Web Launcher

Full versjon:
VG + FaceBook + DB + YR

Lite versjon:
Freak + VG
""")
 
while version != 'x':
    version = input("Velg versjon (f)ull / (l)ite: \nLukk programmet ved å skrive e(x)it ").lower()
    if versions.has_key(version): #Hvis dictionary "versions" har gyldig nøkkel ifht. input
        cmd = ""
        for url in versions.get(version): #For hver url i lista til nøkkel gjør dette...
            cmd += 'start "{0}" {1} & '.format(chrome_path, url)
        system(cmd+'exit')
        break

print("Programmet lukkes")
sleep(2)


Pope 12. februar 2018 23:20

Æsj, nå datt jeg helt av lasset. Ble litt mange endringer på en gang. Skjønner forsåvidt hvorfor du ønsker å importere system fra os-modulen.
Hva gjør &-tegnet der i linje 32?

for url in versions.get(version): er heller ikke en superintuitiv linje for meg :/

Og hvorfor kan jeg ikke definere variabler for URLs før dictionary defineres? Altså, dict henter ikke inn forhåndsdefinerte variabler.

NAPse 12. februar 2018 23:37

Sitat:

Sitat av Pope (Innlegg 3424102)
takk. Er det en annen feil her og?
I NAPse sitt skript, på linje 33:

if versions.has_key(version):

Dette gjør jeg om til:

if versions in (version): ?
Men det går rett åt skogen med mindre jeg skriver:

if version in (versions):

Je den skal være "if version in versions:" i python 3.

Sitat:

Sitat av Pope (Innlegg 3424104)
Hva gjør &-tegnet der i linje 32?

Det er en windows "kommando" for å utføre neste kommando uten å vente på at forrige avslutter. Det har egentlig lite å gjøre med python, så jeg skjønner det er litt forvirrende

Sitat:

Sitat av Pope (Innlegg 3424104)
for url in versions.get(version): er heller ikke en superintuitiv linje for meg :/

dict.get(key) vil "hente" dataen som ligger under key-en i en dictionary, i dette tilfellet er det en liste som ligger der.

Kode:

>>for x in ['hei', 'på', 'deg']:
>>    print x
hei

deg

Så det er egentlig det den gjør, den henter en liste og itererer etter den lista.

Pope 12. februar 2018 23:53

Og f/l er keys mens urls er dataene i listene som ligger under dict?

Kunne du også svart på dette med å bruke forhåndsdefinerte variabler som innhold i lister (i dicts)? :)

Setter pris på hjelpen jeg får!

NAPse 13. februar 2018 00:15

Etter en liten titt i webbrowser.py så jeg dette:
Sitat:

Sitat av webbrowser.py
usage = """Usage: %s [-n | -t] url
-n: open new window
-t: open new tab""" % sys.argv[0]

Det første scriptet jeg posta skal fungere(utenom den malpasserte "break"-en) dersom du slenger på et &-teng etter %s i chrome_path.

Sitat:

Sitat av Pope (Innlegg 3424109)
Og f/l er keys mens urls er dataene i listene som ligger under dict?

Ja, "f" og "l" er keys, og hver av dem inneholder separate data under seg etter kolonet. ;)

Sitat:

Sitat av Pope (Innlegg 3424109)
Kunne du også svart på dette med å bruke forhåndsdefinerte variabler som innhold i lister (i dicts)? :)

Jeg skjønner ikke helt hva du mener, men kan prøve å komme med et eksempel til så kanskje det blir lettere å se.

Kode:

>>>innlegg_brukere = {'Pope':2323, 'NAPse':251, 'Realist1':2163}
>>>innlegg_brukere.get('NAPse')
251
>>>innlegg_brukere['NAPse']
251


Pope 13. februar 2018 06:03

Takk :) Det jeg mener er at du skriver URLene rett inn i dict. Om jeg har lange URLs hadde det vært greit å lagre de på forhånd under kortere variabelnavn og heller bruke variabelnavnene i dict (versions). Dette får jeg ikke til. Prøver bare å åpne nettsider med url=url_1 , url_2 osv.

Provo 13. februar 2018 11:09

Sitat:

Sitat av Pope (Innlegg 3424104)
Og hvorfor kan jeg ikke definere variabler for URLs før dictionary defineres? Altså, dict henter ikke inn forhåndsdefinerte variabler.

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)


NAPse 13. februar 2018 12:02

Sitat:

Sitat av Provo (Innlegg 3424187)
Det sagt, så ser jeg ikke helt nytten av en dict i dette tilfellet uansett.

Jeg kan forklare hvorfor jeg valgte det, men det er absolutt ikke nødvendig. Det er vel først og fremst en smakssak.

Jeg liker å ha kode som er enkel å modifisere i ettertid dersom jeg skulle ønske flere funksjoner i ettertid.
For eksempel dersom han skulle ønske seg en til "version"/"mode" senere trenger man kun legge til en ny nøkkel og tilhørende liste helt i "toppen" av koden uten å måtte endre flere ting.
I ditt eksempel vil man måtte legge til ny liste, endre "while user_input not in ['f','l','x']" og legge til en ekstra elif som skal håndtere den nye input-verdien.

Men som sagt; det er smak og behag. :)

Pope 13. februar 2018 14:18

Oi. Provo, tusen takk for et veldig utfyllende svar. Må innrømme at jeg måtte konsentrere meg hardt for å skjønne et par av linjene, men det var overkommelig :)

Tusen takk til deg og NAPse! Artig å se hvilke kreative innspill dere kommer med.

Jeg foretrekker nok at koden er mest mulig "vanilla python", altså uten altfor mye imports. Dette fordi det er ren Python jeg forsøker å lære og da blir det bare forvirrende med for mye annet snacks ;)

Dette med komprimering av kode er forhåpentligvis noe som blir lettere etterhvert.

Pope 14. februar 2018 15:27

Provo: Det eneste Python kicker litt på er sys.exit(). Python sier følgende: warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1). Hvorfor?

Om jeg bruker jeg disse kommandoene for å lukke programmet så kjøres likevel resten av koden.

Sitat:

sys.exit([arg])

Since exit() ultimately “only” raises an exception, it will only exit the process when called from the main thread, and the exception is not intercepted.
Altså, siden sys.exit() brukes i en funksjon og ikke i main, så lukkes ikke programmet, men funksjonen avbrytes?

edit: Hmm. Når jeg ser nærmere på det virker det som at resten av koden _ikke_ kjøres, men jeg får likevel en stygg feilmelding.
Spiller kanskje ingen rolle?

Provo 14. februar 2018 15:41

Merkelig. Hvilken Python-versjon kjører du, og hvordan kjører du scriptet? Det kan se ut som du starter scriptet fra inne i et interaktivt Python-shell av noe slag?

Hele programmet skal lukkes, den avbryter ikke bare funksjonen. Den teksten angår ikke om kallet er i en funksjon, men om det er i en egen tråd. Når man kaller sys.exit() avsluttes tråden den kalles fra, og ikke nødvendigvis hele programmet dersom man har forket eller spawnet flere tråder. Men det er ikke relevant for dette eksempelet.

Pope 14. februar 2018 15:56

Ok, jeg forstår. Jeg bruker Python 3.6 i Spyder IDE.
Jeg kompilerte skriptet til .exe og da fungerer alt som det skal.

Jeg ser uendelige muligheter med å bruke Python, men når det kommer til små operasjoner som skal utføres i Windows, som f.eks. skriptet dere har hjulpet meg med, føler jeg at det ikke er noen vits i å bruke slike skript når man likevel må åpne Python for å kjøre de.

Det er derfor jeg kompilerer de så de kan brukes uten Python, men jeg synes pyinstaller, py2exe osv er en kålete måte å kompilere på. Finnes det andre måter å kjøre skriptene på, evt. andre måter å kompilere de på?

snippsat 14. februar 2018 18:10

Ser greit ut prove,men 2-space intendering du vet sikkert godt at det burde/skal være 4-space i Python ;)

Her et alternativ du kan se på @Pope,kunne fint ha brukt funksjoner her.
Men en klasse fungere også bra da listene og path kan gjøres i klasse instantiation(__init__).
Når man kjører så faller man alltid tilbake til menu,her kan kjøres igjen eller Quit for komme seg ut.
Ikke noe sys.exit() da en enkel return vil fungere greit her,ettersom det er ingen forurensning i global namespace.
Kode:

import webbrowser

class OpenUrl:
    def __init__(self, chrome_path):
        self.chrome_path = chrome_path
        self.urls_basic = [
          "http://www.freak.no",
            "http://www.vg.no"
            ]
        self.urls_extra = [
            "http://www.facebook.com",
            "http://www.db.no",
            "http://www.yr.no"
            ]
        self.menu()

    def open_location(self, urls):
        for url in urls:
            webbrowser.get(self.chrome_path).open(url)

    def menu(self):
        while True:
            print('(L) Lite version')
            print('(F) Full version')
            print('(Q) Quit\n')
            choice = input('Enter your choice: ').lower()
            if choice == 'l':
                self.open_location(self.urls_basic)
            elif choice == 'f':
                self.open_location(self.urls_extra)
            elif choice == 'q':
                return
            else:
                print(f'Not a correct choice: <{choice}>,try again\n')

if __name__ == '__main__':
    chrome_path = "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe %s"
    OpenUrl(chrome_path)

He 2-space på meg og,det er forum som gjør det.

Sitat:

Sitat av Pope
føler jeg at det ikke er noen vits i å bruke slike skript når man likevel må åpne Python for å kjøre de.

Det gir jo ingen mening,når du først har Python installert er det klart at man bruker Python til og kjøre koden.
Scenario når man kan kompilere er når man ønsker og dele koden med mange Windows brukere som ikke har Python installert.

Sitat:

Sitat av Pope
men jeg synes pyinstaller, py2exe osv er en kålete måte å kompilere på.

pyexe bør ikke brukes ettersom den virker kun til 3.4.
Pyinstaller er det beste valget,også cx_Freeze grei,begge virker 3.6 og er kryssplattform.
Pyinstaller er enkel og bruke,det kan være noe konfigurasjon som må gjøres i noen tilfeller.

Sitat:

Sitat av Pope
Finnes det andre måter å kjøre skriptene på, evt. andre måter å kompilere de på?

Mye av det vi gjør i dag er web-basert,så lage en web-app for dele det man lager Python er fullt mulig.
Jeg er fan av Flask,men dette kreves også at men setter seg inn i web-development.

For og dele med andre Python brukere,så bruker man PyPi.
Som betyr at man lager wheel med setup.py.
Da bruker man pip som kommer med Python.
Kode:

pip install my_stuff
Eks Requests
Kode:

pip install requests
Sitat:

13,000,000 downloads every month. All the cool kids are doing it!


Alle tidspunkt er GMT +2. Klokken er nå 15:33.