├── .gitattributes ├── Simple Calculator.py ├── README.md ├── LICENSE.txt ├── Simple Calculator Tutorial.md ├── .vscode └── launch.json ├── Advanced Calculator.py └── Advanced Calculator Tutorial.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /Simple Calculator.py: -------------------------------------------------------------------------------- 1 | """ Python Simple Calculator """ 2 | 3 | # Setting all values to 0 (empty, nothing) 4 | output = 0 5 | num1 = "" 6 | operation = "" 7 | num2 = "" 8 | 9 | # Asking What numbers you want using print command 10 | num1 = input("Hello, What is your First Number?\n") 11 | operation = input("Operation (+, -, *, /)?\n") 12 | num2 = input("Your Second Number?\n") 13 | 14 | # Setting asked numbers to float, so that it would give an exact answer 15 | floatnum1 = float(num1) 16 | floatnum2 = float(num2) 17 | 18 | # If selected operation is the following then do the following 19 | if operation == "+": 20 | output=floatnum1+floatnum2 21 | if operation == "-": 22 | output=floatnum1-floatnum2 23 | if operation == "*": 24 | output=floatnum1*floatnum2 25 | if operation == "/": 26 | output=floatnum1/floatnum2 27 | if operation == "+" or operation == "-" or operation == "/" or operation == "*": 28 | print("Your Answer: "+str(output)) 29 | 30 | # If none of above is the operation then give a error 31 | else: 32 | print("Your operation is invalid, please try again") 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SimplePythonTutorial 2 | Python Tutorial: Making a simple command line calculator. *_Assumes no knowledge of programming in python._* I originally made the code for a 6th grade (2013) Math project in which I would be teaching the class how to write code in Python. 3 | 4 | ## Simple Calculator 5 | 6 | * Supports the functions `+,-,*,/` 7 | 8 | [Tutorial](https://github.com/neilbalch/Python-Tutorial-Calculator/blob/master/Simple%20Calculator%20Tutorial.md) 9 | 10 | [Source](https://github.com/neilbalch/Python-Tutorial-Calculator/blob/master/Simple%20Calculator.py) 11 | 12 | ## Advanced Calculator 13 | 14 | * Supports the functions `+,-,*,/,^,sqrt,!,abs,sin,cos,tan,arcsin,arccos,arctan,log,log10,rand,randint` 15 | * Also has memory ability `M+,MR,M-` 16 | * Can recall constants `pi,e,tau` 17 | * Can convert `Degrees to Radians, Radians to Degrees` 18 | 19 | [Tutorial](https://github.com/neilbalch/Python-Tutorial-Calculator/blob/master/Advanced%20Calculator%20Tutorial.md) 20 | 21 | [Source](https://github.com/neilbalch/Python-Tutorial-Calculator/blob/master/Advanced%20Calculator.py) 22 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Neil 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Simple Calculator Tutorial.md: -------------------------------------------------------------------------------- 1 | # Simple Calculator 2 | 3 | ## Printing to the screen 4 | 5 | In python, printing to the command line can be done using the `print()` statement. The only required argument is a string to be printed. For example, in Python 3, `print("Hello World")` will print `Hello World` to the command line. 6 | 7 | ## Intro to Input 8 | 9 | In python, user input on the command line can be taken by using the command `input()`. Putting in a string (optional) as a paramter will give the user a prompt after which they can input text. This statement returns a string with the text the user typed, so it needs to be assigneed to a variable. This can be done in python like so, `myvar = input("Feed me data! ")`. Python is not a language with strongly typed variables, which means that you do not have to define a type when you create a variable. The interpreter will automatically assign the variable a type the first time it is instantiated with data. 10 | 11 | ## Getting input from the user for a calculation 12 | 13 | Querying input from the user for a calculation can be done like so, 14 | ```py 15 | num1 = input("Hello, What is your First Number?\n") 16 | operation = input("Operation?\n") 17 | num2 = input("Your Second Number?\n") 18 | ``` 19 | This code will print a prompt asking for a first number to the screen, ask for input, print a prompt asking for an operation to the screen, ask for input, etc. The `\n` at the end of the strings is an escape character that tells python to add a newline to the end of the prompt. I did this so that the user would start typing on the line below the prompt. (personal asthetic taste) 20 | 21 | ## Typecasting the inputs 22 | 23 | In order for us to do math on the numbers that the user typed, we need to convert them to numerical values, as you cannot do math on strings, for obvious reasons. (After all, what is "abc" / "def" anyways?) The method for doing so is called Typecasting. and in Python, you can convert to float (decimal numbers less than 7 digits) by using the float() statement. This can be done for our purposes like so, 24 | ```py 25 | floatnum1 = float(num1) 26 | floatnum2 = float(num2) 27 | ``` 28 | > NOTE: We are not sanitizing our inputs, and entering in a non-numerical value here will break the code, and sanitizing inputs is really important, but a topic for a later time. For now, we will just hope that no one comes across this code with malicious intentions. 29 | 30 | At this point, the code should look like this: 31 | ```py 32 | num1 = input("Hello, What is your First Number?\n") 33 | operation = input("Operation?\n") 34 | num2 = input("Your Second Number?\n") 35 | 36 | floatnum1 = float(num1) 37 | floatnum2 = float(num2) 38 | ``` 39 | 40 | ## Performing the math 41 | 42 | Now that we have the numbers converted to float types, we are ready to do the math. For simplicity's sake in this lesson, we will use `if()` statements to tell what the user wants to do. In this program, we will support four operations, +,-,* and /, so we will need to have 4 if statements. One if statement for this program will look like, 43 | ```py 44 | if operation == "+": 45 | output=floatnum1+floatnum2 46 | ``` 47 | This checks to see if the user wanted to add the two numbers, and if they did, it adds them together. 48 | > NOTE: Python is whitespace sensitive, so make sure you indent the second line with two spaces, or the if statement will not compile. 49 | 50 | > NOTE: This code also does not sanitize the input for the operation, and if the user did not enter +,-,*, or /, the program will break at the next step, when we print the answer to the screen. Again, for the same reason, we will just hope that no one comes across this code with malicious intentions. 51 | 52 | Repeat the following for the following three operations. 53 | 54 | 55 | At this point, the code should look like this: 56 | ```py 57 | num1 = input("Hello, What is your First Number?\n") 58 | operation = input("Operation?\n") 59 | num2 = input("Your Second Number?\n") 60 | 61 | floatnum1 = float(num1) 62 | floatnum2 = float(num2) 63 | 64 | if operation == "+": 65 | output=floatnum1+floatnum2 66 | if operation == "-": 67 | output=floatnum1-floatnum2 68 | if operation == "*": 69 | output=floatnum1*floatnum2 70 | if operation == "/": 71 | output=floatnum1/floatnum2 72 | 73 | ``` 74 | 75 | ## Printing the result 76 | 77 | Using the `print()` statement, we can print the result out to the screen. In Python, strings can be concatenated by "adding" them together, as if they were numbers. The code for this step looks like this: `print("Your Answer: "+str(output))`. This code prints the text "Your answer: " concatenated with the output, after it has been typecasted to a string. (You can't concatenate it while it is still formatted as a float) 78 | 79 | At this point, the code should look like this: 80 | ```py 81 | num1 = input("Hello, What is your First Number?\n") 82 | operation = input("Operation?\n") 83 | num2 = input("Your Second Number?\n") 84 | 85 | floatnum1 = float(num1) 86 | floatnum2 = float(num2) 87 | 88 | if operation == "+": 89 | output=floatnum1+floatnum2 90 | if operation == "-": 91 | output=floatnum1-floatnum2 92 | if operation == "*": 93 | output=floatnum1*floatnum2 94 | if operation == "/": 95 | output=floatnum1/floatnum2 96 | 97 | print("Your Answer: "+str(output)) 98 | ``` 99 | 100 | 101 | # Running the code 102 | 103 | Running the code is as simple as opening `IDLE`, the official Python editor for Windows, Mac and Linux, opening your code file, and pressing `F5` on your keyboard, or going to the `Run\Run Module` menu item at the top of the window (Windows), or the top of the screen (Mac) 104 | 105 | # Done! 106 | 107 | Amazing! You have made a simple command line based calculator! If you understood all of the code in this lesson, and you have gotten the code to compile, please continue onto the advanced tutorial. 108 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Python", 6 | "type": "python", 7 | "request": "launch", 8 | "stopOnEntry": true, 9 | "pythonPath": "${config:python.pythonPath}", 10 | "program": "${file}", 11 | "cwd": "${workspaceRoot}", 12 | "env": {}, 13 | "envFile": "${workspaceRoot}/.env", 14 | "debugOptions": [ 15 | "WaitOnAbnormalExit", 16 | "WaitOnNormalExit", 17 | "RedirectOutput" 18 | ] 19 | }, 20 | { 21 | "name": "PySpark", 22 | "type": "python", 23 | "request": "launch", 24 | "stopOnEntry": true, 25 | "osx": { 26 | "pythonPath": "${env:SPARK_HOME}/bin/spark-submit" 27 | }, 28 | "windows": { 29 | "pythonPath": "${env:SPARK_HOME}/bin/spark-submit.cmd" 30 | }, 31 | "linux": { 32 | "pythonPath": "${env:SPARK_HOME}/bin/spark-submit" 33 | }, 34 | "program": "${file}", 35 | "cwd": "${workspaceRoot}", 36 | "env": {}, 37 | "envFile": "${workspaceRoot}/.env", 38 | "debugOptions": [ 39 | "WaitOnAbnormalExit", 40 | "WaitOnNormalExit", 41 | "RedirectOutput" 42 | ] 43 | }, 44 | { 45 | "name": "Python Module", 46 | "type": "python", 47 | "request": "launch", 48 | "stopOnEntry": true, 49 | "pythonPath": "${config:python.pythonPath}", 50 | "module": "module.name", 51 | "cwd": "${workspaceRoot}", 52 | "env": {}, 53 | "envFile": "${workspaceRoot}/.env", 54 | "debugOptions": [ 55 | "WaitOnAbnormalExit", 56 | "WaitOnNormalExit", 57 | "RedirectOutput" 58 | ] 59 | }, 60 | { 61 | "name": "Integrated Terminal/Console", 62 | "type": "python", 63 | "request": "launch", 64 | "stopOnEntry": true, 65 | "pythonPath": "${config:python.pythonPath}", 66 | "program": "${file}", 67 | "cwd": "", 68 | "console": "integratedTerminal", 69 | "env": {}, 70 | "envFile": "${workspaceRoot}/.env", 71 | "debugOptions": [ 72 | "WaitOnAbnormalExit", 73 | "WaitOnNormalExit" 74 | ] 75 | }, 76 | { 77 | "name": "External Terminal/Console", 78 | "type": "python", 79 | "request": "launch", 80 | "stopOnEntry": true, 81 | "pythonPath": "${config:python.pythonPath}", 82 | "program": "${file}", 83 | "cwd": "", 84 | "console": "externalTerminal", 85 | "env": {}, 86 | "envFile": "${workspaceRoot}/.env", 87 | "debugOptions": [ 88 | "WaitOnAbnormalExit", 89 | "WaitOnNormalExit" 90 | ] 91 | }, 92 | { 93 | "name": "Django", 94 | "type": "python", 95 | "request": "launch", 96 | "stopOnEntry": true, 97 | "pythonPath": "${config:python.pythonPath}", 98 | "program": "${workspaceRoot}/manage.py", 99 | "cwd": "${workspaceRoot}", 100 | "args": [ 101 | "runserver", 102 | "--noreload", 103 | "--nothreading" 104 | ], 105 | "env": {}, 106 | "envFile": "${workspaceRoot}/.env", 107 | "debugOptions": [ 108 | "WaitOnAbnormalExit", 109 | "WaitOnNormalExit", 110 | "RedirectOutput", 111 | "DjangoDebugging" 112 | ] 113 | }, 114 | { 115 | "name": "Flask", 116 | "type": "python", 117 | "request": "launch", 118 | "stopOnEntry": false, 119 | "pythonPath": "${config:python.pythonPath}", 120 | "program": "fully qualified path fo 'flask' executable. Generally located along with python interpreter", 121 | "cwd": "${workspaceRoot}", 122 | "env": { 123 | "FLASK_APP": "${workspaceRoot}/quickstart/app.py" 124 | }, 125 | "args": [ 126 | "run", 127 | "--no-debugger", 128 | "--no-reload" 129 | ], 130 | "envFile": "${workspaceRoot}/.env", 131 | "debugOptions": [ 132 | "WaitOnAbnormalExit", 133 | "WaitOnNormalExit", 134 | "RedirectOutput" 135 | ] 136 | }, 137 | { 138 | "name": "Flask (old)", 139 | "type": "python", 140 | "request": "launch", 141 | "stopOnEntry": false, 142 | "pythonPath": "${config:python.pythonPath}", 143 | "program": "${workspaceRoot}/run.py", 144 | "cwd": "${workspaceRoot}", 145 | "args": [], 146 | "env": {}, 147 | "envFile": "${workspaceRoot}/.env", 148 | "debugOptions": [ 149 | "WaitOnAbnormalExit", 150 | "WaitOnNormalExit", 151 | "RedirectOutput" 152 | ] 153 | }, 154 | { 155 | "name": "Pyramid", 156 | "type": "python", 157 | "request": "launch", 158 | "stopOnEntry": true, 159 | "pythonPath": "${config:python.pythonPath}", 160 | "cwd": "${workspaceRoot}", 161 | "env": {}, 162 | "envFile": "${workspaceRoot}/.env", 163 | "args": [ 164 | "${workspaceRoot}/development.ini" 165 | ], 166 | "debugOptions": [ 167 | "WaitOnAbnormalExit", 168 | "WaitOnNormalExit", 169 | "RedirectOutput", 170 | "Pyramid" 171 | ] 172 | }, 173 | { 174 | "name": "Watson", 175 | "type": "python", 176 | "request": "launch", 177 | "stopOnEntry": true, 178 | "pythonPath": "${config:python.pythonPath}", 179 | "program": "${workspaceRoot}/console.py", 180 | "cwd": "${workspaceRoot}", 181 | "args": [ 182 | "dev", 183 | "runserver", 184 | "--noreload=True" 185 | ], 186 | "env": {}, 187 | "envFile": "${workspaceRoot}/.env", 188 | "debugOptions": [ 189 | "WaitOnAbnormalExit", 190 | "WaitOnNormalExit", 191 | "RedirectOutput" 192 | ] 193 | }, 194 | { 195 | "name": "Attach (Remote Debug)", 196 | "type": "python", 197 | "request": "attach", 198 | "localRoot": "${workspaceRoot}", 199 | "remoteRoot": "${workspaceRoot}", 200 | "port": 3000, 201 | "secret": "my_secret", 202 | "host": "localhost" 203 | } 204 | ] 205 | } -------------------------------------------------------------------------------- /Advanced Calculator.py: -------------------------------------------------------------------------------- 1 | # Import 'math' and 'random' Libraries 2 | import math 3 | import random 4 | # Define Variables 5 | output = 0 6 | num1 = "" 7 | operator = "" 8 | num2 = "" 9 | memStore = "Empty" 10 | 11 | # Define Function Listing Function 12 | def abilitiesList(): 13 | print("+...Addition") 14 | print("-...Subtraction") 15 | print("*...Multiplication") 16 | print("/...Division") 17 | print("^...Powers") 18 | print("/-...Square Roots ") 19 | print("!...Factorials (Input Cannot Be Negetave)") 20 | print("Abs...Absolute Value") 21 | print("d/r...Degrees To Radians") 22 | print("r/d...Radians To Degrees") 23 | print("pi...Returns PI") 24 | print("e...Returs 'e'") 25 | print("tau...Returns TAU (2xPI)") 26 | print("M+...Save input to memory") 27 | print("MR...Recall Memory") 28 | print("M-...Clear Memory") 29 | print("sin...Sine") 30 | print("cos...Cosine") 31 | print("tan...Tangent") 32 | print("asin...Arc Sine") 33 | print("acos...Arc Cosine") 34 | print("atan...Arc Tangent") 35 | print("log10...Log(10) of Input") 36 | print("log...Returns The Apropriate Log of the Input (input1 is the log power)") 37 | print("rand...Returns A Random Number Between 0 and 1") 38 | print("randint...Returns A Random Number Between The Two Inputs") 39 | print("//////////////////////////////////////////////////////////////////////////") 40 | 41 | def askForNumInput(textPrompt): 42 | # Devine local variable 43 | convertedNum = math.nan 44 | 45 | # Wait for valid numerical input 46 | while True: 47 | num = input(textPrompt) 48 | try: 49 | # Try to typecast the input to a float 50 | float(num) 51 | except ValueError: 52 | # Catch the exception if it is not a number 53 | print("ERROR: Syn: Invalid Num") 54 | else: 55 | # Typecasting 56 | convertedNum = float(num) 57 | break 58 | return convertedNum 59 | 60 | # While Loop 61 | while True: 62 | print("//////////////////////////////////////////////////////////////////////////") 63 | print("Type 'help' for a list of abilities") 64 | # Loop for getting operation 65 | while True: 66 | operator = input("What operation do you want to perform? ") 67 | # Is operator == to any of out constants or predefines? 68 | if operator == "help": 69 | abilitiesList() 70 | elif operator == "pi": 71 | print(math.pi) 72 | elif operator == "e": 73 | print(math.e) 74 | elif operator == "tau": 75 | print(math.pi*2) 76 | elif operator == "MR": 77 | print(str(memStore)) 78 | elif operator == "M-": 79 | memStore = "Empty" 80 | print("Memory Cleared") 81 | elif operator == "rand": 82 | print(random.random()) 83 | # Has the user entered in a valid operator? 84 | elif operator == "+" or operator == "-" or operator == "*" or operator == "/" or operator == "^" or operator == "/-" or operator == "!" or operator == "Abs" or operator == "d/r" or operator == "r/d" or operator == "M+" or operator == "M-" or operator == "MR" or operator == "sin" or operator == "cos" or operator == "tan" or operator == "asin" or operator == "acos" or operator == "atan" or operator == "log10" or operator == "log" or operator == "randint": 85 | break 86 | else: 87 | print("ERROR: Invalid Operator") 88 | 89 | # Loop for 1st number input 90 | while True: 91 | num1 = askForNumInput("First Number? ") 92 | # Catch asin and acos out of bounds error case 93 | if (operator == "asin" or operator == "acos") and (num1 > 1 or num1 < -1): 94 | print("ERROR: Math: 'asin' and 'acos' commands only accept inputs in range -1 to +1") 95 | elif operator == "!" and num1 < 0: 96 | print("ERROR: Math: Factorials only accept inputs > 0") 97 | else: 98 | break 99 | 100 | # Does the operation require a 2nd input? 101 | if not (operator=="/-" or operator=="!" or operator=="Abs" or operator=="d/r" or operator=="r/d" or operator=="M+" or operator=="sin" or operator=="cos" or operator=="tan" or operator=="asin" or operator=="acos" or operator=="atan" or operator=="log10"): 102 | # Loop for 2nd number input 103 | while True: 104 | num2 = askForNumInput("Second Number? ") 105 | # Catch x/0 error case 106 | if operator == "/" and num2 == "0": 107 | print("ERROR: Math: Canot divide by 0!") 108 | else: 109 | break 110 | 111 | # Calculations 112 | if operator == "+": 113 | output = num1 + num2 114 | print("Your Answer: "+str(output)) 115 | elif operator == "-": 116 | output = num1 - num2 117 | print("Your Answer: "+str(output)) 118 | elif operator == "*": 119 | output = num1 * num2 120 | print("Your Answer: "+str(output)) 121 | elif operator == "/": 122 | output = num1 / num2 123 | print("Your Answer: "+str(output)) 124 | elif operator == "^": 125 | output = math.pow(num1,num2) 126 | print("Your Answer: "+str(output)) 127 | elif operator == "/-": 128 | output = math.sqrt(num1) 129 | print("Your Answer: "+str(output)) 130 | elif operator == "!": 131 | output = math.factorial(num1) 132 | print("Your Answer: "+str(output)) 133 | elif operator == "Abs": 134 | output = math.fabs(num1) 135 | print("Your Answer: "+str(output)) 136 | elif operator == "d/r": 137 | output = math.radians(num1) 138 | print("Your Answer: "+str(output)) 139 | elif operator == "r/d": 140 | output = math.degrees(num1) 141 | print("Your Answer: "+str(output)) 142 | elif operator == "M+": 143 | memStore = num1 144 | print("Number Stored") 145 | elif operator == "sin": 146 | output = math.sin(num1) 147 | print("Your Answer: "+str(output)) 148 | elif operator == "cos": 149 | output = math.cos(num1) 150 | print("Your Answer: "+str(output)) 151 | elif operator == "tan": 152 | output = math.tan(num1) 153 | print("Your Answer: "+str(output)) 154 | elif operator == "asin": 155 | output = math.asin(num1) 156 | print("Your Answer: "+str(output)) 157 | elif operator == "acos": 158 | output = math.acos(num1) 159 | print("Your Answer: "+str(output)) 160 | elif operator == "atan": 161 | output = math.atan(num1) 162 | print("Your Answer: "+str(output)) 163 | elif operator == "log10": 164 | output = math.log10(num1) 165 | print("Your Answer: "+str(output)) 166 | elif operator == "log": 167 | output = math.log(num2, num1) 168 | print("Your Answer: "+str(output)) 169 | elif operator == "randint": 170 | output = random.randint(num1, num2) 171 | print("Your Answer: "+str(output)) 172 | -------------------------------------------------------------------------------- /Advanced Calculator Tutorial.md: -------------------------------------------------------------------------------- 1 | # Advanced Calculator 2 | 3 | I strongly reccomend you got through the tutorial for the [Simple Calculator](https://github.com/neilbalch/Python-Tutorial-Calculator/blob/master/Simple%20Calculator%20Tutorial.md) first, before you look at this, as it covers important important details of python such as whitespace and strongly typed variables. 4 | 5 | ## Goals 6 | 7 | * This calculator is more advanced in that it includes some operations that require only one numberical input, like log and square root, as well as recalling constants, like pi and such that do not require any numerical input whatsoever. The program we build will have to deal with this, without crashing or bein vumbersome to use. 8 | * The aim is to get this calculator to support the following functions: `+,-,*,/,/-,^,!,abs,sin,cos,tan,asin,acos,atan,log10,log,rand,randint,pi,e,tau,M+,M-,MR,degrees->radians,radians->degrees` 9 | * The simple calculator program ended once the operation was completed, something we also want to avoid with this calculator. 10 | * Since it has a long list of functions, we also want to be able to list out all of the things the calculator can do. 11 | * We want to sanitize our inputs so that we will not get screwed up by malicious or otherwiwe malformed inputs 12 | 13 | ## Sanitizing numerical inputs 14 | 15 | Because of its nature, we will not sanitize our operation input the same way as our numerical inputs; we have a list of operations that we support, and if the input doesn't match one on the list, we won't let them proceed, instead asking them to try again. Because we will be using the code for sanitizing numerical inputs multiple times, one for each of the two inputs, we will break it our into a function. Functions are used whenever code will be reused, as it speeds up bug detection and prevention as well as makes your code more readable to other people. (and you when you inevitably come back to your own code a few years later and have no idea what your code does anymore!) 16 | 17 | Basic functions can be declared like so, `def myFunction([parameters]):`. Our function for taking input will be called "askForNumInput". Note the camel casing in the name. 18 | 19 | > NOTE: Camel casing is the common practice of making the first letter of an object or function name lowercase and then making every subsequent first letter of a word uppercase, i.e. "askForNumInput" or "abilitiesList" 20 | 21 | As before in the Simple Calculator, we will still use the same basic method for taking input, but instead of a constant string for the prompt, we will replace that with a variable set as a parameter in the function. 22 | 23 | Inside this function, we will use a new statement, the `try` block. It serves the purpose of helping catch errors that would otherwise have caused the program to crash. It has three parts, `try`, `catch` and `else`. The `try` block contains the code you want to test run, the `catch` block takes a parameter, the error you are testing for and contains wat you want to do if the error ocurs, and the `else` block contains what you want to do if there is no error. 24 | 25 | As in the Simple Calculator, we will need to have the input typecasted to `float` for our math operations, and if you put in a non numerical value, the program will crash with a `ValueError: could not convert string to float`. We want to avoid that error, so with our try block, we will catch the error `ValueError`. If we catch the ValueError, we want to tell the user that their input was invalid, and if there was no error, we want to actually typecast the input. So, our finished function should look like this: 26 | 27 | ```py 28 | def askForNumInput(textPrompt): 29 | # Devine local variable 30 | convertedNum = math.nan 31 | 32 | # Wait for valid numerical input 33 | while True: 34 | num = input(textPrompt) 35 | try: 36 | # Try to typecast the input to a float 37 | float(num) 38 | except ValueError: 39 | # Catch the exception if it is not a number 40 | print("ERROR: Syn: Invalid Num") 41 | else: 42 | # Typecasting 43 | convertedNum = float(num) 44 | break 45 | return convertedNum 46 | ``` 47 | 48 | ## abilitiesList 49 | 50 | Because our program will support a miryad different operations, we want the user to be able to recall a list of the operations we support. For the sake of neatness in the main block of code, we will break this out into a function. This one will be simple, it takes no parameters, as it is just a function with a bunch of print statements. The code for this should look like so: 51 | 52 | ```py 53 | # Define Function Listing Function 54 | def abilitiesList(): 55 | print("+...Addition") 56 | print("-...Subtraction") 57 | print("*...Multiplication") 58 | print("/...Division") 59 | print("^...Powers") 60 | print("/-...Square Roots ") 61 | print("!...Factorials (Input Cannot Be Negetave)") 62 | print("Abs...Absolute Value") 63 | print("d/r...Degrees To Radians") 64 | print("r/d...Radians To Degrees") 65 | print("pi...Returns PI") 66 | print("e...Returs 'e'") 67 | print("tau...Returns TAU (2xPI)") 68 | print("M+...Save input to memory") 69 | print("MR...Recall Memory") 70 | print("M-...Clear Memory") 71 | print("sin...Sine") 72 | print("cos...Cosine") 73 | print("tan...Tangent") 74 | print("asin...Arc Sine") 75 | print("acos...Arc Cosine") 76 | print("atan...Arc Tangent") 77 | print("log10...Log(10) of Input") 78 | print("log...Returns The Apropriate Log of the Input (input1 is the log power)") 79 | print("rand...Returns A Random Number Between 0 and 1") 80 | print("randint...Returns A Random Number Between The Two Inputs") 81 | print("//////////////////////////////////////////////////////////////////////////") 82 | ``` 83 | 84 | ## The whole shebang 85 | 86 | Since we want this program to loop indefinetly, letting the user perform as many operations as they want before they clode the program, we will utilize an infinite loop. This can be done with a `while` loop configured as such: `while True:`. This line runs the code in the code within the loop for as long as `True` is equal to `True`, or more succinctly, while 1=1, which will always be correct, hence the name infinite loop. 87 | 88 | At the beginning of the loop, we want to let the user know that they can request a list of the operations we can perform. We will write the code to call `abilitiesList()` later. 89 | 90 | ```py 91 | print("//////////////////////////////////////////////////////////////////////////") 92 | print("Type 'help' for a list of abilities") 93 | ``` 94 | 95 | Next, we will have three loops to get the operation and numerical inputs for the calculations. They are loops because we want to loop until we have a valid input for each. 96 | 97 | ### Operation input 98 | 99 | For the operation input loop, we will first see if the input is one of the commands that doesn't require any numerical inputs, like i.e. recalling pi or storing a value in the calculator's "memory", and if it isn't, then we will check to see if it is one of the operations we support that requires numerical input, i.e. +,-,sqrt, etc. Because we support recalling numerical constants and generating randon numbers, we need to import the libraries that allow us to use those commands. At the top of the file, add the following lines: 100 | 101 | ```py 102 | # Import 'math' and 'random' Libraries 103 | import math 104 | import random 105 | ``` 106 | 107 | We will call the `abilitesList` function like so: `abilitiesList()`. The 'memory' for the calculator will be implimented using the variable `memStore` that the user can store a value into using `M+`, recall a value from using `MR` and delete the contents of using `M-`. The `memStore` variable will be defined at the top of the file so that its scope includes the entire file, following convention, below the `import` statements. If the user inputs an operation that requires numerical input(s), we will break from the loop using the command `break`, which breaks away from the current loopm in this case the `while True:`. The finished operation loop should look like this: 108 | 109 | ```py 110 | # Loop for getting operation 111 | while True: 112 | operator = input("What operation do you want to perform? ") 113 | # Is operator == to any of out constants or predefines? 114 | if operator == "help": 115 | abilitiesList() 116 | elif operator == "pi": 117 | print(math.pi) 118 | elif operator == "e": 119 | print(math.e) 120 | elif operator == "tau": 121 | print(math.pi*2) 122 | elif operator == "MR": 123 | print(str(memStore)) 124 | elif operator == "M-": 125 | memStore = "Empty" 126 | print("Memory Cleared") 127 | elif operator == "rand": 128 | print(random.random()) 129 | # Has the user entered in a valid operator? 130 | elif operator == "+" or operator == "-" or operator == "*" or operator == "/" or operator == "^" or operator == "/-" or operator == "!" or operator == "Abs" or operator == "d/r" or operator == "r/d" or operator == "M+" or operator == "M-" or operator == "MR" or operator == "sin" or operator == "cos" or operator == "tan" or operator == "asin" or operator == "acos" or operator == "atan" or operator == "log10" or operator == "log" or operator == "randint": 131 | break 132 | else: 133 | print("ERROR: Invalid Operator") 134 | ``` 135 | 136 | If the user inputs an operation that is one of the ones we can perform without taking input, we will print the corresponding answer, and loop back to asking for another operation. 137 | 138 | ### First numerical input 139 | 140 | Luckily, because we wrote the `askForNumInput(textPrompt)` function before, the code required to take input for the next two numerical inputs is a lot easier. We still need to have loops, because we still need to sanitize our inputs. Inside the loop, instead of calling the `input()` command ourselves, we will call `askForNumInput()`, which takes care of making sure the value is numerical for us, leaving us just to making sure the value is within the range of acceptable values for each operation. 141 | 142 | Luckily, the only operations that require this level of finesse are `asin`, `acos` and `!` (Factorial), as the first two functions provided by the `math` library only accept balues that are between 1 and -1, and factorial inputs have to be above 0. Since we need to check two conditions, that the requested operation is `asin` or `acos` AND that the values are within -1 and 1, we will use a compound condition. We could just make two nested if statements, jone for each of the conditions, but python allows us to make better and more concise code. The same can be done with the `!` test. 143 | 144 | Using the `and` keyword, we can combine the two conditions so that only if the first condition AND the second condition are both true we will proceed to tell the usr that there is an error. The `or` keyword works similarly, but instead of both conditions needing to be true for the entire compound condition to be true, only one needs to. Because we have four nested conditions here, between each of the sets, (around the `or`s) we need to have parentheses to tell the comiler what to evaluate first. (Very similar to how they work in PEMDAS for math!) Otherwise, if the values are kosher, we will break from the loop. The finished code for the first input should look like this: 145 | 146 | ```py 147 | # Loop for 1st number input 148 | while True: 149 | num1 = askForNumInput("First Number? ") 150 | # Catch asin and acos out of bounds error case 151 | if (operator == "asin" or operator == "acos") and (num1 > 1 or num1 < -1): 152 | print("ERROR: Math: 'asin' and 'acos' commands only accept inputs in range -1 to +1") 153 | elif operator == "!" and num1 < 0: 154 | print("ERROR: Math: Factorials only accept inputs > 0") 155 | else: 156 | break 157 | ``` 158 | 159 | ### Second numerical input 160 | 161 | The code for this input is extreemely simimar to the previous one. Just like the first input, we need to take input from the user using `askForumInput(textPrompt)` and check for if an error will surface with the given inputs. (this time for checking for divide by 0) But unlike the first input, where if you have gotten to to that point in the program, you automatically need a numerical input, some operations only require one numerical input, and not two, i.e. sqrt, factorial, abs, etc. So, instead of directly going to the loop, we need to check if the operation is one of the ones that only requires one numerical input. To do so, we will use another keyword, `not`. `not` inverts the boolean result from a condition, so for example, `not True` will never be true because the inverse of true is always false. Just like the condition for the first numerical input, parentheses are required around the condition to make sure that `not` modifies the correct part of the condition. The finished code for the second numerical input should look like this: 162 | 163 | ```py 164 | # Does the operation require a 2nd input? 165 | if not (operator=="/-" or operator=="!" or operator=="Abs" or operator=="d/r" or operator=="r/d" or operator=="M+" or operator=="sin" or operator=="cos" or operator=="tan" or operator=="asin" or operator=="acos" or operator=="atan" or operator=="log10"): 166 | # Loop for 2nd number input 167 | while True: 168 | num2 = askForNumInput("Second Number? ") 169 | # Catch x/0 error case 170 | if operator == "/" and num2 == "0": 171 | print("ERROR: Math: Canot divide by 0!") 172 | else: 173 | break 174 | ``` 175 | 176 | ### Da calculations 177 | 178 | Now that we have all of the input we need for the selected operation, we need to actually perform the operation and print the result ot the screen. In other languages, there is a control structure called a `switch` that evaluates the condition for each `case`, each of which has its own condition that will make the code within the case run if the case condition matches the value of the switch condition. But, unfortunately, python doesn't support the `switch`, so we will need to use `if` statements instead, a more tedious and slightly less elegant solution, but it still works, and that's what matters most. 179 | 180 | For each of the operations we listed in `abilitiesList()` that was not one that didn't need inputs, we will need to make a new `if` statements. For simple operations, i.e. +,-,* and /, this is as simple as copying the code from the Simple Calculator, (changing the input variable names to match, and making the `print` statements for the output of course!) but for the more complex operations, like sqrt, sin,cos,tan,etc., we will need to call on the `math` and `random` libraries for help. In general, the python docs link for the [math library](https://docs.python.org/3.5/library/math.html) and the [random library](https://docs.python.org/3.5/library/random.html) will help you out with finding out what function to call for each operation we need to support and which numerical input to put where. 181 | 182 | > NOTE: I strongly encourage you to puzzle through this yourself, as learning how to read library documentation is an extremely valueable resource for any programmer. 183 | 184 | For the command `M+`, you will need to store the numerical value the user inputed to the variable `memStore`. The finished code for this section should look like this: 185 | 186 | ```py 187 | # Calculations 188 | if operator == "+": 189 | output = num1 + num2 190 | print("Your Answer: "+str(output)) 191 | elif operator == "-": 192 | output = num1 - num2 193 | print("Your Answer: "+str(output)) 194 | elif operator == "*": 195 | output = num1 * num2 196 | print("Your Answer: "+str(output)) 197 | elif operator == "/": 198 | output = num1 / num2 199 | print("Your Answer: "+str(output)) 200 | elif operator == "^": 201 | output = math.pow(num1,num2) 202 | print("Your Answer: "+str(output)) 203 | elif operator == "/-": 204 | output = math.sqrt(num1) 205 | print("Your Answer: "+str(output)) 206 | elif operator == "!": 207 | output = math.factorial(num1) 208 | print("Your Answer: "+str(output)) 209 | elif operator == "Abs": 210 | output = math.fabs(num1) 211 | print("Your Answer: "+str(output)) 212 | elif operator == "d/r": 213 | output = math.radians(num1) 214 | print("Your Answer: "+str(output)) 215 | elif operator == "r/d": 216 | output = math.degrees(num1) 217 | print("Your Answer: "+str(output)) 218 | elif operator == "M+": 219 | memStore = num1 220 | print("Number Stored") 221 | elif operator == "sin": 222 | output = math.sin(num1) 223 | print("Your Answer: "+str(output)) 224 | elif operator == "cos": 225 | output = math.cos(num1) 226 | print("Your Answer: "+str(output)) 227 | elif operator == "tan": 228 | output = math.tan(num1) 229 | print("Your Answer: "+str(output)) 230 | elif operator == "asin": 231 | output = math.asin(num1) 232 | print("Your Answer: "+str(output)) 233 | elif operator == "acos": 234 | output = math.acos(num1) 235 | print("Your Answer: "+str(output)) 236 | elif operator == "atan": 237 | output = math.atan(num1) 238 | print("Your Answer: "+str(output)) 239 | elif operator == "log10": 240 | output = math.log10(num1) 241 | print("Your Answer: "+str(output)) 242 | elif operator == "log": 243 | output = math.log(num2, num1) 244 | print("Your Answer: "+str(output)) 245 | elif operator == "randint": 246 | output = random.randint(num1, num2) 247 | print("Your Answer: "+str(output)) 248 | ``` 249 | 250 | # Voila! 251 | 252 | Congratulations, you are done! Feel good about yourself if you understood this tutorial, but if you didn't, please let me know, and or read it through again and do research on your questions online. I look forward to seeing you all on the interwebs as full on programmers! 253 | --------------------------------------------------------------------------------