‘str’ object has no attribute ‘digits’
On silly ways you can puzzle yourself – part 412
Summary
How to make Python report that a string object has no attribute ‘digits’
Confusing Yourself – the easy way
Today I was working on a little piece of code which I hadn’t originally written and which looked something like this :
import string def foo(string): for c in string: if c in string.digits: #do something
As is well known the Python string module contains a number of useful constants one of which is string.digits
>>> import string >>> print string.digits 0123456789
Missing ‘digits’
My problem was that every time I went to execute this code it got to the reference to string.digits and the Python intepreter would report
AttributeError: 'str' object has no attribute 'digits'
I spent a happy half hour looking backwards and forwards trying to understand why the String module might think it had no attribute ‘digits’ when everything indicated quite clearly it did until I realised what the problem was.
def foo(string):
That argument name ‘string’ had carefully chucked away my previous reference to the String module and as a string has no attribute ‘digits’ the intpreter was quite reasonably complaining !
My defense
In my defense I wouldn’t normally use variable names, like ‘string’, that come quite that close to commonly used modules but then like I say I didn’t write the original function
… but what I should have done
But then again what I should have done a great deal sooner than I did was to add a couple of lines to the function so that it read :
import string import pprint def foo(string): for c in string: pprint.pprint(dir(string)) if c in string.digits: #do something
which would have output something like this
['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_formatter_field_name_split', '_formatter_parser', 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
… and made it pretty clear that things were not as I thought they were.