Fehler: Attribute Error

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
supersonic72
User
Beiträge: 17
Registriert: Freitag 15. September 2006, 15:45

Habe ein Problem mit der .index Funktion. Bei folgendem Code

Der code:

Code: Alles auswählen

            for p in power_p:
                for inkr in inkrements:
                    if k==0 and excel_mean_column==0 and excel_column_2==0:
                        begin_est=clock()
                    # Index von p und inkr in der Liste
                    print "p= "+str(p)
                    print "p in power_p="+str(p in power_p)
                    p_index=power_p.index(p)
                    inkr_index=inkrements.index(inkr)

Bekomme ich immer die Fehlermeldung:
p_index=power_p.index(p)
AttributeError: index
Wenn ich es auf dem Weg löse:

Code: Alles auswählen

                    for i in range(0,len(power_p)):
                        if p == power_p[i]:
                            p_ind=i
Funktionierts aber. Wieso geht der erste Weg nicht?
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

Was ist power_p?

'power_p' besitzt die Methode 'index' anscheinend nicht, daher der Attribut Error.


MFG EnTeQuAk
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Bau mal ein print type(power_p) ein.
supersonic72
User
Beiträge: 17
Registriert: Freitag 15. September 2006, 15:45

Danke schonmal für die schnelle Hilfe.

Code: Alles auswählen

power_p = arange(0.1,10.1,0.1)
Die Funktion type gibt

Code: Alles auswählen

 
<type 'array'>

aus.[/code]
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

Hallo!


Woher kommt die Funktion arange? In der Python Dokumentation konnte ich keine derartige Funktion finden. (nicht mal 'arrange', was besser passen würde.

Was gibt denn

Code: Alles auswählen

print dir(power_p)
aus?
Zuletzt geändert von EnTeQuAk am Freitag 6. Juli 2007, 10:35, insgesamt 1-mal geändert.
supersonic72
User
Beiträge: 17
Registriert: Freitag 15. September 2006, 15:45

Code: Alles auswählen

from Numeric import arange
power_p hat in etwa die Form

Code: Alles auswählen

power_p=[0.1,0.2,...,9.8,9.9,10.0]
Spricht eine alternative zu range, die mir auch steps ausgibt, die keine integer sind.


Das war die einzige, die ich gefunden habe. Mit range geht das ja nicht.
supersonic72
User
Beiträge: 17
Registriert: Freitag 15. September 2006, 15:45

Habe jetzt eine Lösung gefunden:

arange erstellt anscheinend arrays, auf die man index nicht anwenden kann. Über den Tip mit dir(power_p) habe ich den Befehl

Code: Alles auswählen

power_p.tolist()
gefunden, der mir aus dem Array eine Liste macht, auf den ich dann index loslassen kann.

Danke für die Tipps!
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

Das ist schön.

@all:
Warum kann 'range' eigentlich nur ganze Integerwerte verwenden?

Dabei währe doch so was, wie

Code: Alles auswählen

>>> def new_range(start=0, stop=None, step=1):
...     stop = stop or start
...     i = 0
...     rv = []
...     while i < stop:
...             rv.append(i)
...             i += step
...     return rv
viel schöner, oder?

Es gann jedenfalls mit jeden Zahlen umgehen.

MfG EnTeQuAk
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Es kann doch mit allen ganzen Zahlen umgehen:

Code: Alles auswählen

>>> range(-5, 0)
[-5, -4, -3, -2, -1]
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
supersonic72
User
Beiträge: 17
Registriert: Freitag 15. September 2006, 15:45

Ja, das ist ja auch wunderbar, aber was ist wenn man nicht Stepsize 1 sondern 0.1 haben will?

Wie gesagt, so in der Art

Code: Alles auswählen

range(0,1,0.1)=[0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9]
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Ich würde mir so helfen:

Code: Alles auswählen

>>> [ float(i)/10 for i in range(10) ]
[0.0, 0.10000000000000001, 0.20000000000000001, 0.29999999999999999, 0.40000000000000002, 0.5, 0.599
99999999999998, 0.69999999999999996, 0.80000000000000004, 0.90000000000000002]
(ja, sieht komisch aus... Das liegt aber daran das floats immer so abgespeichert werden)

Code: Alles auswählen

>>> r_list = [ float(i)/10 for i in range(10) ]
>>> r_list[1] == 0.1
True
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

supersonic72 hat geschrieben:Ja, das ist ja auch wunderbar, aber was ist wenn man nicht Stepsize 1 sondern 0.1 haben will?

Wie gesagt, so in der Art

Code: Alles auswählen

range(0,1,0.1)=[0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9]
Weil das mit Floats nicht so einfach funktioniert. Wenn du wiederholt Floats addierst, wird das Ergebnis immer ungenauer.

Insofern ist Zaps Lösung die, die man sinnvollerweise hernimmt.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
supersonic72
User
Beiträge: 17
Registriert: Freitag 15. September 2006, 15:45

Klar, über eine Schleife kann ich mir das auch basteln. Über eine Schleife kann ich mir auch den Befehl "range" basteln. Mich würde nur interessieren, ob es dafür auch eine buildin Funktion gibt.
BlackJack

Ich wollte nur noch mal anmerken, das man sich mit Fliesskommazahlen Probleme einhandelt, die mit der Genauigkeit zu tun haben. Suchen mit ``in`` macht zum Beispiel immer einen *genauen* Vergleich, man sollte Fliesskommazahlen aber nicht auf ``==`` testen, sondern immer einen kleinen Fehler mit einkalkulieren. Sonst kann es passieren, dass scheinbar gleiche Ergebnisse nicht gleich sind.

Code: Alles auswählen

In [17]: 0.3 == 3 * 0.1
Out[17]: False
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

supersonic72 hat geschrieben:Klar, über eine Schleife kann ich mir das auch basteln. Über eine Schleife kann ich mir auch den Befehl "range" basteln. Mich würde nur interessieren, ob es dafür auch eine buildin Funktion gibt.
Ich frage mich was dich an der lösung genau stört? Ist sie dir zu langsam?
Bezweifle das es eine Build-in Lösung dafür gibt und empfinde das
Iterieren über float-Werte als ziemlichen Sonderfall.
BlackJack hat geschrieben:man sollte Fliesskommazahlen aber nicht auf ``==`` testen, sondern immer einen kleinen Fehler mit einkalkulieren. Sonst kann es passieren, dass scheinbar gleiche Ergebnisse nicht gleich sind.
Ich wusste das da was war, was ich vergessen hatte :)
supersonic72
User
Beiträge: 17
Registriert: Freitag 15. September 2006, 15:45

Ich frage mich was dich an der lösung genau stört? Ist sie dir zu langsam?
Bezweifle das es eine Build-in Lösung dafür gibt und empfinde das
Iterieren über float-Werte als ziemlichen Sonderfall.
Ich iteriere über die float Werte, da ich sie später in verschiedene Funktionen ausgeben lasse. Es ist praktisch meine x-Koordinate, wenn man so will. klar könnte ich an jeder Stelle, wo ich p verwende, durch 10 teilen, da ich aber auch eine eingabe wie [0.01,0.02,...] zulassen muss, wird das meiner Meinung nach sehr unbersichtlich.
Ja, hatte aus Geschwindigkeitsgründen auf eine Build-in Lösung gehofft.
Führe mit dem Programm Analysen von großen Datenmengen durch, die im Schnitt 10 Stunden laufen, da macht sich jedes bisschen bemerkbar. Aber mit der .tolist() Variante habe ich mir ja abhilfe geschafft.

Wenn ich die float-Werte miteinander vergleichen will wie

Code: Alles auswählen

0.3==3*0.1
verwende ich inzwischen

Code: Alles auswählen

from decimal import Decimal
Damit habe das Problem behoben. Das existiert ja aber auch nur, wenn ich die Zahlen multipliziere, wenn ich nur die Werte direkt aus der Liste abfrage macht das keine Probleme.
BlackJack

Wenn Dir das zu unübersichtlich wird, dann stecke es in eine Funktion.

Ich verstehe Deinen Beispielquelltext übrigens nicht so ganz. Zu testen ob ein Element, das man aus einem Container hat, in diesem Container enthalten ist, ist ziemlich witzlos. Natürlich ist `p` in `power_p` enthalten.

Und wenn es Dir auf Laufzeit ankommt, möchtest Du ganz sicher weder ``in`` noch `index()` verwenden. Beides sucht linear vom Anfang der Liste nach dem Wert, wird also mit jedem Schleifendurchlauf langsamer und langsamer. Den Index kann man auch gleich in der äusseren Schleife mitzählen:

Code: Alles auswählen

    for p_index, p in enumerate(power_p):
        # ...
Falls `power_p` sehr viele Werte enthält, könnte man auch eine Generatorfunktion oder ein Sequenz-Objekt dafür schreiben um Speicherplatz zu sparen.

`arange()` schützt nicht vor dem Problem mit dem multiplizieren:

Code: Alles auswählen

In [27]: a = numpy.arange(0, 0.5, 0.1)

In [28]: a
Out[28]: array([ 0. ,  0.1,  0.2,  0.3,  0.4])

In [29]: 0.3 in a
Out[29]: False
supersonic72
User
Beiträge: 17
Registriert: Freitag 15. September 2006, 15:45

Wenn Dir das zu unübersichtlich wird, dann stecke es in eine Funktion.
Ich bin mir immer unsicher, was mehr Zeit verbraucht, wenn ich die Funktionen auslager oder sie direkt in das Programm schreibe.
Und wenn es Dir auf Laufzeit ankommt, möchtest Du ganz sicher weder ``in`` noch `index()` verwenden. Beides sucht linear vom Anfang der Liste nach dem Wert, wird also mit jedem Schleifendurchlauf langsamer und langsamer. Den Index kann man auch gleich in der äusseren Schleife mitzählen:
Danke für den Tip. Die Enumerate Funktion ist genau das, was ich gesucht habe. Wusste nicht, wie ich das jeweils mitzählen konnte. Werde das gleich mal einarbeiten und schauen, ob es Zeit spart.
Falls `power_p` sehr viele Werte enthält, könnte man auch eine Generatorfunktion oder ein Sequenz-Objekt dafür schreiben um Speicherplatz zu sparen.
Was versteht man unter einer Generator-Funktion oder einem Sequenzobjekt? power_p enthält im Schnitt 100 Werte.
`arange()` schützt nicht vor dem Problem mit dem multiplizieren:
Ich weiß, dafür verwende ich Decimal, und das funktioniert.

Danke nochmal für die vielen hilfreichen Anregungen.
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Ein Generator ist quasi eine On-Demand-Sequenz, die nur Werte ausgibt, wenn sie angefordert werden. Das kann eine einfache Funktion sein:

Code: Alles auswählen

def generate_range(stop):
    i = 0
    while i < stop:
        yield i
        i += 1
Anstelle von `return` wird das `yield`-Statement verwendet, das zwar einen Wert liefert, die Funktion danach aber weiterlaufen lässt.

Anwendung:

Code: Alles auswählen

numbers = generate_range(10)
for number in numbers:
    print number
Im Gegensatz zu normalen Sequenzen wie Tupeln oder Listen hat ein Generator aber keine Länge, da die Werte nur schrittweise ausgegeben werden; um sie zu erhalten (d.h. `len()` darauf anwenden zu können), muss man den Generator erst mit `tuple()` oder `list()` in eine Sequenz umwandeln.

Interna: Bei jedem Schleifendurchlauf wird die Methode `next()` des Generators aufgerufen; wirft sie eine `StopIteration`(?)-Exception, wird die Schleife verlassen.

Einer der Vorteile eines Generators besteht nun darin, dass seine Ausgabe schrittweise und nicht auf einmal erzeugt wird. Werden die Daten direkt weiter verarbeitet, müssen sie gar nicht erst in einer Liste zwischengespeichert werden. Je nach Umfang der Daten kann das einen großen Unterschied im Speicherverbrauch darstellen.
Antworten