‘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.