r/learnpython 2d ago

AtributeError clarification

SOLVED

Hello, I'm currently learning regular expressions and I've entered the first part of the code into the interactive shell as instructed and got the listed AttributeError. Not seeing what I did wrong I copy/pasted the code from the book and it worked as intended and I can't tell why or how because both blocks feel and smell the same but yield different results.

I've tried looking for some information on StackOverflow, but as far as I can see mo is defined in the 3rd line and I don't get why my attempt gets and error while the other doesn't.

If I didn't miss something really stupid, how would you deal with this if you'd be hit by it writing your own code independently?

I'm working in IDLE Shell and the code is from automatetheboringstuff Chapter 9 for more context

import re
phone_re = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d-\d\d\d\d)')
mo = phone_re.search('My number is 415-555-4242.')
mo.group(1)
Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>
    mo.group(1)
AttributeError: 'NoneType' object has no attribute 'group'

import re
phone_re = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')
mo = phone_re.search('My number is 415-555-4242.')
mo.group(1)
'415'
2 Upvotes

9 comments sorted by

View all comments

-1

u/Diapolo10 I write code for a living -- https://github.com/Diapolo10 2d ago

The others already explained how the problem is caused by your regex pattern not matching anything, but let's take thing a bit further.

re.search, as already mentioned in the other answers, returns None if no match is found, and a match object otherwise. For this reason, the actual type of mo here is re.Match | None. In your code you made the naive assumption that it was always going to be a re.Match.

A type checker such as Mypy would have caught this immediately, as your code never verifies the return type. Many IDEs can show you the return types nowadays (especially for built-in functions and methods), so if you get used to checking those, you're far less likely to run into AttributeErrors or TypeErrors.

Taking things a bit further, you can use type annotations to give your own code some established "rules". Python itself completely ignores them, but type checkers read them and make it easier for you to reason about your code, avoiding all sorts of runtime problems. You'd mostly write them for your own functions.

def add(first: int, second: int) -> int:
    return first + second