Olen python-noviisi. Pitääkö tehdä jotain erikoista saadakseen käyttöön ison listan, jossa indeksit ulottuvat alueelle 1...15000000. Kun yritän asettaa tietylle listan alkiolle arvoa niin ei onnistu millään. If-lauseella onnistun kyllä testaamaan että arvo = 0 tai siitä ei ainakaan valita. Indeksille i on määrätty arvo mutta t(i) = 1 tai t(i) += 1 ei toimi. Alussa olen määrittänyt tyhjän listan rivillä t = []. Mitä puuttuu?
Pythonissa listaa ei voi luoda halutun kokoiseksi, vaan sinne lisätään yksittäisiä alkioita kunnes haluttu koko on saavutettu.
Haluat mahdollisesti käytää sanakirjaa (dictionary). Tämä on erityisesti kannattavaa, jos suurin osa indekseistä ei ole käytössä.
%alustus t = {} %lisäys t[100] = 1 %haku if t.has_key(i): value = t[i] %poisto if t.has_key(i): del t[i]
Epäilinkin vessassa että indeksi on ympäröitävä hakasuluilla. lista on kokonaislukulista. Aloittelijan moka!
Nyt se ilmoittaa: list index out of range
Eli miten tuo listan ulottuvuus määritellään. VB:ssä on määrittely:
Dim t(15000000) As Long, mutta miten pythonissa? En löytänyt oppaasta ohjetta tähän. Olen kai huono hakemaan.
setä kirjoitti:
Nyt se ilmoittaa: list index out of range
Eli miten tuo listan ulottuvuus määritellään. VB:ssä on määrittely:
Dim t(15000000) As Long, mutta miten pythonissa?
Näyttää siltä, että käytät tuossa vieläkin listaa sanakirjan sijasta. Huomaa, että lista määritellään hakasuluilla ja sanakirja aaltosuluilla, mutta molempiin viitataan kuitenkin hakasuluilla. Pythonissa sanakirjan kokoa ei tarvitse määritellä, vaan se kasvaa sitä mukaa kun siihen lisää dataa.
Onko pythonissa lista jokin tietty taulukko ja sanakirja jokin toinen taulukko. En mitään sanakirjaa ole värkkäämässä vaan kokonaislukutaulukkoa. Siis määrittely hakasulkujen sijaan kaarisuluilla! Nyt tulee:
IndexError: tuple index out of range
TypeError: 'tuple' object does not support item assignment
Miten ihmeessä pythoniin saa ison kokonaislukutaulukon, jossa kaikki indeksit ovat käytössä? Vai eikö tuo kieli sellaista sisällä lainkaan???
setä kirjoitti:
Onko pythonissa lista jokin tietty taulukko ja sanakirja jokin toinen taulukko. En mitään sanakirjaa ole värkkäämässä vaan kokonaislukutaulukkoa. Siis määrittely hakasulkujen sijaan kaarisuluilla!
Sanakirja poikkeaa listasta siten, että sanakirjan indeksit voivat olla mitä tahansa kuten vapaavalintaisia lukuja tai merkkijonoja. Jos yrität määritellä listaa kaarisuluilla, saat tuplen, jota ei voi muokata, eli siitä tuskin on hyötyä sinulle.
Jos sinulla on aivan pakottava tarve luoda lista, jossa on 15000000 alkiota arvolla 0, onnistuu se näin.
lista = [0] * 15000000
setä kirjoitti:
Miten ihmeessä pythoniin saa ison kokonaislukutaulukon? Vai eikö tuo kieli sellaista sisällä lainkaan???
Pythonissa ei ole tiukkaa tyypitystä, joten siinä ei ole erikseen kokonaislukutaulukkoja.
No just tuo on pakko tehdä, kiitos.
Sain viimein simulaationi pelittämään mutta python on jumalattoman hidas. VB:llä homma hoituu paljon sukkelammin mutta satunnaisluku on rajallinen ja muutenkin numeroiden määrä. Mikä olisi sopiva kieli, onko pakko ruveta vanhana opiskelemaan jotain C++ vai mikä olisi passeli kieli VB:n jälkeen.
Jos kerrot millaisen simulaation teit, voisimme vinkata mahdollisesti parempaa toteutusta Pythonilla.
C++ taipunee kaikkeen mitä yrität, mutta vaatii jonkin verran opettelua.
Asensin itselleni Pythonin version 2.7.1 64-bittiseen Windows 7:ään. Piti arpoa satunnaisesti kokonaislukuja väliltä 0...15 milj. ja ilmaista arvontojen määrä kun enää yksi luku oli arpomatta ja kun lopulta se viimeinenkin tuli arvottua.
# -*- coding: latin-1 -*- import random for j in range(10): t = [0]*15380937 s = 0 n = 0 f = 0 while s < 15380937: i = random.randint(0, 15380936) if t[i] == 0: t[i] = 1 s += 1 n += 1 if s == 15380936 and f == 0: n1 = n f = 1 print n1, n
VB:llä 20 kierroksen arvontaan meni muutama minuutti mutta tämän koodin pyöritys vei noin 1,5 h.
for j in range(10): t = {} s = 0 n = 0 f = 0 while s < 15380937: i = random.randint(0, 15380936) if t.get(i, 0) == 0: t[i] = 1 s += 1 n += 1 if s == 15380936 and f == 0: n1 = n f = 1 print n1, n
Siinä sama Dictionarylla (En viellä testannut) kuten yllä ehdotettiin, ottamatta kantaa itse koodiin.
Edit. Pääsinkin jo testaamaan ja toimii.
Edit2. get:in tilalle kävisi tietysti myös has_key(). get on parempi tietyissa tapauksissa, mutta en tiedä onko niillä suuria nopeuseroja.
Laitoin pyörimään mutta hitaalta vaikuttaa tämäkin. Pitikö sen näin toimia nopeammin vai miksi tämä olisi suositeltavampi ratkaisu?
Edit: Näyttää kestävän yli 2 tuntia. Mittaampa nopeuden hieman tarkemmin.
Nopeudesta en tiedä, luultavasti ei suuria eroja (joku viisaampi voi kertoa?). Etuna lähinnä se ettei tarvitse määritellä kokoa vaan koko kasvaa sitä mukaan kuin tarvitaan.
Noita erilaisten toteutusten nopeuseroja kannattaisi testata vaikka sata kertaa pienemmällä taulukolla, jotta suoritusaika on noin 10-60 s.
Veikkaan listaa nopeammaksi tuossa tapauksessa, koska kaikkia alkioita tarvitaan. Sanakirjasta (dictionary, {}) on etua muistin säästämisessä, jos vain pientä osaa lukualueesta oikeasti käytetään. Kolmas vaihtoehto on joukko (set).
Tein mittausversiot molemmista. Lista oli hieman nopeampi, miljoona arvontaa 2,9 sekunnissa ja kirjastona 3,5 s.
Käytin apuna Antin kirjoittamaa Python-opasta. Kuinkahan tuota joukkoa tässä käytetään ja mistä tähän Pythoniin saa tarkempaa tietoa, mieluummin suomeksi?
Pythonissa varsinainen pullonkaula saattaa olla tuo funktiokutsu.
Ajoin testin 100000 luvulla ja alustuksella random.seed(0)
. Arvontoja tuli tällöin ajettua 1150713. Listaan perustuva versio vei 4,3 sekuntia. Set-versio tyhjästä täyteen päin vei 4,7 sekuntia ja set-versio täydestä tyhjään päin vei 4,5 sekuntia. (Näiden ero on siinä, että kun set aluksi sisältää kaikki ja lukuja poistetaan, setin koko keskimäärin on pienempi, koska viimeisiä lukuja joudutaan hakemaan pidempään kuin ensimmäisiä.) Täsmälleen sama määrä pelkkiä arvontoja ilman kirjanpitoa vei jo 4,0 sekuntia.
Ajoin vielä testin VB5:llä ja miljoonaan arvontaan kirjanpitoineen meni melko tarkasti 80 ms.
Yleisimmän ja tuetuimman Python-toteutuksen (CPython) tilalla voi kokeilla suorituskykyisempää PyPyä.
Täytin sadantuhannen alkion kokoisen taulukon kymmenen kertaa:
CPython (Python 2.6.4):
$ time python test.py 1114711 1163988 1046070 1180377 1108874 1161013 1101852 1173923 1016151 1032114 1119036 1319794 1025606 1026722 1065318 1136217 1193189 1207619 1179027 1183550 real 0m32.061s user 0m32.050s sys 0m0.010s
PyPy:
$ time ~/pypy-1.4/bin/pypy test.py 1054526 1068945 1033222 1260999 1251017 1266189 1068709 1116446 1077002 1113051 1168525 1235442 1116246 1262609 1028934 1055615 1071553 1075678 1075551 1079500 real 0m2.439s user 0m2.410s sys 0m0.030s
Onkos tuo PyPy ilmainen ja mistä ladattavissa?
Edellisessä viestissäni olevan linkin takaa näyttäisi löytyvän 32-bit Windows-binääri.
Kovin on ruuhkainen palvelin kun tulee muutama 10 tavua sekunnissa. Ei meinaa onnistua lataus millään.
Kyllä tuo minulla latautui ihan parissa sekunnissa osoitteesta http://pypy.org/download/pypy-1.4.1-win32.zip, joten tarkistapa oma nettiyhteytesi.
Mulla on saunalahden 1 Mbit/s yhteys ja yleensä latausnopeus on 112 B/s. Mutta tuosta osoitteesta tulee huomattavasti hitaammin ja lopulta katkeaa kokonaan.
Kokeiles http://pessi.kapsi.fi/pypy-1.4.1-win32.zip tuosta ladata.
Kiitos, sieltähän se tuli ongelmitta.
Chiman, voitko antaa pari vinkkiä, miten tuota PyPyä käytetään. Miten sinne saa olemassa olevan ohjelman, miten se käännetään ja ajetaan?
Voiko Pythonilla käsitellä myös binääritiedostoja tekstitiedostojen lisäksi?
PyPyä käytetään niin, että ajetaan Python-kooditiedosto käyttäen PyPy-binääriä normaalin Python-binäärin sijasta. Ei siinä mitään erillistä käännösvaihetta ole, vaan PyPy hoitaa sisäisesti kaiken tarvittavan. Windows-versiota en ole kokeillut, joten en osaa antaa tarkkoja komentoja.
Linuxilla purin pypy-paketin kotihakemistooni, jolloin ajokomento oli:
~/pypy-1.4/bin/pypy test.py
Pythonilla voi käsitellä myös binääritiedostoja.
Kun tallensin python-tiedoston samaan kansioon, jossa pypy.exe on, toimi komennolla pypy tiedosto. Mutta ohjelma ajoi vain yhden for-silmukan ja ilmoitti virheestä vaikka pythonilla (2.7) ohjelma toimi oikein. Pypy on kai tehty versiolla 2.5. Johtuneeko tosta versioiden erosta. kesti kuitenkin yli kolme minuuttia sen yhden arvonnanryppään suoritus, siis noin 2,6 E8 arvontaa.
PyPy ei tue kaikkia CPythonin mukana tulevia kirjastoja, joten PyPy ei sovellu kaikkiin käyttötapauksiin. Pastea virheilmoitus ja mahdollisesti siihen liittyvää koodia, jos haluat vinkkiä.
En nyt muista kuinka saan tosta komentoikkunasta mitään kopsattua.
Koodi on tuolla ylempänä. Virhe tuli toisen for-silmukan alkuun rivillä 12 t(i) = 1 (piti olla hakasulut mutta siitä tulikin italic). En nyt muista mitä kaikkea herjaa se heitti mutta ajan uudelleen ja kopioin vaikka käsin.
Traceback (most recent call last): File "app_main.py", line 53, in run_toplevel File "test1", line 15, in <module> t[i] = 1 MemoryError
Eka silmukka meni virheettä ja myös toinen jonkin aikaa. Koodiin on lisätty ajanmittauskäskyt, muuten sama kuin yllä. (Kuinkahan nuo hakasulut saa tungettua tuonne ilman että heittää tekstin kursiiviksi.) (Mod. vastaa: tageilla [h] ja [/h] tai käyttämällä kooditagia.)
Aihe on jo aika vanha, joten et voi enää vastata siihen.