was ist in python eigentlich besser ?

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.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Was sollte man eigentlich machen, wenn man mehrer Datentypen direckt nutzen möchte.
Ich spiele darauf an sowohl eine Dictionary, List, Tuple und Objekte zu nutzen in einer Funktion.
Also zB.:

Code: Alles auswählen

def func(data):
    data.name
    data["name"]
    data[0]

class data(object):
     name = "hw"

instanz = data()

func(instanz)
func(dict(name="hw"))
func(["hw",])
func(("hw",))
Natürlich geht das jetzt nicht, aber sollte man die Fälle mit try...except...
Abfangen, oder auf typ prüfen(was ich eher als unschön empfände) oder gibt es andere Möglichkeiten.

Nur nebenbei, bin gerade dabei meine "älteren"(auch neuere) Scripte mal aufzuräumen, funktionieren tut alles nur der Stil lässt zum Teil echt zu Wünschen übrig. Deswegen die ganzen Fragen, damit sich endlich mal eine einheitliche Strucktur durch zieht.
Denn das ist bei den meisten Tutorials unmöglich und zum Teil richtig Falsch. Und in der Python Documentation stehen solche Fälle selten ausführlich Beschrieben drin.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

ich habe das bisher zwar nur sehr wenig gebraucht, aber bisher so gelöst:
Da muss es doch auch was besseres geben ?!

Code: Alles auswählen

def func(data):
    try:
        data.name
    except AttributeError:
         try:
             data[0]
         except (TypeError, IndexError, KeyError):
             try:
                 data["name"]
             except:
                 raise Warning
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
BlackJack

@Xynon1: Ich würde sagen man sollte nicht so eine API haben, bei der `data` so viele verschiedene "Dinge" sein kann.
lunar

DasIch hat geschrieben:4. In keiner Sprache ist == True/False eine gute Idee.
Das stimmt im Übrigen auch nicht, sondern hängt von der Sprache ab. Das nur als Anmerkung.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

mh, was haltet ihr von follgendem:

Code: Alles auswählen

class Data:
    def __init__(self):
         self.name = ""
    #...
    def __iter__(self):
        yield self.name
        #yield attr2

# statt
def func(data):
    try:
        data.name
    except AttributeError:
         try:
             data[0]
         except (TypeError, IndexError, KeyError):
             try:
                 data["name"]
             except:
                 raise Warning

#diese hier:

def func(data):
    try:
        [name for name in data.values()]
    except AttributeError:
        [name for name in data]
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

BlackJacks Einwand bleibt da immernoch bestehen (allerdings zur Intention nicht direkt am Code) und die Funktionen tun nun wirklich nichts aequivalentes.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Wieso nicht ?

Mir geht es ja nicht um eine explizite Typ-Prüfung, sondern nur um den Zugriff auf die Liste, Tuple, Dict und das Objekt.
So das ich an die Daten komme, sicher BlackJack hat schon ganz recht sowas sollte man sehr selten oder gar nicht anbieten.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
BlackJack

@Xynon1: Kannst Du nicht einfach mehrere Funktionen für die verschiedenen Typen anbieten? Die können sich ja letztendlich alle auf eine stützen, welche die tatsächliche Arbeit verrichtet.

Du machst zwar keine explizite Typ-Prüfung, aber Du probierst verschiedene APIs nacheinander aus -- das sollte man IMHO auch nur in Ausnahmefällen machen, weil's doch sehr magisch und implizit ist.

Kannst Du den Daten-Objekten nicht schon vorher eine gleiche API verpassen, notfalls mit einem Wrapper-Objekt?
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Mehrere Funktionen für sowas finde ich eigentlich nicht sehr schön, das erinnert dann eher an typsichere Sprachen.
BlackJack hat geschrieben:weil's doch sehr magisch und implizit ist.
Ich weiß :mrgreen:

Nein, ist ok ich ändere ich den input voher und die Funktion kann dann halt nur noch Tuple und Listen akzeptiert.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
BlackJack

@Xynon1: Also ich halte Python für typsicher. Typsicher und statisch typisiert sind IMHO zwei verschiedene Dinge. C zum Beispiel würde ich nicht als 100% typsicher ansehen, obwohl es statisch typisiert ist.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Xynon1 hat geschrieben:@numerix und @DasIch 8.
Ähm bitte mit begründen, sonst hat der Thread wohl keinen sinn
Wenn du einen Test machst wird 2 mal versucht den Schlüssel im dict zu finden, wenn du den KeyError abfängst nur einmal.
@DasIch 7.
Detallierter bitte :(
Wenn du *args verwendest kannst du zu einem späteren Zeitpunkt die Signatur nicht mehr verändern, bei **kwargs kannst du keine keyword Argumente mehr hinzufügen. Vorrausgesetzt du willst rückwärtskompatibel bleiben.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Ok, leuchtet ein.

Kann man bei "unveränderbaren" *args zB in einem Konstrucktor dann ohne Bedenken eingesetzt werden ?
Denn wenn ich mir mal einige Python-Module aus der Standardlib ansehe, sind nutzen eigentlich nicht allzu wenige diese Möglichkeiten, aber werde sie demnächst nach möglichkeit vermeiden.

Noch ein Beispiel:

Code: Alles auswählen

list_ = [1,2,3,4]

#besser dies 
",".join([str(value) for value in list_])

#oder das
",".join(map(str, list_))
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wenn du die "Stern-Variante" vermeiden willst, könntest du das Problem einigermaßen mit einer Hilfsfunktion umgehen:

Code: Alles auswählen

In [1]: def args2list(args):
   ...:     try:
   ...:         if not isinstance(args, basestring):
   ...:             return list(args)
   ...:     except TypeError:
   ...:         pass
   ...:     return [args]
   ...: 

In [2]: args2list(23)
Out[2]: [23]

In [3]: args2list('bla')
Out[3]: ['bla']

In [4]: args2list(['bla', 'blupp'])
Out[4]: ['bla', 'blupp']

In [5]: args2list(xrange(3))
Out[5]: [0, 1, 2]

In [6]: def test(args):
   ...:     for arg in args2list(args):
   ...:         print arg
[...]
Hierbei wird alles außer Zeichenketten durch den `list()`-Konstruktor gejagt. Iterierbare Objekte gehen durch die Umwandlung und werden zurückgegeben. Falls die Umwandlung fehlt schlägt (z.B. bei Zahlen) oder wenn es sich um eine Zeichenkette handelt, wird eine einelementrige Liste mit dem `arg` zurückgegeben. Dies führt dazu, dass man später grundsätzlich über den Rückgabewert iterieren kann, also in etwa das hat, was beim Stern rausgekommen wäre. Der Vorteil: Wenn man als Benutzer nur ein Argument mitgeben will, muss man keine Liste erstellen, da dies später implizit von der Funktion gemacht wird.
Xynon1 hat geschrieben:Kann man bei "unveränderbaren" *args zB in einem Konstrucktor dann ohne Bedenken eingesetzt werden ?
Denn wenn ich mir mal einige Python-Module aus der Standardlib ansehe, sind nutzen eigentlich nicht allzu wenige diese Möglichkeiten, aber werde sie demnächst nach möglichkeit vermeiden.
Diese Bedenken sind ja eher theoretischer Natur. Es könnte halt als sauberer angesehen werden, weil `*` und `**` bei der Verwendung weiterer Argumente in der Signatur blöde Nebeneffekte haben. Wenn du einfach nur einen Wrapper machst, der die Argumente quasi ungesehen weitergibt, dann finde ich Sterne nicht so tragisch.
lunar

@DasIch: Einen Schlüssel in einem Wörterbuch zu finden, ist nicht aufwendig und geschieht in konstanter Zeit. Demgegenüber ist das Abfangen von Ausnahmen wesentlich teurer als ein Funktionsaufruf. Folglich ist – wie Numerix festgestellt hat – die Variante mit dem Test schneller, sobald Ausnahmen mit einer bestimmten Häufigkeit ausgelöst werden.

Unabhängig davon ist das eine Frage der Intention. Ausnahmen bezeichnen einen „Ausnahmezustand“, und sollten demnach nur zur Behandlung solcher Zustände eingesetzt werden. Möchte man dagegen verschiedene Dinge tun, je nach dem ob der Schlüssel enthalten ist oder nicht, also eine Entscheidung treffen, so ist die Abfrage die natürlichere und idiomatischere Variante.

Das zweifache Nachschlagen des Schlüssels lässt sich mit ".get()" vermeiden.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Xynon1 hat geschrieben:Mit anderen Worten ich hätte 5 - 10 Threads öffnen sollen deswegen ? :shock:
Ja, für neue Themen sollte man auch neue "Themenstränge" machen. Der Themenstrang sollte dabei nicht "Ich bin Anfänger und stelle diverse Fragen zu Python" lauten.

Bedenke immer, dass in 4 Monaten jemand auf den Thread stoßen könnte, weil er ein entsprechendes Suchwort eingegeben hat. Derjenige hat dann wenig Lust, immer Beiträge zu ganz anderen Themen in den Antworten zu haben, nur weil du als Fragesteller zu faul warst, neue Threads aufzumachen. Will man es von der "wissenschaftlichen" Seite betrachten, dann sind solche Foren ja ein Fundus von einer Art ungeordneten Buchkapiteln. Der Leser interessiert sich meist für das Thema des Kapitels und nicht so sehr für den Autor. ;)
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

@snafu
Es ging mir Haupsächlich um Stilistische fragen (zumindest am anfang, jetzt hat sich es leider etwas ausgedehnt) und das würde ich einer Gruppe zuordnen und nicht zehn verschieden.

@lunar
Ok, am besten mach ich an den stellen wo ich mir nicht sicher bin mal ein paar geschwindigkeits test bzw. pass es der Sachlage an.
Im Prizip also so wie ich es bisher gemacht habe.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

IMHO hast du Lunar nicht verstanden. Er sprach im Wesentlichen davon, dass eine Ausnahme auch wirklich als ein seltener Fall angesehen werden sollte. Hinzu kommt, dass Exception-Handling relativ teuer ist. Dementsprechend solltest du eben nicht das beibehalten, was du bisher gezeigt hast.

Zur Vermeidung doppelter Lookups wurde ja schon `dict.get()` genannt, welches standardmäßig `None` bei einem nicht-existenten Schlüssel zurückliefert anstatt eine Ausnahme zu werfen. Für Objektattribute gibt es analog dazu `getattr(obj, attrname, None)`.

Es kommt aber sicher auf den Einzelfall an, ob man nach Versuch-und-Irrtum vorgeht oder explizit auf Bedingungen testet.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Das meinte ich doch mit [...pass es der Sachlage an.]

Die ganzen try...excepts.. habe ich bisher nur einmal benutzt un nirgendwo sonst.
Diese Sachen am Anfang waren sachen die mir mir ständig wieder begegnet sind und wissen wollte ob es dazu etwas allgemein gültiges gibt.

und ja .get() hört sich gut an, aber bei den kleinen dicts die ich bisher hatte wäre eine doppelte prüfung mit "in" sowieso nicht aufgefallen in der Zeit.

So damit ihr mir nochmal sagen könnt das ich falsch liege fasse ich das mir hier nochmal zusammen. :mrgreen:

- try...except... kostet Zeit
- sind aber Prinzipiell in Python erwünscht
- sollten aber nicht bei zu häufigen auftreten der Exceptions nicht genutz werden, wenn man eine andere Möglichkeit hat

- "in" statement um zuprüfen ob sich ein key in einer dict befindet nur dann Sinnvoll wenn man den Wert hinter dem Key nicht benötigt
- da man sonst zweimal auf die dict zugreifen muss
- also .get() nutzen

so ungefähr ?
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Xynon1 hat geschrieben:- "in" statement um zuprüfen ob sich ein key in einer dict befindet nur dann Sinnvoll wenn man den Wert hinter dem Key nicht benötigt
- da man sonst zweimal auf die dict zugreifen muss
- also .get() nutzen
Würde ich so nicht sagen. Sondern:
- get() lässt sich nicht immer einsetzen. Soll beispielsweise nur dann ein Wert ausgegeben werden, wenn es dazu einen Schlüssel im dict gibt, hilft get() nicht weiter.
- get() ist elegant und ich nutze es auch gerne; aber schneller als ein zweifacher Zugriff auf das dict ist es leider nicht.
- evtl. wäre hier noch defaultdict zu nennen; damit geht manches noch eleganter, aber nicht schneller (eher im Gegenteil).

Zusammenfassung: Muss es wirklich schnell gehen, dann ist die Prüfung mit "in" und das anschließende Abrufen oder Zuweisen des Wertes selbst bei ziemlich großen dicts in der Regel die beste Lösung.
Kommt es nicht so sehr auf die Performance an, sind get() und defaultdict auf jeden Fall eine Überlegung wert.
Antworten