'''
What do you like about the various quantify_parens()?
What do you dislike about the various quantify_parens()?
What do you like about the various parens_are_balanced()?
What do you dislike about the various parens_are_balanced()?
What do you think about the last sum_ = 0 for doing nothing gracefully?
'''

from __future__ import print_function 
import operator

def quantify_parens(s):
    return [{'(': +1, ')': -1}[c] if c in {'(': +1, ')': -1} else 0 for c in s]

def quantify_parens(s):
    weights = {'(': +1, ')': -1}
    return [weights[c] if c in weights else 0 for c in s]

def quantify_parens(s):
    weights = {'(': +1, ')': -1}
    for c in s:
        try:
            weight = weights[c]
        except KeyError:
            weight = 0
        yield weight

def quantify_parens(s):
    weights = {'(': +1, ')': -1}
    for c in s:
        try:
            weight = weights[c]
        except KeyError:
            pass
        else:
            yield weight

def quantify_parens(s):
    weights = {'(': +1, ')': -1}
    for c in s:
        if c in weights:
            yield weights[c]

def parens_are_balanced(s):
    sum_ = 0
    for x in quantify_parens(s):
        sum_ += x
        if sum_ < 0:
            return False
    return sum_ == 0

def running_op(iterable, op=operator.add, initial=0):
    running_result = initial
    for element in iterable:
        running_result = op(running_result, element)
        yield running_result

def running_sum(iterable, initial=0):
    sum_ = initial
    for element in iterable:
        sum_ += element
        yield sum_

def parens_are_balanced(s):
    n = n_unmatched_left_parentheses = 0
    for n in running_sum(quantify_parens(s)):
        if n < 0:
            return False
    return n == 0

def main():
    strings = [
        '',
        'hello world',
        '(',
        ')',
        '()',
        '((())',
        '((()))',
        '(a((b)))',
        '((())))',
        'hello(a(b())))world',
        '(a(b(c)d)e)',
    ]

    for s in strings:
        print(
            repr(s),
            list(quantify_parens(s)),
            sum(quantify_parens(s)),
            parens_are_balanced(s))

    print(list(running_op(range(1, 5), operator.mul, 1)))

main()
