Interpret English as Math and Perform Operations
How should I be naming variables? Operation and numInString good names?
  


Great question, Python has an extensive but approachable style guide call PEP8. Specifically local variables should be lowercase, Global Constants should be UPPERCASE, and Global variables should be avoided.


  
  Should I print the result of a function operator?
  


In order to use it later you should return the value:

Instead of: print(multAns) do return multAns


  
  Should I be storing the numbers in a global list, numInString, instead of passing them to operator functions?
  


No, pass the numbers to the operator and save the returned result

result = oper(a=1, b=3)


instead of 

a = 1
b = 3
oper()



  
  Should I print errors like this?:

print('NO OPERATION GIVEN')

  


No, raise errors when you come to this sort of situation.

ValueError("Cannot match an operator to \"{}\"".format(inputstring))



  
  Is it ok to assume all numbers will be int?
  


It would be better to handle the case of decimal number, especially if you want to be able to do true division (which was in your code)

My revision with plenty of comments, incorporating my above suggestions

import re
from decimal import Decimal


Dictionary mapping search words to operator function

operations = {
    '&lt;a&gt; (times|multiplied by) &lt;b&gt;':
        lambda a, b: a * b,
    '&lt;a&gt; divided by &lt;b&gt;':
        lambda a, b: a / b,
    '(add|sum)? &lt;a&gt; (and|plus) &lt;b&gt;':
        lambda a, b: a + b,
    'subtract &lt;a&gt; and &lt;b&gt;':
        lambda a, b: a - b,
    '&lt;a&gt; (minus|take) &lt;b&gt;':
        lambda a, b: a - b,
    '&lt;a&gt; squared':
        lambda a: a**2,
    '&lt;a&gt; cubed':
        lambda a: a**3,
    '&lt;a&gt; raised to the power &lt;b&gt;':
        lambda a, b: a**b,
    }


think of lambda as "make_function"

def plus(a, b):
    return a + b

is the same as

plus = lambda a, b: a + b


also you can use the actual operator:
    eg. * instead of operator.mul
        + instead of add

Match any number eg. 8, 8.8, -3.14 https://stackoverflow.com/questions/15814592/how-do-i-include-negative-decimal-numbers-in-this-regular-expression this is defined as a Global Constant

NUM_RE = "-?\d+(\.\d+)?"


Match that number and give it a name that can be
access later via m.groupdict()

def named_number_regex(name):
    return "(?P&lt;{name}&gt;{num})".format(name=name, num=NUM_RE)

variable_names = ['a', 'b']
for name in variable_names:
    # replace all of the name placeholders with
    # the actual regex for matching a named number
    #     eg. "&lt;a&gt;" ---&gt; "(?P&lt;a&gt;-?\d+(\.\d+)?)"
    # placeholder were used just to make the above patterns easier to read
    old = '&lt;{}&gt;'.format(name)
    new = named_number_regex(name)
    operations = {k.replace(old, new): v for k, v in operations.items()}

# allow for varying amount of whitespace
operations = {'\s*' + k.replace(' ', '\s*'): v for k, v in operations.items()}


Now the patterns look like this:

#
# \s*(?P&lt;a&gt;-?\d+(\.\d+)?)\s*squared
#
# let's break it down:
#
# \s*                                 ignore leading whitespace
#    (?P&lt;a&gt;-?\d+(\.\d+)?)             match any number, name it 'a'
#                        \s*          ignore other whitespace
#                           squared   only match if you find " squared"


Function to take a string and and recursively simplify it until we either get a number or encounter an error.

def simplify(inputstring):
    print(inputstring) # see what is going on internally

    # if you get down to a single number return its value
    if re.fullmatch(NUM_RE, inputstring) is not None:
        return Decimal(inputstring)

    for matcher, oper in operations.items():
        # iterate over all key: value pairs in the dict "operations" eg:
        #    matcher = '(?P&lt;a&gt;\d+) (times|multiplied by) (?P&lt;b&gt;\d+)'
        #    oper = lambda a, b: operator.mul(a, b)
        m = re.match(matcher, inputstring)
        if m is None:
            continue

        # dict of named matches eg {'a': '4', 'b': '8'}
        numbers = m.groupdict()

        # convert text eg. '4' strings into integers eg. 4
        # this is like your [int(d) for d in re.findall(r'-?\d+', inputs)]
        # Decimal handles ints and floats, with floating point rounding errors
        numbers = {k:Decimal(v) for k, v in numbers.items()}

        # now numbers = {'a': 4, 'b': 8}

        # get the result of the matched operation
        # Note: ** means call function with keyword args from a dict
        #     eg. oper(a=4, b=8)
        result = oper(**numbers)

        # substitute the result of oper with the matched string
        # Note we can lose precision here when casting Decimal to str
        simplified = re.sub(matcher, str(result), inputstring)

        # now simplify it further if possible
        # this is call recursion, it will continue to simplify until we get down to just a number
        print('= ', sep='', end='')
        return simplify(simplified)

    raise ValueError("Cannot match an operator to \"{}\"".format(inputstring))


Test Cases

def test_a_few_cases():
    print("\nSimple Addition:")
    result = simplify("4 plus 8")

    print("\nDemonstrate the recursion:")
    result = simplify("2 squared squared squared squared")

    print("\nMore elaborate:")
    result2 = simplify("2 plus 1.11 times -7 raised to the power 6")

    print("\nDemonstrate an Error:")
    result = simplify("2 squared squared squared squard")

def main():
    print("\nYour input:")
    yourresult = simplify(input("&gt;").lower())

if __name__ == '__main__':
    test_a_few_cases()
    main()