Würfel

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.
Clockworx
User
Beiträge: 2
Registriert: Montag 1. Juni 2009, 18:40

Ich möchte mit python einen "Würfel" erstellen. Das stelle ich mir so vor:
Man hat ein Fenster mit einem button, auf dem "würfeln" steht. wenn man darauf drückt, soll eine zufällige Zahl zwischen 1-6 erscheinen. Dies kann man dann beliebig viel wiederholen.
Ich habe wenig Vorkenntnisse und wäre sehr erfreut, wenn mir jemand Tipps geben könnte(z.B. nützliche funktionen)
vielen Dank im voraus
BlackJack

@Clockworx: Als erstes solltest Du das Tutorial in der Python-Dokumentation durcharbeiten. Dann sind die Module `Tkinter` für die grafische Oberfläche und `random` für die Zufallszahl interessant.
problembär

Ist wohl'n bißchen unfair, weil Du's kaum verstehen kannst:

Code: Alles auswählen

#!/usr/bin/env python
#-*- coding: iso-8859-1 -*-
import Tkinter, random
root = Tkinter.Tk()
btn = Tkinter.Button(root,
                     text = "würfeln",
                     command = lambda: btn.configure(text = str(random.randrange(6) + 1)))
btn.pack(padx = 30, pady = 30)
root.mainloop()
Gruß
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

@Clockworx:
Vermutlich wäre es das beste, wenn du dich für die nächsten Wochen von der Vorstellung "Ich klicke auf einen Button und dann passiert etwas" zunächst verabschieden würdest und erst einmal die Grundlagen von Python lernen würdest. Das hat nämlich - wie in den meisten Programmiersprachen - mit "Button anklicken" zunächst einmal gar nichts zu tun. Ein Programm soll ja beim "Button anklicken" nicht irgendetwas machen, sondern etwas bestimmtes - und das hat mit dem Klick an sich meist wenig zu tun.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

@problembär: Wa willst du mit

Code: Alles auswählen

random.randrange(6) + 1
bewirken? Ist das so etwas wie

Code: Alles auswählen

random.choice(range(6) + [1])
? Und warum nicht

Code: Alles auswählen

random.randint(1, 6)
?
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Was hast du gegen randrange()?

Ich benutze randint() nie, weil es noch langsamer ist als randrange(). :D
Außerdem hat randint() den Nachteil, dass bei randint(a,b) ganz entgegen all dem, was in Python sonst üblich ist, b mit enthalten ist. Das ist bei randrange() nicht so. Und schließlich ist randrange() flexibler als randint(), weil z.B. auch so etwas geht: randrange(5,501,5).

Fazit: randint() ist überflüssig, randrange() ist die bessere Wahl.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Bei einer Liste, die 6 Objekte enthält, spielt Geschwindigkeit doch keine große Rolle. Das Argument mit der Inkonsistenz kann ich allerdings verstehen. Meine Fragen waren übrigens nicht rhetorisch gemeint. Ich habe also keine Abneigung gegen randrange, sondern war nur verwundert über den Code.
ichbinsisyphos
User
Beiträge: 120
Registriert: Montag 4. Juni 2007, 19:19

problembär hat geschrieben:...
Verdammt, ich hab nicht gewusst, dass TKinter so simpel ist. Das beantwortet dann wohl auch die Frage, wieso irgendjemand, bei all den Alternativen, so ein obskures Toolkit benützt.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

PyQt ist genauso simpel - zumindest solche Anwendungen ;)
(Bei GTK + wxWindows ist das bestimmt genauso)

Ich denke der Hauptgrund ist nicht die Einfachheit, sondern die Verfügbarkeit, da Tkinter batteriebetrieben ist ;)
lunar

@Numerix
Es ist doch nett, dass die Bibliothek dir mit "randint()" sogar die ansonsten erforderliche Addition mit eins abnimmt ;) Außerdem ruft "randint(a, b)" ruft direkt "randrange(a, b+1)" auf. Wenn du das was misst, dann die Verzögerung durch Funktionsaufrufe und die Addition ... und letztlich sieht "randint(1, 6)" einfach besser aus als "randrange(6) + 1".

@problembär
Die Qt4-Version ist nur unwesentlich länger ;)

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys
from random import randint
from PyQt4 import QtCore, QtGui

app = QtGui.QApplication(sys.argv)
button = QtGui.QPushButton(u'Würfeln')
button.connect(button, QtCore.SIGNAL('clicked()'),
               lambda: button.setText(unicode(randint(1,6))))
button.show()
app.exec_()
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

lunar hat geschrieben:@Numerix
Es ist doch nett, dass die Bibliothek dir mit "randint()" sogar die ansonsten erforderliche Addition mit eins abnimmt ;) Außerdem ruft "randint(a, b)" ruft direkt "randrange(a, b+1)" auf. Wenn du das was misst, dann die Verzögerung durch Funktionsaufrufe und die Addition ... und letztlich sieht "randint(1, 6)" einfach besser aus als "randrange(6) + 1".
Wieso denn 1 addieren?
randrange(1,7) leistet das gleiche wie randint(1,6), außer, dass ich mir bei randint() merken muss, dass bei randint(a,b) das b - anders als bei range/xrange, slicing etc. mit drin ist. Eine potentielle Fehlerquelle! randint() braucht kein Mensch.
BlackJack

@numerix: Du hast doch 1 addiert. Sonst würde da nicht 7 stehen. Bei `randrange()` muss man sich im Gegenzug merken, dass die Obergrenze nicht enthalten ist. Wenn ich keinen zufälligen Index generieren möchte, sondern eine Zahl von 1 bis 6 inklusive, finde ich `randint()` deutlicher und direkter.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

BlackJack hat geschrieben:@numerix: Du hast doch 1 addiert. Sonst würde da nicht 7 stehen. Bei `randrange()` muss man sich im Gegenzug merken, dass die Obergrenze nicht enthalten ist. Wenn ich keinen zufälligen Index generieren möchte, sondern eine Zahl von 1 bis 6 inklusive, finde ich `randint()` deutlicher und direkter.
Kann ich überhaupt nicht nachvollziehen.
Nun kennst du Python weit besser als ich, aber soweit ich sehe, gilt außer bei randint(a,b) bei der Angabe von Bereichen IMMER, dass der zweite Wert exklusiv ist und ich halte es für überaus sinnvoll, das so etwas konsistent durchgehalten wird, weil das sonst eine potentielle Fehlerquelle ist. Darum ist das davon abweichende Verhalten von randint() für mich inkonsistent. Da randint() außerdem langsamer und weniger flexibel ist (keine Schrittweite möglich), sehe ich nicht, warum ich randint() an irgendeiner Stelle randrange() vorziehen sollte.
lunar

numerix hat geschrieben:Nun kennst du Python weit besser als ich, aber soweit ich sehe, gilt außer bei randint(a,b) bei der Angabe von Bereichen IMMER, dass der zweite Wert exklusiv ist und ich halte es für überaus sinnvoll, das so etwas konsistent durchgehalten wird, weil das sonst eine potentielle Fehlerquelle ist.
Das gilt nur für Slicing und alle "*range()"-Funktionen. Eine allgemeine Konvention besteht da nicht, und Fehlerquelle ist auch nur dann, wenn man nicht in die Doku schaut.
Da randint() außerdem langsamer [...] ist.
Mich würde interessieren, wie du darauf kommst ...
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

..... Hier noch als weitere Ergänzung die wxPython-Variante:

Code: Alles auswählen

import wx
from random import randint

app = wx.App()

app_win = wx.Frame(None, size=(100,100))
button = wx.Button(app_win, label=str(1))
app_win.Bind(wx.EVT_BUTTON,
    lambda event: button.SetLabel(str(randint(1,6))), button)

app_win.Show()
app.MainLoop()
Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

lunar hat geschrieben:
Da randint() außerdem langsamer [...] ist.
Mich würde interessieren, wie du darauf kommst ...
Weil es auf meinem System so ist - mag woanders anders sein:

Code: Alles auswählen

from time import time
from random import randint, randrange, random

def test():
    t0 = time()
    for k in xrange(10**6):
        n = randint(1,6)
    print time()-t0
    t0 = time()
    for k in xrange(10**6):
        n = randrange(1,7)
    print time()-t0
    t0 = time()
    for k in xrange(10**6):
        n = int(random()*6)+1
    print time()-t0

test()
Python 2.5:

Code: Alles auswählen

6.84303498268
5.88890886307
1.54791784286
Python 2.6:

Code: Alles auswählen

9.91317200661
7.94979190826
2.14650988579
Python 3.0 (syntaktisch angepasst):

Code: Alles auswählen

10.7660419941
9.33516716957
2.65259599686
Jython 2.2

Code: Alles auswählen

17.42199993133545
14.800999879837036
9.039999961853027
Jython 2.5rc

Code: Alles auswählen

19.5909998417
15.2780001163
3.43799996376
Benutzeravatar
HerrHagen
User
Beiträge: 430
Registriert: Freitag 6. Juni 2008, 19:07

Mich würde interessieren, wie du darauf kommst ...
Ein Blick in die Quellen zeigt warum:

Code: Alles auswählen

    def randint(self, a, b):
        """Return random integer in range [a, b], including both end points.
        """

        return self.randrange(a, b+1)
Ich finde randint trotzdem schöner. Die Verbindung dieser Funktion zu range und den slice-Operationen sehe ich einfach nicht. Es ist eine ganz normale Funktion die halt genau das bietet was benötigt wird. Wenns zeitkritisch wird, taugen die beiden Funktionen eh nichts. Dann würde ich gleich ein ganzes Feld von Zufallsvariaben mit numpy erzeugen.

MFG HerrHagen
lunar

Ich kenne die Quellen von "randint()", daher habe ich ja auch nachgefragt. "randint()" selbst ist nicht langsam, was Numerix da gemessen hat, sind einzig die Kosten eines Funktionsaufrufs in Python und einer Addition in Python. Mit diesem Argument könnte man gleich auf Funktionen verzichten ...
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

lunar hat geschrieben:Ich kenne die Quellen von "randint()", daher habe ich ja auch nachgefragt. "randint()" selbst ist nicht langsam, was Numerix da gemessen hat, sind einzig die Kosten eines Funktionsaufrufs in Python und einer Addition in Python. Mit diesem Argument könnte man gleich auf Funktionen verzichten ...
Diese Argumentation kann ich nicht nachvollziehen.
Fakt ist doch:
- randint() ist langsamer als randrange() - ob nun durch einen Funktionsaufruf und/oder eine Addition, spielt doch keine Rolle
- randrange() ist leistungsfähiger durch die optionale Schrittweite
- randrange() fügt sich durch den ausgeschlossenen Wert für die obere Intervallgrenze besser in das bestehende Konzept von range/slicing
- randrange() ist nicht komplizierter einzusetzen zu verstehen o.ä. als randint()

Was bleibt also als Argument für randint(), außer, dass man sich daran gewöhnt hat und es nach meinem Eindruck häufiger in Quelltexten auftaucht als randrange()?

Vor allem: Wieso wird so ein Wind gegen randrange() gemacht? Was ist denn schlecht an randrange()? Oder liegt es einfach daran, dass es einigen weniger vertraut ist als randint() und darum nicht gut gelitten ist?
Antworten