{"course":{"slug":"python-for-ai","title":"Python, from Zero, for AI","url":"https://addaly.com/learn/python-for-ai","level":"beginner","track":"build"},"lesson":{"slug":"strings-and-input","title":"Strings, and why input() always hands you text","url":"https://addaly.com/learn/python-for-ai/strings-and-input","position":6,"of":89,"minutes":6,"answer":"input() always returns text, so convert it the moment it arrives or you will compare numbers alphabetically.","keyIdea":"input() always returns text, so convert it the moment it arrives or you will compare numbers alphabetically."},"body":{"format":"markdown","text":"## Text is a sequence of characters\n\nA string is text in quotes. Single or double quotes, your choice, as long as they match:\n\n```python\ncity = \"Kano\"\ncountry = 'Nigeria'\nprint(city + \", \" + country)   # Kano, Nigeria\nprint(len(city))               # 4\nprint(city.upper())            # KANO\nprint(city[0])                 # K\n```\n\n`len` counts characters. `.upper()` is a thing strings know how to do to themselves; the dot means \"ask this value to do that\". `city[0]` picks the first character, because Python counts positions from zero. That zero will matter again in the next lesson.\n\nA few more that earn their keep:\n\n```python\nline = \"  78, 81, 90  \"\nprint(line.strip())              # \"78, 81, 90\"\nprint(line.strip().split(\", \"))  # ['78', '81', '90']\nprint(\"marks\" in \"exam marks\")   # True\n```\n\n## f-strings, for building sentences\n\nJoining with `+` gets ugly fast. Put an `f` before the quote and put values in curly braces:\n\n```python\nname = \"Amara\"\nmarks = 81\nprint(f\"{name} scored {marks} out of 100\")\nprint(f\"Half of that is {marks / 2}\")\n```\n\nThe braces are worked out as the line runs. Anything inside them can be arithmetic, not just a name.\n\n## input() asks the person running the program\n\n```python\nname = input(\"Your name: \")\nprint(f\"Hello, {name}\")\n```\n\nRun it and the program pauses, shows the prompt, and waits for you to type and press Enter. Whatever you typed becomes the value of `name`.\n\n## The rule that causes the most beginner bugs\n\n`input()` always gives you a string. Always. Even when the person typed digits.\n\n```python\nage = input(\"Your age: \")\nprint(type(age))     # <class 'str'>\nprint(age + 1)\n```\n\n```\nTypeError: can only concatenate str (not \"int\") to str\n```\n\nThe person typed `20` and you got `\"20\"`. Python cannot know that you wanted a number rather than a house number or a bus route. So you say it:\n\n```python\nage = int(input(\"Your age: \"))\nprint(f\"Next year you will be {age + 1}\")\n```\n\nRead that from the inside out: `input(...)` runs first and gives text, then `int(...)` turns that text into a number, then the name `age` is attached to the number.\n\n## The quieter version of the same bug\n\nThe crash above is the friendly case. Here is the unfriendly one:\n\n```python\nbudget = input(\"Monthly budget in pesos: \")   # you type 1200\nif budget > \"900\":\n    print(\"above\")\nelse:\n    print(\"below\")\n```\n\nThis prints `below`, and never complains. Both sides are text, so Python compared them the way a dictionary or a phone book does: character by character, left to right. `\"1\"` comes before `\"9\"`, so `\"1200\"` sorts before `\"900\"` and the comparison is decided at the very first character. Length never enters into it.\n\n> Figure: input() handed you text: what each comparison then answers. A two by two grid, rows Compared as text and Compared as numbers, columns '9' against '10' and '100' against '99': Compared as text and '9' against '10': True; Compared as text and '100' against '99': True; Compared as numbers and '9' against '10': False; Compared as numbers and '100' against '99': False. Text comparison is not broken. It compares character by character, left to right, the way a phone book does, so '1' sorts before '9' whatever the numbers mean. The program never complains, which is what makes it worse than a crash. Convert at the edge: age = int(input(...)).\n\nText comparison is not broken. It is answering a different question from the one you meant. The fix is to convert before you compare:\n\n```python\nbudget = int(input(\"Monthly budget in pesos: \"))\nif budget > 900:\n    print(\"above\")\n```\n\nA program that crashes tells you where it went wrong. A program that silently answers the wrong question does not. Convert at the edge, the moment data arrives, and the rest of your code can stop worrying.\n\n## Try this now\n\n```python\nitem = input(\"What did you buy? \")\nprice = float(input(\"Price? \"))\nqty = int(input(\"How many? \"))\nprint(f\"{qty} x {item} = {price * qty:.2f}\")\n```\n\nThe `:.2f` rounds to two decimal places. Then type `abc` when it asks for the price and read the error."},"check":{"question":"A program does `budget = input(\"Budget: \")` and then `if budget > \"900\":`. The user types 1200 and the program prints the else branch. What is the real explanation?","options":[{"text":"Python compared the two as text, character by character, and `\"1\"` sorts before `\"9\"`, so the answer was decided at the first character.","correct":true},{"text":"Python compared the lengths: `\"900\"` has three characters and `\"1200\"` has four, and it treats the shorter string as the greater one.","correct":false,"tempting":"Length is the most visible difference between the two strings, and it does affect comparison when the earlier characters happen to match."},{"text":"`input()` returned the number 1200, and Python converted the text `\"900\"` into a number badly, producing zero.","correct":false,"tempting":"Several popular languages really do convert across types during a comparison, so assuming Python does the same is a reasonable transfer of experience."},{"text":"`input()` kept the Enter key at the end, so the value was 1200 followed by a newline, and any string ending in a newline compares as smaller.","correct":false,"tempting":"You really did press Enter, and it is plausible that the keystroke ends up inside the value, which would explain an invisible difference."}]},"prev":{"slug":"numbers-and-arithmetic","title":"Numbers: whole, decimal, and the one that surprises everybody","url":"https://addaly.com/learn/python-for-ai/numbers-and-arithmetic"},"next":{"slug":"formatting-output","title":"Building the output a person will read","url":"https://addaly.com/learn/python-for-ai/formatting-output"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'Strings, and why input() always hands you text', in Python, from Zero, for AI. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/python-for-ai/strings-and-input (Accessed: 31 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"Strings, and why input() always hands you text","courseTitle":"Python, from Zero, for AI","module":{"index":1,"slug":"getting-python-running","title":"Getting Python running, and your first working code"},"answer":null,"keyIdea":"input() always returns text, so convert it the moment it arrives or you will compare numbers alphabetically.","hero":{"kind":"figure","figure":{"t":"figure","label":"Figure","figure":{"cols":["’9’ against ’10’","’100’ against ’99’"],"rows":["Compared as text","Compared as numbers"],"type":"matrix","cells":[["True","True"],["False","False"]],"title":"input() handed you text: what each comparison then answers","caption":"Text comparison is not broken. It compares character by character, left to right, the way a phone book does, so ’1’ sorts before ’9’ whatever the numbers mean. The program never complains, which is what makes it worse than a crash. Convert at the edge: age = int(input(...)).","cellLabels":[["'9' > '10'","'100' < '99'"],["9 > 10","100 < 99"]]},"alt":"Figure: input() handed you text: what each comparison then answers. A two by two grid, rows Compared as text and Compared as numbers, columns ’9’ against ’10’ and ’100’ against ’99’: Compared as text and ’9’ against ’10’: True; Compared as text and ’100’ against ’99’: True; Compared as numbers and ’9’ against ’10’: False; Compared as numbers and ’100’ against ’99’: False. Text comparison is not broken. It compares character by character, left to right, the way a phone book does, so ’1’ sorts before ’9’ whatever the numbers mean. The program never complains, which is what makes it worse than a crash. Convert at the edge: age = int(input(...))."}},"blocks":[{"t":"h2","id":"text-is-a-sequence-of-characters","runs":[{"text":"Text is a sequence of characters"}]},{"t":"p","runs":[{"text":"A string is text in quotes. Single or double quotes, your choice, as long as they match:"}]},{"t":"code","lang":"python","label":"Python","text":"city = \"Kano\"\ncountry = 'Nigeria'\nprint(city + \", \" + country)   # Kano, Nigeria\nprint(len(city))               # 4\nprint(city.upper())            # KANO\nprint(city[0])                 # K"},{"t":"p","runs":[{"text":"len","code":true},{"text":" counts characters. "},{"text":".upper()","code":true},{"text":" is a thing strings know how to do to themselves; the dot means “ask this value to do that”. "},{"text":"city[0]","code":true},{"text":" picks the first character, because Python counts positions from zero. That zero will matter again in the next lesson."}]},{"t":"p","runs":[{"text":"A few more that earn their keep:"}]},{"t":"code","lang":"python","label":"Python","text":"line = \"  78, 81, 90  \"\nprint(line.strip())              # \"78, 81, 90\"\nprint(line.strip().split(\", \"))  # ['78', '81', '90']\nprint(\"marks\" in \"exam marks\")   # True"},{"t":"h2","id":"f-strings-for-building-sentences","runs":[{"text":"f-strings, for building sentences"}]},{"t":"p","runs":[{"text":"Joining with "},{"text":"+","code":true},{"text":" gets ugly fast. Put an "},{"text":"f","code":true},{"text":" before the quote and put values in curly braces:"}]},{"t":"code","lang":"python","label":"Python","text":"name = \"Amara\"\nmarks = 81\nprint(f\"{name} scored {marks} out of 100\")\nprint(f\"Half of that is {marks / 2}\")"},{"t":"p","runs":[{"text":"The braces are worked out as the line runs. Anything inside them can be arithmetic, not just a name."}]},{"t":"h2","id":"input-asks-the-person-running-the-program","runs":[{"text":"input() asks the person running the program"}]},{"t":"code","lang":"python","label":"Python","text":"name = input(\"Your name: \")\nprint(f\"Hello, {name}\")"},{"t":"p","runs":[{"text":"Run it and the program pauses, shows the prompt, and waits for you to type and press Enter. Whatever you typed becomes the value of "},{"text":"name","code":true},{"text":"."}]},{"t":"h2","id":"the-rule-that-causes-the-most-beginner-bugs","runs":[{"text":"The rule that causes the most beginner bugs"}]},{"t":"p","runs":[{"text":"input()","code":true},{"text":" always gives you a string. Always. Even when the person typed digits."}]},{"t":"code","lang":"python","label":"Python","text":"age = input(\"Your age: \")\nprint(type(age))     # <class 'str'>\nprint(age + 1)"},{"t":"code","lang":"","label":"Text","text":"TypeError: can only concatenate str (not \"int\") to str"},{"t":"p","runs":[{"text":"The person typed "},{"text":"20","code":true},{"text":" and you got "},{"text":"\"20\"","code":true},{"text":". Python cannot know that you wanted a number rather than a house number or a bus route. So you say it:"}]},{"t":"code","lang":"python","label":"Python","text":"age = int(input(\"Your age: \"))\nprint(f\"Next year you will be {age + 1}\")"},{"t":"p","runs":[{"text":"Read that from the inside out: "},{"text":"input(...)","code":true},{"text":" runs first and gives text, then "},{"text":"int(...)","code":true},{"text":" turns that text into a number, then the name "},{"text":"age","code":true},{"text":" is attached to the number."}]},{"t":"h2","id":"the-quieter-version-of-the-same-bug","runs":[{"text":"The quieter version of the same bug"}]},{"t":"p","runs":[{"text":"The crash above is the friendly case. Here is the unfriendly one:"}]},{"t":"code","lang":"python","label":"Python","text":"budget = input(\"Monthly budget in pesos: \")   # you type 1200\nif budget > \"900\":\n    print(\"above\")\nelse:\n    print(\"below\")"},{"t":"p","runs":[{"text":"This prints "},{"text":"below","code":true},{"text":", and never complains. Both sides are text, so Python compared them the way a dictionary or a phone book does: character by character, left to right. "},{"text":"\"1\"","code":true},{"text":" comes before "},{"text":"\"9\"","code":true},{"text":", so "},{"text":"\"1200\"","code":true},{"text":" sorts before "},{"text":"\"900\"","code":true},{"text":" and the comparison is decided at the very first character. Length never enters into it."}]},{"t":"p","runs":[{"text":"Text comparison is not broken. It is answering a different question from the one you meant. The fix is to convert before you compare:"}]},{"t":"code","lang":"python","label":"Python","text":"budget = int(input(\"Monthly budget in pesos: \"))\nif budget > 900:\n    print(\"above\")"},{"t":"p","runs":[{"text":"A program that crashes tells you where it went wrong. A program that silently answers the wrong question does not. Convert at the edge, the moment data arrives, and the rest of your code can stop worrying."}]},{"t":"h2","id":"try-this-now","runs":[{"text":"Try this now"}],"role":"try"},{"t":"code","lang":"python","label":"Python","text":"item = input(\"What did you buy? \")\nprice = float(input(\"Price? \"))\nqty = int(input(\"How many? \"))\nprint(f\"{qty} x {item} = {price * qty:.2f}\")"},{"t":"p","runs":[{"text":"The "},{"text":":.2f","code":true},{"text":" rounds to two decimal places. Then type "},{"text":"abc","code":true},{"text":" when it asks for the price and read the error."}]}],"check":{"question":[{"text":"A program does "},{"text":"budget = input(\"Budget: \")","code":true},{"text":" and then "},{"text":"if budget > \"900\":","code":true},{"text":". The user types 1200 and the program prints the else branch. What is the real explanation?"}],"options":[{"text":[{"text":"Python compared the two as text, character by character, and "},{"text":"\"1\"","code":true},{"text":" sorts before "},{"text":"\"9\"","code":true},{"text":", so the answer was decided at the first character."}],"correct":true,"tempting":null},{"text":[{"text":"Python compared the lengths: "},{"text":"\"900\"","code":true},{"text":" has three characters and "},{"text":"\"1200\"","code":true},{"text":" has four, and it treats the shorter string as the greater one."}],"correct":false,"tempting":[{"text":"Length is the most visible difference between the two strings, and it does affect comparison when the earlier characters happen to match."}]},{"text":[{"text":"input()","code":true},{"text":" returned the number 1200, and Python converted the text "},{"text":"\"900\"","code":true},{"text":" into a number badly, producing zero."}],"correct":false,"tempting":[{"text":"Several popular languages really do convert across types during a comparison, so assuming Python does the same is a reasonable transfer of experience."}]},{"text":[{"text":"input()","code":true},{"text":" kept the Enter key at the end, so the value was 1200 followed by a newline, and any string ending in a newline compares as smaller."}],"correct":false,"tempting":[{"text":"You really did press Enter, and it is plausible that the keystroke ends up inside the value, which would explain an invisible difference."}]}],"order":[3,2,1,0],"why":null},"prev":{"slug":"numbers-and-arithmetic","title":"Numbers: whole, decimal, and the one that surprises everybody","minutes":8},"next":{"slug":"formatting-output","title":"Building the output a person will read","minutes":7}}}