Wenn man mal einen zufälligen String braucht...

Code-Stücke können hier veröffentlicht werden.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

...dann nutzt man für temporäre Dateien natürlich [mod]tempfile[/mod], aber manchmal brauch man ja auch nen Zufallsnamen für was anderes.

Der folgende hochkomplexe Codeschnipsel kann das:

Code: Alles auswählen

import random
import string

CHARS = string.ascii_letters + string.digits

def get_random_name(length=10, chars=CHARS):
    sample = random.sample(chars, length)
    return ''.join(sample)
Ich habe mal bewusst keine exotischen Zeichen reingenommen.
Zuletzt geändert von snafu am Mittwoch 28. Oktober 2009, 18:04, insgesamt 1-mal geändert.
stuhlbein
User
Beiträge: 89
Registriert: Freitag 9. Januar 2009, 16:08

wäre "get_random_string()" ein nicht viel passender name für die funktion?
Ich finde nämlich, dass "k4rumaVT5M" (o.ä.) ein relativ exotischer name ist. ;)

Problem (vermutlich eh nur ein eventuelles) ist auch, dass der string nie länger als 62 zeichen sein kann, da die variable CHARS nur 62 character hat (stichwort: ValueError: sample larger than population) - sowas könnte man so beheben (nicht sehr hübsch, funktioniert aber):

Code: Alles auswählen

import os
import re
def get_random_string(length=10, ofsize=2048):
    return re.sub(r'[\s\W]', '', os.urandom(ofsize))[0:length]
Zuletzt geändert von stuhlbein am Mittwoch 21. Oktober 2009, 18:40, insgesamt 1-mal geändert.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Code: Alles auswählen

import random
import string

def get_random_string(length, chars):
    return ''.join(random.choice(chars) for char in xrange(length))

if __name__ == '__main__':
    chars = string.ascii_letters + string.digits
    print get_random_string(70, chars)
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

Da man ja manchmal bestimme Strings haben möchte, dachte ich mir dass es ganz nett wäre, zu bestimmen, dass man bestimmte Positionen im String bestimmen kann. (Zum Beispiel, dass Namen mit einem Buchstaben beginngen müssen).

Ich hab mal was zusammen gehackt, in welche Richtung das gehen könnte:

Code: Alles auswählen

import random

from string import (ascii_lowercase as LOWERCASE, ascii_uppercase as UPPERCASE,
    ascii_letters as LETTERS, digits as DIGITS)

ALNUM = LETTERS+DIGITS

class RandomString(object):
    def __init__(self, length=10, chars=ALNUM):
        self.length = length
        self.chars = chars
        self.rules = {}
    
    def __setslice__(self, start,stop,value):
        for i in xrange(start,stop):
            self.rules[i] = value
    
    def __setitem__(self, key, value):
        self.rules[key] = value
    
    def __call__(self):
        if type(self.length) == int:
            length = self.length
        else:
            length = random.randint(*self.length)

        chars = []
        for i in xrange(length):
            rev = -length+i
            if rev in self.rules:
                s = self.rules[rev]
            elif i in self.rules:
                s = self.rules[i]
            else:
                s = self.chars
            chars.append(random.choice(s))
        return ''.join(chars)

def get_random_name():
    r = RandomString( (6,10), ALNUM)
    r[0] = LETTERS
    return r()

get_random_digits = RandomString(8, DIGITS)
    
if __name__ == '__main__':
    print get_random_name()
    print get_random_digits()
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Code: Alles auswählen

>>> class Foo(object):
...     def __setitem__(self, key, value):
...         print type(key)
... 
>>> foo = Foo()
>>> foo[3:8:-2] = 'oink'
<type 'slice'>
>>> foo[42] = 'sprotz'
<type 'int'>
object.__setslice__ ist imho deprecated.

Edit: Ich hatte es richtig in Erinnerung: http://docs.python.org/reference/datamo ... ence-types
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

danke, gut zu wissen :)

funktioniert also einfach so :)
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Statt type(<Integer>) == int besser isinstance() verwenden. Und wenn in der vorherigen Form dann zumindest mit "is" prüfen, denn die Klasse gibts nur einmal.

Ich hatte sowas auch mal geschrieben, meine Version generiert (mithilfe einer bestimmten Relation) Namen, die man auch aussprechen kann.

http://paste.pocoo.org/show/146325/
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

Ich denke am besten löst man es mit

Code: Alles auswählen

try:
    length=int(self.length)
except ValueError:
    length = random.randint(*self.length)
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@stuhlbein: Ich finde ja, `ofsize` ist mehr ein Implementierungsdetail, daher vielleicht besser etwas in dieser Art:

Code: Alles auswählen

def get_random_string(length=10):
    s = ''
    while len(s) < length:
        s += re.sub(r'[\s\W]', '', os.urandom(length))
    return s[:length]
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

str1442: Bei Zeile 60 springt mir str.title ins Gesicht. Statt der Konstanten in den Zeilen 26/27 würde ich diese als Parameter der Funktion verwenden.
stuhlbein
User
Beiträge: 89
Registriert: Freitag 9. Januar 2009, 16:08

@snafu: ziemlich geschickt ^^ so ist's natürlich besser ;)
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wobei man das bei Bedarf noch etwas optimieren könnte. Bei jeder Anfrage sind anscheinend 20-25% verwertbare Zeichen dabei. Wenn man direkt das Zehnfache anfragt, hätte man es wahrscheinlich in einem Rutsch, allerdings auch mehr Daten im Speicher. Andererseits glaube ich, dass der Faktor Zeit/Volumen bei irgendwelchen zehnstelligen Zufallsstrings eher vernachlässigt werden kann. ;)
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

oder einfach from uuid import uuid4 ... :wink:
[url=http://29a.ch/]My Website - 29a.ch[/url]
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

veers hat geschrieben:oder einfach from uuid import uuid4 ... :wink:
Ziemlich doofer Name! ;)

16fd2706-8baf-433b-82eb-8c7fada847da attacks and hits for 4 hit points!
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Hier mal für die Kommandozeile mit der zusätzlichen Verfeinerung, dass auf Systemen, die `/dev/urandom` anbieten, das Device nicht unnötig oft auf und zu gemacht wird.

Wenn man viel Wert auf die Vermeidung von Schlüsselworten bei der Namensgebung legt, kann man `bytes` natürlich auch umbenennen... *räusper*

Wer's konsistenter mag, hier mit einem `close()`, das sich konsequenterweise auch unter Windows beschwert.
Zuletzt geändert von snafu am Freitag 23. Oktober 2009, 14:40, insgesamt 1-mal geändert.
stuhlbein
User
Beiträge: 89
Registriert: Freitag 9. Januar 2009, 16:08

Ich versteh nicht inwiefern das manuelle öffnen von /dev/urandom besser als die nutzung von os.urandom() ist?
Letztenendes ist letzteres bereits plattform-unabhängig, und du öffnest das device nicht öfter oder weniger als os.urandom() es tut.
Im grunde erfindest du mit der Klasse das rad neu, statt ein bereits vorhandenes zu nutzen...
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Doch, das Device wird bei jedem Zugriff auf `os.urandom()` geöffnet, also bei jedem Durchlauf meiner while-Schleife. Mit dem Wrapper wird es einmal geöffnet, es wird in der while-Schleife gelesen und am Ende geschlossen. Auf Windows-Systemen wird weiterhin die Python-Implementierung genommen, die die Windows-Funktion CryptGenRandom aufruft, die augenscheinlich kein Datei-Objekt ist.
lunar

@snafu: Und welches tatsächlich existierende Problem wird dadurch nun gelöst? Was ist denn so schlimm daran, dass diese Datei jedes mal erneut geöffnet wird?

Wie dem auch sei, wenn schon, dann wenigstens mit korrekter Ausnahmebehandlung.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Zeitersparnis, dachte ich. Wie schon gesagt: Eigentlich ist das eher zu vernachlässigen und bläht den Code nur unnötig auf.

Wo mache ich keine korrekte Ausnahmebehandlung?
lunar

In "get_random_string()". ".close()" wird nicht aufgerufen, wenn eine Ausnahme ausgelöst wird.
Antworten