Seite 1 von 1
AttributeError: 'str' object has no attribute 'uppper'
Verfasst: Sonntag 27. Januar 2013, 18:02
von hypnoticum
Hallo,
die obige Fehlermeldung bekomme ich, wenn ich folgendes Script ausführe:
Code: Alles auswählen
def checkHex(hexStr):
boolResult = True
for chr in hexStr:
if not (48 <= ord(chr) and ord(chr) <= 57) or (65 <= ord(chr.uppper()) and ord(chr.upper()) <= 70):
boolResult = False
return boolResult
checkHex("10")
kann mir bitte jemand sagen was daran falsch ist? Danke.
Re: AttributeError: 'str' object has no attribute 'uppper'
Verfasst: Sonntag 27. Januar 2013, 18:10
von derdon
upper schreibt man mit 2 p, nicht mit 3. Außerdem überschreibst du die eingebaute Funktion chr, womit du auf die Nase fallen könntest. Die Fehlermeldung kommt aber vom falsch geschriebenen upper. Es ist übrigens unnötig, in jedem Fall die komplette Schleife zu durchlaufen. Wenn du False zurückgeben willst, dann tu das sofort.
Re: AttributeError: 'str' object has no attribute 'uppper'
Verfasst: Sonntag 27. Januar 2013, 18:33
von cofi
Code: Alles auswählen
any(not (48 <= ord(c) <= 57) and not (65 <= ord(c.upper()) <= 70) for c in hex_string)
Vielleicht reicht ja aber auch schon `int(hex_string, 16)` fuer dein Vorhaben.
Ich glaube sogar, zu testen ob der Buchstabe im entsprechenden String enthalten ist, macht es lesbarer:
Code: Alles auswählen
any(c not in [chr(i) for i in range(48, 58) + range(65, 71)] for c in hex_string)
Re: AttributeError: 'str' object has no attribute 'uppper'
Verfasst: Sonntag 27. Januar 2013, 18:49
von Sirius3
Code: Alles auswählen
def checkHex(hexStr):
for c in hexStr.upper():
if not ('0'<=c<='9' or 'A'<=c<='F'):
return False
return True
Code: Alles auswählen
def checkHex(hexStr):
return all(c in '0123456789ABCDEF' for c in hexStr.upper())
Code: Alles auswählen
import re
def checkHex(hexStr):
return re.search('[^0-9A-F]',hexStr,re.I) is None
Und der Geschwindigkeitssieger:
Code: Alles auswählen
import re
CHECK_HEX = re.compile('[^0-9A-Fa-f]').search
def checkHex(hexStr):
return CHECK_HEX(hexStr) is None
Re: AttributeError: 'str' object has no attribute 'uppper'
Verfasst: Sonntag 27. Januar 2013, 18:58
von karolus
Hallo
Code: Alles auswählen
>>> from string import hexdigits
>>> hexset = set(hexdigits)
>>> set('abc0').issubset(hexset)
Karolus
Re: AttributeError: 'str' object has no attribute 'uppper'
Verfasst: Sonntag 27. Januar 2013, 19:05
von pillmuncher
@hypnoticum: Was derdon gesagt hat.
Außerdem könnte man dein Programm pythonischer machen.
Variablen sollte man nicht so benennen, dass sie builtins überschreiben. Außerdem gibt es Operator Chaining. Und die Klammern um die Ausdrücke rechts und links vom
or sind auch überflüssig:
Code: Alles auswählen
def checkHex(hexStr):
boolResult = True
for c in hexStr:
if not (48 <= ord(c) <= 57 or 65 <= ord(c.upper()) <= 70):
boolResult = False
return boolResult
Schon besser. Allerdings gibt es die Funktion
all(), mittels derer man
boolResult loswerden kann:
Code: Alles auswählen
def checkHex(hexStr):
return all(48 <= ord(c) <= 57 or 65 <= ord(c.upper()) <= 70 for c in hexStr)
Als nächstes fällt auf, dass die Aufrufe von
ord() und
c.upper() teuer sind und durch eine - zudem besser lesbare - Konstruktion ersetzt werden können, unter Zuhilfenahme des string-Moduls:
Code: Alles auswählen
from string import hexdigits
def checkHex(hexStr):
return all(c in hexdigits for c in hexStr)
Wenn wir statt eines Strings eine Buchstabenmenge verwenden, können wir jetzt die
all()-Konstruktion loswerden, weil Mengen schon eine entsprechende Methode mitbringen:
Code: Alles auswählen
from string import hexdigits
def checkHex(hexStr):
return set(hexdigits).issuperset(hexStr)
Wenn wir das genau ansehen, stellen wir fest, dass
checkHex() dieselbe Signatur besitzt, wie
set(hex_chars).issuperset(), nämlich
str --> bool. Also können wir
checkHex auch einfach direkt mittels Zuweisung definieren:
Code: Alles auswählen
from string import hexdigits
checkHex = set(hexdigits).issuperset
Diesen Programmierstil nennt man
point-free, oder auch
tacit.
Jetzt müssen wir nun noch den Namen unserer Funktion PEP8-konform machen:
Code: Alles auswählen
from string import hexdigits
is_hex_string = set(hexdigits).issuperset
Das Ergebnis ist deklarativer, kürzer, expliziter und besser lesbar, und vielleicht sogar performanter, was ich allerdings nicht getestet habe.
Re: AttributeError: 'str' object has no attribute 'uppper'
Verfasst: Sonntag 27. Januar 2013, 19:51
von lunar
@pillmuncher Python ist nicht Haskell, und point-free ist kein sonderlich gute Idee. Eine derartige Namensbindung ist nicht equivalent zu einer Funktionsdefinition, da die Metadaten der Funktion nicht stimmen, insbesondere ihr Docstring. "help(is_hex_string)" ist bei Deiner Definition mehr verwirrend als hilfreich.
Re: AttributeError: 'str' object has no attribute 'uppper'
Verfasst: Sonntag 27. Januar 2013, 20:53
von pillmuncher
@lunar: Dasselbe Argument könntest du auch gegen jede Verwendung von
functools.partial() anführen. Hier das
Beispiel aus der Doku:
Code: Alles auswählen
>>> from functools import partial
>>> basetwo = partial(int, base=2)
>>> basetwo.__doc__ = 'Convert base 2 string to an int.' # <-- !!!!!!!!!!!!!!!
>>> basetwo('10010')
18
>>> basetwo.__doc__
'Convert base 2 string to an int.'
>>> help(basetwo)
Help on partial object:
class partial(builtins.object)
| partial(func, *args, **keywords) - new function with partial application
| of the given arguments and keywords.
|
| Methods defined here:
|
| __call__(...)
| x.__call__(...) <==> x(...)
| ...
Ich halte point-free style für pythonisch, denn wenn point-free style von den
powers that be als nicht pythonisch angesehen würde, hätten sie
functools.partial() sicherlich nicht in die std-lib aufgenommen.
Außerdem hängt es letztlich von der Aufgabenstellung ab. Wenn die Aufgabe lautet "schreib eine Funktion, die genau
das macht", dann ist meine Implementation völlig korekt. Wenn die Aufgabe dagegen lautet "schreib eine Funktion, die genau
das macht und zusätzlich einen doc string hat, der ihre Funktionsweise in den Begriffen von Strings und Hexadezimalzahlen beschreibt", dann ist eine point-free Implementation in Python fehlerhaft. Wenn
functools.partial() so funktionieren würde, wie in der Dokumentation angedeutet, dann könnte man es etwa so machen:
Code: Alles auswählen
from string import hexdigits
from functools import partial
is_hex_string = partial(set(hexdigits).issuperset)
is_hex_string.__name__ = 'is_hex_string'
is_hex_string.__doc__ = 'Ein Prädikat, das angibt, ob der übergebene String ein gültiger Hexadezimalstring ist.'
Aber das funktioniert eben nicht richtig.
Re: AttributeError: 'str' object has no attribute 'uppper'
Verfasst: Sonntag 27. Januar 2013, 20:58
von hypnoticum
Ich danke euch für die Beantwortung meiner Frage.
Was ein Tippfehler so alles zu Tage bringt - hätte ich nicht gedacht, dass soviele Leute hier Vorschläge zu diesem Thema machen. Und ich kann wirklich was davon lernen

Re: AttributeError: 'str' object has no attribute 'uppper'
Verfasst: Montag 28. Januar 2013, 00:02
von sma
Code: Alles auswählen
import re
def check_hex(hs):
return bool(re.match('[0-9a-f]+$', hs, re.I))
Stefan
Re: AttributeError: 'str' object has no attribute 'uppper'
Verfasst: Montag 28. Januar 2013, 09:34
von lunar
@pillmuncher ".partial()" erzeugt ein neues, unabhängiges Objekt, und ist damit nahezu äquivalent zu einer richtigen Funktionsdefinition. Das ist der entscheidende Unterschied zu Deiner vorherigen Definition.
Re: AttributeError: 'str' object has no attribute 'uppper'
Verfasst: Montag 28. Januar 2013, 16:25
von Leonidas
Ich sehe da, wie pillmuncher auch, keinen Konflikt. Sowohl bei ``partial`` als auch bei Referenzen auf Funktionen stimmt der Docstring nicht und wenn man einmal ``partial`` um die Referenz wrappt wird das IMHO nicht "pythonischer" nur weils jetzt ein separates Objekt ist.
Re: AttributeError: 'str' object has no attribute 'uppper'
Verfasst: Montag 28. Januar 2013, 16:54
von pillmuncher
Man kann sich
partial() natürlich auch selber definieren:
Code: Alles auswählen
from string import hexdigits
def partial(f, *a0, **k0):
def curried(*a1, **k1):
k0.update(k1)
return f(*(a0 + a1), **k0)
return curried
is_hex_string = partial(set(hexdigits).issuperset)
is_hex_string.__doc__ = 'Ein Prädikat, das angibt, ob der übergebene String ein gültiger Hexadezimalstring ist.'
is_hex_string.__name__ = 'is_hex_string'
Dann geht es halbwegs:
Code: Alles auswählen
>>> from is_hex import is_hex_string
>>> is_hex_string('44af')
True
>>> help(is_hex_string)
Help on function is_hex_string in module is_hex:
is_hex_string(*a1, **k1)
Ein Prädikat, das angibt, ob der übergebene String ein gültiger Hexadezimalstring ist.
(END)
Nur die Parameterliste ist irreführend.