Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make string parsing in Python less unwieldy?

Apologies if the question title is too vague - would welcome edits.

I'm trying to parse XML using BeautifulSoup, but because each function call could return None, I have to parse a single element over a number of lines. This gets unwieldy very quickly:

books_count = result.books_count

if not books_count:
    return None

books_count = books_count.string

if not books_count:
    return None

books_count = int(books_count)

if not books_count:
    return None

Doing the same thing in Swift, a language I'm far more familiar with, it's a lot cleaner:

guard let booksCountString = result.booksCount?.string,
    let booksCountInt = Int(booksCountString) else {
    return nil
}

Is there a similar way I could do this in Python? I want to avoid using try/catch as causing it to potentially have a runtime error constantly in my code doesn't feel like good practice.

like image 918
Andrew Avatar asked May 12 '18 09:05

Andrew


People also ask

How do you parse a string in Python?

Use str. Call str. split(sep) to parse the string str by the delimeter sep into a list of strings. Call str. split(sep, maxsplit) and state the maxsplit parameter to specify the maximum number of splits to perform.

How do you convert a string to a real number in Python?

To convert, or cast, a string to an integer in Python, you use the int() built-in function. The function takes in as a parameter the initial string you want to convert, and returns the integer equivalent of the value you passed. The general syntax looks something like this: int("str") .


1 Answers

If you represent your sequence of None checks using lambdas, like so:

check_1 = lambda r: r.books_count
check_2 = lambda r: r.string
check_3 = lambda r: int(r)

Then we can generalize a solution for any number of those checks. This function is similar (in a way) to how functools.reduce works:

def my_reduce(fs, arg, stop_value=None):
    res = arg
    for f in fs:
        res = f(res)
        if res == stop_value:
            return stop_value
    return res

Then use it like this:

my_reduce([check_1, check_2, check_3], good_value)
Out[1]: 42

my_reduce([check_1, check_2, check_3], bad_value) is None
Out[2]: True
like image 112
MadeOfAir Avatar answered Oct 17 '22 02:10

MadeOfAir