Checking for balanced brackets in Python I'm solving HackerRank "Stacks: Balanced Brackets" in Python.


  A bracket is considered to be any one of the following characters: (,
  ), {, }, [, or ].
  
  Two brackets are considered to be a matched pair if the an opening
  bracket (i.e., (, [, or {) occurs to the left of a closing bracket
  (i.e., ), ], or }) of the exact same type. There are three types of
  matched pairs of brackets: [], {}, and ().
  
  A matching pair of brackets is not balanced if the set of brackets it
  encloses are not matched. For example, {[(])} is not balanced because
  the contents in between { and } are not balanced. The pair of square
  brackets encloses a single, unbalanced opening bracket, (, and the
  pair of parentheses encloses a single, unbalanced closing square
  bracket, ].
  
  By this logic, we say a sequence of brackets is considered to be
  balanced if the following conditions are met:
  
  It contains no unmatched brackets. The subset of brackets enclosed
  within the confines of a matched pair of brackets is also a matched
  pair of brackets. Given  strings of brackets, determine whether each
  sequence of brackets is balanced. If a string is balanced, print YES
  on a new line; otherwise, print NO on a new line.


My code:

def is_matched(expression):
    if len(expression) % 2 != 0:
        return False

    opening = ("(", "[", "{")
    closing = (")", "]", "}")
    mapping = {opening[0]:closing[0],
               opening[1]:closing[1],
               opening[2]:closing[2]}

    if expression[0] in closing:
        return False

    if expression[-1] in opening:
        return False

    closing_queue = []
    for letter in expression:
        if letter in opening:
            closing_queue.append(mapping[letter])
        elif letter in closing:
            if not closing_queue:
                return False

            if closing_queue[-1] == letter:
                closing_queue.pop()
            else:
                return False

    return True

t = int(input().strip())
for a0 in range(t):
    expression = input().strip()
    if is_matched(expression) == True:
        print("YES")
    else:
        print("NO")


What could be improved here? What can be done to make my code more idiomatic (pythonic code)?

Is my implementation bad? Why is it?
Review

Your implementation is quite good, but ofcourse there are always some things that can be improved upon.


Use a if __name__ == '__main__' guard, see what they do.
opening closing and mapping could be done a bit simpler


You may use list over the values, to create a list, 
And you may zip those in a dictionary with the zip keyword.

If you need to add alot of corner cases, your algorithm is likely off somewhere else.
Consider adding Testcases, Docstrings, or both in the form of Doctest. To make it easier to Test your algorithm.


Alternative code

def is_matched(expression):
    """
    Finds out how balanced an expression is.
    With a string containing only brackets.

    &gt;&gt;&gt; is_matched('[]()()(((([])))')
    False
    &gt;&gt;&gt; is_matched('[](){{{[]}}}')
    True
    """
    opening = tuple('({[')
    closing = tuple(')}]')
    mapping = dict(zip(opening, closing))
    queue = []

    for letter in expression:
        if letter in opening:
            queue.append(mapping[letter])
        elif letter in closing:
            if not queue or letter != queue.pop():
                return False
    return not queue

if __name__ == '__main__':
    import doctest
    doctest.testmod()