Temporäre Dateien erzeugen und auslesen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Chr0medome
User
Beiträge: 26
Registriert: Freitag 20. Juli 2018, 15:39

Freitag 20. Juli 2018, 16:00

Hallöchen zusammen.

Also ich habe ein Skript geschrieben, das mit einem, zwar ineffizienten aber eigenem, Algorithmus, in einem angegebenen Breich alle Primzahlen auflistet.

Da ich gerne mit den Zahlen weiterarbeiten möchte, möchte ich gerne eine temporäre Datei erstellen, die mir entweder jede gefundene Primzahl in eine einzelne Zeile schreibt, oder sie mit einem Komma voneinander trennt.

Außerdem wäre es gut wenn man mir jemand dazu erklärt wie man jede einzelne Zahl auch wieder ausliest, bzw. weiterarbeiten kann.

Der Code des Programms:

Code: Alles auswählen

from decimal import Decimal, ROUND_UP

def getAllPrime(minPrime, maxPrime):
    notPrime = []
    isPrime = []

    while int(maxPrime) > minPrime:
        maxPrime -= 1
        indexPrime = len(str(maxPrime)) - 1
        exceptPrime = ["2", "4", "5", "6", "8", "0"]
        if str(maxPrime)[indexPrime] in exceptPrime:
            if str(maxPrime) == "2" or str(maxPrime) == "5":
                isPrime.append(maxPrime)
        else:
            if sum([int(char) for char in str(maxPrime)]) % 3 == 0:
                notPrime.append(maxPrime)
            else:
                if int(maxPrime)**0.5%1 != 0.0:
                    div = Decimal((maxPrime + 1)**0.5).quantize(Decimal('1.'),
                                                  rounding = ROUND_UP)
                    while div > 2:
                        if div%5 == 0 or div%2 == 0:
                            div -= 1
                        division = maxPrime%div
                        if division != 0.0:
                            """print("Searching", maxPrime, "/", div, "=", maxPrime/div) 
                               - Kann man hinzufügen, wenn man gerne einen Statusbericht haben möchte... """ 
                            div -= 1
                        elif division == 0:
                            """print("Searching", maxPrime, "/", div, "=", maxPrime/div) 
                                - Kann man hinzufügen, wenn man gerne einen Statusbericht haben möchte... """ 
                            notPrime.append(maxPrime)
                            break
                    else:
                        isPrime.append(maxPrime)
                else:
                    notPrime.append(maxPrime)
    print(isPrime)
                                   
if __name__ == "__main__":                                               
    getAllPrime(1, 1000000)
Sirius3
User
Beiträge: 8831
Registriert: Sonntag 21. Oktober 2012, 17:20

Freitag 20. Juli 2018, 16:29

Halte Dich an die Namenskonvention: alle Funktionen und Variablennamen schreibt man klein_mit_unterstrich. Bei einer Funktion die get_xxx heißt, erwarte ich, dass sie etwas zurückliefert und nicht etwas auf dem Bildschirm ausgibt. Mehrzeilige Strings sind keine Kommentare, Kommentare werden mit # eingeleitet.
maxPrime ist ein irreführender Name, weil er nicht die maximale Primzahl ist, die getestet wird, sondern die aktuelle Zahl, die auf eine Primzahl getestet werden soll. maxPrime ist schon ein int, braucht also nicht immer wieder in ein solches umgewandelt werden. Man sollte nicht die selbe Zahl fünf! mal hintereinander in einen String verwandeln. Wenn man eine Zahl als String braucht, dann speichert man das Ergebnis in einer Variablen. Die Länge des Strings muß man nicht ermitteln, weil man mit Index -1 auch auf das letzte Zeichen eines Strings zugreifen kann.
Computer sind sehr schnell darin, eine Zahl auf Teilbarkeit mit 2 oder 5 oder 3 zu testen. Das mit Eselsbrücken, die man aus der Schule für's Kopfrechnen kennt, nachzuprogrammieren ist nur umständlich und langsam. Warum werden durch 5 oder durch 2 teilbare Zahlen nicht in nonPrimes gespeichert? Warum ist 3 keine Primzahl?
Wenn division nicht ungleich 0 ist, dann ist der elif-Fall auf jeden Fall erfüllt. Warum testest Du einmal auf 0.0 und einmal auf 0?

Zur Frage: mit welchem Tutorial lernst Du und hast Du dort schon das Kapitel über Dateioperationen gelesen?
Chr0medome
User
Beiträge: 26
Registriert: Freitag 20. Juli 2018, 15:39

Freitag 20. Juli 2018, 17:04

Hi. Erstmal vielen dank für die schnelle Antwort!
Also:
Sirius3 hat geschrieben:
Freitag 20. Juli 2018, 16:29
Halte Dich an die Namenskonvention: alle Funktionen und Variablennamen schreibt man klein_mit_unterstrich.
Jawohl das war mir anders aus Java bekannt...
Sirius3 hat geschrieben:
Freitag 20. Juli 2018, 16:29
Bei einer Funktion die get_xxx heißt, erwarte ich, dass sie etwas zurückliefert und nicht etwas auf dem Bildschirm ausgibt.
Ich verstehe was das angeht leider nicht was du meinst..?
Sirius3 hat geschrieben:
Freitag 20. Juli 2018, 16:29
maxPrime ist ein irreführender Name, weil er nicht die maximale Primzahl ist, die getestet wird, sondern die aktuelle Zahl, die auf eine Primzahl getestet werden soll. maxPrime ist schon ein int, braucht also nicht immer wieder in ein solches umgewandelt werden. Man sollte nicht die selbe Zahl fünf! mal hintereinander in einen String verwandeln. Wenn man eine Zahl als String braucht, dann speichert man das Ergebnis in einer Variablen. Die Länge des Strings muß man nicht ermitteln, weil man mit Index -1 auch auf das letzte Zeichen eines Strings zugreifen kann.
Computer sind sehr schnell darin, eine Zahl auf Teilbarkeit mit 2 oder 5 oder 3 zu testen. Das mit Eselsbrücken, die man aus der Schule für's Kopfrechnen kennt, nachzuprogrammieren ist nur umständlich und langsam. Warum werden durch 5 oder durch 2 teilbare Zahlen nicht in nonPrimes gespeichert? Warum ist 3 keine Primzahl?
Die beschriebenen Mängel habe ich jetzt hoffentlich behoben:

Code: Alles auswählen

from decimal import Decimal, ROUND_UP

def get_all_prime(bottom_bound, current_prime):
    not_prime = []
    is_prime = []

    while current_prime > bottom_bound:
        current_prime -= 1
        if current_prime % 2 == 0 or current_prime % 5 == 0:
            if current_prime == 2 or current_prime == 5:
                is_prime.append(current_prime)
            else:
                not_prime.append(current_prime)
        else:
            if sum([int(char) for char in str(current_prime)]) % 3 == 0 and current_prime != 3:
                not_prime.append(current_prime)
            else:
                if current_prime ** 0.5 % 1 != 0:
                    div = Decimal((current_prime + 1)**0.5).quantize(Decimal('1.'),
                                                  rounding = ROUND_UP)
                    while div > 2:
                        if div % 5 == 0 or div % 2 == 0:
                            div -= 1
                        division = current_prime % div
                        if division != 0:
                            div -= 1
                        else:
                            not_prime.append(current_prime)
                            break
                    else:
                        is_prime.append(current_prime)
                else:
                    not_prime.append(current_prime)
    print(is_prime)
                                      
if __name__ == "__main__":                                               
    get_all_prime(1, 10000)
Sirius3 hat geschrieben:
Freitag 20. Juli 2018, 16:29
Zur Frage: mit welchem Tutorial lernst Du und hast Du dort schon das Kapitel über Dateioperationen gelesen?
Ohne Tutorial. Nur mit bereits aus meinen vorherigen Programmen erlerntem Wissen und dem lieben Internet
Benutzeravatar
__blackjack__
User
Beiträge: 1617
Registriert: Samstag 2. Juni 2018, 10:21

Freitag 20. Juli 2018, 17:09

Dann solltest Du vielleicht mal das Tutorial in der Python-Dokumentation durcharbeiten.

Code: Alles auswählen

    **** COMMODORE 64 BASIC V2 ****
 64K RAM SYSTEM  38911 BASIC BYTES FREE
   CYBERPUNX RETRO REPLAY 64KB - 3.8P
READY.
█
Benutzeravatar
__blackjack__
User
Beiträge: 1617
Registriert: Samstag 2. Juni 2018, 10:21

Freitag 20. Juli 2018, 17:11

Zu dem `get_*()`: Bei einem Namen der mit `get` anfängt erwartet der Leser das die einen Rückgabewert hat mit dem der Aufrufer dann etwas machen kann. Nicht das die irgendwas ausgibt an das man im Programm dann nicht mehr heran kommt. Das ist auch in Java so üblich das `get`-Methoden etwas an den Aufrufer zurückgeben und nichts ausgeben.

Code: Alles auswählen

    **** COMMODORE 64 BASIC V2 ****
 64K RAM SYSTEM  38911 BASIC BYTES FREE
   CYBERPUNX RETRO REPLAY 64KB - 3.8P
READY.
█
Benutzeravatar
ThomasL
User
Beiträge: 431
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Freitag 20. Juli 2018, 17:12

Also der Algorithmus ist ja interessant, es kommen tatsächlich Primzahlen raus, in reverse order, nur fehlt die 3, dafür wird 2 ausgegeben
Zeitlich ist er allerdings nicht optimal. Für die avisierten Primzahlen bis 1Mio benötigt er bei mir 99sek.
Dieser hier braucht nur 5sek.

Code: Alles auswählen

import math

def is_prime(number):
    if number % 2 == 0:
        return False
    else:
        return all(number % factor != 0
                for factor in range(3, math.ceil(math.sqrt(number)) + 1, 2))

def show_all_primes_upto(max_num):
    return [i for i in range(2, max_num) if is_prime(i)]

for zahl in show_all_primes_upto(1_000_000):
    print(zahl)
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
Chr0medome
User
Beiträge: 26
Registriert: Freitag 20. Juli 2018, 15:39

Freitag 20. Juli 2018, 17:23

ThomasL hat geschrieben:
Freitag 20. Juli 2018, 17:12
Also der Algorithmus ist ja interessant, es kommen tatsächlich Primzahlen raus, in reverse order, nur fehlt die 3, dafür wird 2 ausgegeben
In der verbesserten Variante wird die 3 auch ausgegeben. Außerdem ist die 2 eine Primzahl :P

Könntest du die for-Schleifen vielleicht genauer erläutern? Ehrlich gesagt hab ich mit denen auch nicht sehr viel Erfahrung... :|
Benutzeravatar
ThomasL
User
Beiträge: 431
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Freitag 20. Juli 2018, 17:47

Chr0medome hat geschrieben:
Freitag 20. Juli 2018, 17:23
Außerdem ist die 2 eine Primzahl :P
Stimmt.
Könntest du die for-Schleifen vielleicht genauer erläutern? Ehrlich gesagt hab ich mit denen auch nicht sehr viel Erfahrung... :|
Für eine ausführliche Erklärung von for-Schleifen schau mal hier: https://www.python-kurs.eu/for-schleife.php

Die Funktion is_prime() liefert True für eine Primzahl und False andernfalls
(2 wird hier nicht als Primzahl gegeben, kann man aber leicht ändern)

Die For-Schleife in der Funktion show_all_primes_upto() durchläuft die Zahlen von 2 bis 1.000.000.
Wenn die Funktion is_prime() True zurück liefert, wird die Zahl in die Liste eingefügt,
die beim Rücksprung mit return an den aufrufenden Code zurück gegeben wird

Die letzte For-Schleife iteriert über die Elemente in dieser Liste und gibt sie aus.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
Sirius3
User
Beiträge: 8831
Registriert: Sonntag 21. Oktober 2012, 17:20

Freitag 20. Juli 2018, 19:32

ThomasL: um sich die Primzahlen in unter einer Sekunde berechnen zu lassen, würde man ein Sieb benutzen.
Chr0medome
User
Beiträge: 26
Registriert: Freitag 20. Juli 2018, 15:39

Freitag 20. Juli 2018, 21:09

ThomasL hat geschrieben:
Freitag 20. Juli 2018, 17:12
Also der Algorithmus ist ja interessant, es kommen tatsächlich Primzahlen raus, in reverse order, nur fehlt die 3, dafür wird 2 ausgegeben
Zeitlich ist er allerdings nicht optimal. Für die avisierten Primzahlen bis 1Mio benötigt er bei mir 99sek.
Dieser hier braucht nur 5sek.
Also ich habe mir jetzt deinen Code noch einmal genauer angeguckt und ihn ein wenig "verfeinert" :lol:

Code: Alles auswählen

import math

def is_prime(number):
    if number % 2 == 0 or number % 5 == 0 or number % 3 == 0:
        if number == 2 or number == 3 or number == 5:
            return True
        else:
            False
    else:
        return all(number % factor != 0
                   for factor in range(3, math.ceil(math.sqrt(number)) + 1, 2))

def show_all_primes_upto(min_num, max_num):
    return [i for i in range(min_num, max_num) if is_prime(i)]

for zahl in show_all_primes_upto(2, 100):
    print(zahl)
Ich habe ihn jetzt verstanden und bin sehr dankbar für die hilfreichen Tipps, die Ich bisher bekommen hab.

Leider habe ich noch immer keine Antwort auf meine eigentliche Frage bekommen... Falls mir also jemand erklären kann wie temporäre Dateien funktionieren oder einen passenden Artikel dazu kennt, wäre das wunderbar ^^

Gruß
Chr0medome
Benutzeravatar
__blackjack__
User
Beiträge: 1617
Registriert: Samstag 2. Juni 2018, 10:21

Freitag 20. Juli 2018, 21:35

@Chr0medome: Eine Verfeinerung würde ich das ja nicht nennen. Warum ziehst Du da jetzt in das ``if`` Sachen mit rein die im ``else`` schon enthalten sind?

Ein Verfeinerung wäre es gewesen `is_prime()` komplett ohne ``if``/``else`` zu schreiben in dem man die beiden Bedingungen die übrig bleiben wenn man den Divisionstest durch 2 mit in das `all()` nimmt, durch ein ``or`` verknüpft.

Und den `factor` sollte man vielleicht besser `divisor` nennen. Ist ja keine Multiplikation. Der Name `show_all_primes_upto()` hat das gegenteilige Problem von `get_*()`, denn die Funktion ”zeigt” überhaupt nichts (an).

Man könnte da auch einen Iterator zurück geben statt die Liste komplett aufzubauen. Statt eines Generatorausdrucks an Stelle der „list comprehension“, bietet sich die `filter()`-Funktion hier geradezu an.

Code: Alles auswählen

import math
from itertools import chain


def is_prime(number):
    return number == 2 or all(
        number % divisor != 0
        for divisor in chain([2], range(3, math.ceil(math.sqrt(number)) + 1, 2))
    )


def iter_primes_upto(max_num):
    return filter(is_prime, range(2, max_num))


for prime in iter_primes_upto(1000000):
    print(prime)
Eine Antwort auf Deine Frage hast Du bekommen. Nochmal: Arbeite ein Tutorial durch. Zum Beispiel das in der Python-Dokumentation.

Wobei ich mich gerade Frage warum Du etwas bzw. was Du mit *temporären* Dateien machen willst? Da gäbe es auch noch etwas zu zu sagen, aber ich vermute mal Du willst eigentlich eine ganz normale Datei.

Code: Alles auswählen

    **** COMMODORE 64 BASIC V2 ****
 64K RAM SYSTEM  38911 BASIC BYTES FREE
   CYBERPUNX RETRO REPLAY 64KB - 3.8P
READY.
█
Chr0medome
User
Beiträge: 26
Registriert: Freitag 20. Juli 2018, 15:39

Freitag 20. Juli 2018, 22:22

@__Blackjack__
Ich möchte gerne mit den gefundenen Primzahelen weiterarbeiten ohne diese Dauerhaft in einer Textdatei zu speichern. Dazu hatte ich vor das mithilfe von tempfile zu lösen?

Eine noch schönere Lösung fände ich zwar threading jedoch ist das vermutlich noch ein bisschen aufwändiger.
Benutzeravatar
__blackjack__
User
Beiträge: 1617
Registriert: Samstag 2. Juni 2018, 10:21

Freitag 20. Juli 2018, 22:29

@Chr0medome: Dazu braucht man doch weder eine temporäre Datei noch Threads. Was ist denn das eigentliche Problem das Du damit lösen willst?

Code: Alles auswählen

    **** COMMODORE 64 BASIC V2 ****
 64K RAM SYSTEM  38911 BASIC BYTES FREE
   CYBERPUNX RETRO REPLAY 64KB - 3.8P
READY.
█
Benutzeravatar
noisefloor
User
Beiträge: 2536
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: Görgeshausen
Kontaktdaten:

Samstag 21. Juli 2018, 10:57

Hallo,
Ich möchte gerne mit den gefundenen Primzahelen weiterarbeiten ohne diese Dauerhaft in einer Textdatei zu speichern.
Du speicherst die in eine Liste und übergibtst die Liste an den weiterverarbeitenden Teil deines Programms - ganz ohne IO auf der Festplatte.
Eine noch schönere Lösung fände ich zwar threading jedoch ist das vermutlich noch ein bisschen aufwändiger.
Das macht eigentlich wenig Sinn, sofern du nicht jede gefundenen Primzahl direkt weiter verarbeiten willst. Aber so wie die Frage gestellt ist brauchst du doch erst alle Primzahlen von 2 bis X, bevor du weiter machst. Dann läuft dein Programm aber linear und nicht parallel.

Zur Frage der temporären Datei: Python hat das Modul `tempfile` an Bord, was für temporäre Dateien gemacht ist. Doku zum Modul findest du in der offiziellen Python-Dokumentation.

Gruß, noisefloor
Benutzeravatar
__blackjack__
User
Beiträge: 1617
Registriert: Samstag 2. Juni 2018, 10:21

Samstag 21. Juli 2018, 12:02

@noisefloor: Selbst wenn man jede gefundene Primzahl sofort weiterverarbeiten möchte ist ein Iterator/Generator, der die sofort nach dem finden ausspuckt, sinnvoller als Threads. Schon allgemein, aber insbesondere bei CPython oder anderen Implementierungen mit „global interpreter lock“.

@Chr0medome: Wenn es nicht ums selber implementieren des Findens von Primzahlen geht, gibt es das auch schon fertig und performant. Beispielsweise im `sympy`-Package:

Code: Alles auswählen

In [21]: from sympy.ntheory import sieve

In [22]: sieve.primerange(0, 1000000)
Out[22]: <generator object primerange at 0xb3ebf144>

In [23]: primes = list(sieve.primerange(0, 1000000))

In [24]: primes[:20]
Out[24]: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71]

In [25]: len(primes)
Out[25]: 78498

Code: Alles auswählen

    **** COMMODORE 64 BASIC V2 ****
 64K RAM SYSTEM  38911 BASIC BYTES FREE
   CYBERPUNX RETRO REPLAY 64KB - 3.8P
READY.
█
Antworten