Skip to content
Cortex

Python Fundamentals

Python FoundationsBeginner
Where this fits

This is the first topic in Python and the foundation for everything that follows. Every later topic, from operators and control flow to the data-analysis and machine learning tracks, is written in Python, so the syntax and mental models here are assumed throughout. Start here if you are new to coding.

This note builds Python from the ground up: why the language exists and became popular, how it turns your English-like code into something a machine can run, and the first building blocks you need to write real programs. Those building blocks are printing output, data types, variables, comments, keywords, identifiers, reading user input, converting between types, and literals.

Nothing here assumes prior programming experience. Every term is defined the first time it appears.


Python was created in 1989, several years before Java, yet it stayed in the background for decades. Java dominated when the internet era began. Today Python competes with Java in general use and clearly leads in data science. It is worth understanding why, because the reasons explain what the language is good at.

Reason one: the design philosophy

A language’s design philosophy is the set of ideas its creators optimized for. Python optimized for human readability.

  • It is likely the easiest mainstream language to learn. A beginner with no background can write working code quickly.
  • Python code is forced into clean indentation, so it stays readable. You can look at code someone else wrote and follow what it does.
Tip

A useful contrast: languages like Java are strict and ceremonious, and they reject your code if the form is not exactly right. Python is forgiving. It lets you make mistakes, learn from the errors, and keep moving. That forgiveness is why beginners get productive fast.

Reason two: batteries included

Batteries included means the language ships with a large amount of useful functionality already built in, so you do not have to write it yourself.

Python’s built-in data types arrive with functions and operators already attached. Work that takes many lines in C or C++ often takes one line in Python.

Example

Reversing a piece of text is a classic beginner exercise in C, where you write a loop and build the logic by hand. In Python there is a single-line way to do it, with no loop to write.

A fair question is whether relying on built-in tools prevents you from becoming a good programmer. It does not. Your job is to build something that works well, not to rewrite from scratch what already exists. Python follows the principle: do not reinvent the wheel. If the wheel exists, use it to build the car.

Reason three: it is general purpose

A general purpose language is one you can use across many kinds of problems, rather than one narrow domain. Python qualifies in two ways.

It supports multiple programming paradigms, which are different styles of organizing a program:

  • Procedural programming
  • Object-oriented programming
  • Functional programming

It also supports many kinds of software:

  • Desktop applications
  • Websites
  • Data science and machine learning code

So learning Python pays off beyond data science. The same skill transfers to web development or building tools.

Reason four: the community and its libraries

A library is a bundle of code someone else wrote that you can reuse in your own program.

Python’s community is unusually active and generous, and it keeps producing libraries. For data work you have pandas, NumPy, SciPy, PySpark, TensorFlow, Keras, and many more. In practice, whatever you are trying to build, a library probably already exists for a large part of it.

ReasonWhat it gives you
Design philosophySimple, readable, forgiving code
Batteries includedOne-line solutions instead of long hand-written logic
General purposeOne language for web, desktop, and data science
Community and librariesReusable code for almost any task

Why Python leads in data science

Python is the number one language for data science in industry. In academia and research, R is also widely used, and it has excellent plotting libraries. But for a job in industry, Python is the one to learn. Three reasons explain why Python won over Java, JavaScript, PHP, and Ruby.

It is easy to learn. Data science was first practiced by mathematicians and statisticians, not programmers. When they needed to turn their algorithms into working software, they wanted a language they could pick up in days, not months. Python fit. Java and C++ are harder to learn, so they lost this group.

It is close to mathematics. Python already had strong libraries for scientific computing, such as NumPy and SciPy, before the data science boom. The language was already being used for mathematical work, so it was the natural place to continue.

The community compounded the advantage. Once people arrived and started publishing open-source libraries, an ecosystem formed. Now the gap is so wide that other languages would need enormous effort to catch up in this domain.

Note

A common objection is that Python is slow compared to C or C++, and its native data structures are indeed slower. The community solved this rather than accepting it. NumPy provides a data type called the ndarray that is implemented in C, so it runs fast while you still write ordinary Python. Most machine learning work uses these arrays, which means your code is Python but the heavy computation is C speed.


How your code reaches the machine

Before writing code, it helps to know what happens to it. This explains both error messages and the idea of keywords later on.

You write programs in words like print, if, else, and for. These are English words, which makes this a high-level language: something close to human language and far from hardware.

The machine that runs your code is a processor chip. It does not understand English. It understands only binary: patterns of 11 and 00, which physically mean power on and power off.

So something must translate your English-like code into binary. That translation is called compilation, and the program that performs it is either a compiler or an interpreter.

Compiled languages translate the whole program at once; interpreted languages translate line by line

CompiledInterpreted
TranslatesThe whole program at onceOne line at a time
ExamplesJava, C, C++Python, PHP
Typical speedFasterSlower

Python is an interpreted language, so it converts and runs your code line by line. This is part of why it is slower than compiled languages, and also why it can report an error at the exact line where it occurred.

Note

Low-level coding means writing close to the hardware, in assembly language or raw binary. It is difficult and rarely done today outside specialized areas like microcontrollers and robotics. Almost all modern programming is high level, with a compiler or interpreter handling the translation.


Printing to the screen

The first thing you learn in any language is how to put something on the screen. In Python you do this with print.

Before using it, understand what a function is. A function is a named box you hand some input to, which then does a job and gives you output. You can recognize a function by the pattern name( ): a word followed by parentheses. Whatever you put inside the parentheses is the input.

print is a built-in function, meaning it already exists inside Python and needs no setup.

print('Hello world')
Hello world
Warning

Python is case sensitive, so print and Print are different names. Only the lowercase print is the function. This applies to every name in Python, so be consistent.

Quotes mark text

Text must be wrapped in quotes. The quotes are how you tell Python that something is text rather than a name it should look up.

print('Salman Khan')   # works: quoted, so it is text
print(Salman Khan)     # error: Python does not know what this is

You can print other kinds of values too, and they do not need quotes because they are not text.

print(7)        # a whole number
print(7.5)      # a decimal
print(True)     # a boolean

Printing several values at once

print is flexible. Separate values with commas and it prints them all, joined by spaces.

print('hello', 1, 4.5, True)
hello 1 4.5 True

Controlling the separator and the line ending

Every built-in function comes with documentation, which you can think of as the instruction manual that ships with a product. The manual for print reveals two settings you can change.

The sep setting controls what goes between values; the end setting controls what follows the line

sep is the separator: what Python puts between multiple values. Its default is a single space, which is why the example above had spaces.

print('hello', 1, 4.5, sep='/')
hello/1/4.5

end is what Python adds after finishing the line. Its default is \n, the newline character, which is why two print statements produce two lines.

print('hello')
print('world')
hello
world

Override end to keep them on one line:

print('hello', end='-')
print('world')
hello-world
Tip

You can use any separator or ending you like: a hyphen, a slash, a percent sign, or nothing at all. This level of control is a small example of how much flexibility Python gives you by default.


Data types

A data type is a kind of value a language can work with. Knowing the available types tells you what Python can represent.

The clearest way to hold the whole set in your head is to group them by what you are allowed to do to a value. An immutable value cannot be changed after it is created, while a mutable value can be changed in place.

Python data types grouped into immutable and mutable, with None as a separate case

Each type is introduced below.

Numbers

Integers (int) are whole numbers, positive or negative. Python integers have arbitrary precision: they grow as large as your memory allows, with no fixed maximum, so you never overflow an integer.

print(8)
print(2 ** 1000)    # a 302-digit number, computed exactly

Floats (float) are decimals. Unlike integers, they have a finite range, holding values up to about 1.8×103081.8 \times 10^{308}. Beyond that a float reports inf (infinity).

print(8.55)
print(1e308)        # 1 multiplied by 10 to the power 308
print(1e309)        # inf: past the float range

In 1e3081e308, the e notation means 1×103081 \times 10^{308}.

Note

Other languages separate long and double from int and float. Python does not. Long values map into int automatically, which is why Python integers need no separate type for large values.

Complex numbers (complex) have a real part and an imaginary part, written with j.

print(5 + 6j)

They exist for completeness and mathematical work, but you will rarely use them in ordinary projects.

Booleans

A boolean (bool) is either True or False. These power all decision logic.

print(True)
print(False)
Warning

Do not put quotes around True and False. A boolean is not text. Writing 'True' gives you a string that happens to spell the word, which behaves differently.

Text

Strings (str) hold text.

print('hello world')

Python has no separate single-character type. Languages like C have a char type; in Python a single character is just a string of length one.

Collections

These types hold several values together. Each is covered in depth on its own, so here the goal is only to recognize them.

TypeWritten withExample
listSquare brackets[1, 2, 3]
tupleRound brackets(1, 2, 3)
setCurly braces{1, 2, 3}
dictCurly braces with key-value pairs{'name': 'Aarav'}

A list plays the role that arrays play in C, though it is more capable. A tuple looks almost identical to a list but behaves differently in ways that matter later. A set is the mathematical set you met in school, holding unique items. A dictionary stores key-value pairs, where you look up a value by its key.

{'name': 'Aarav', 'gender': 'male', 'weight': 70}

Here name is a key and 'Aarav' is its value.

Note

The choice between square, round, and curly brackets carries no deeper meaning. They are the notation Python uses to tell these types apart.

None

None is a special value meaning nothing. Its use is explained in the literals section below.

Checking a type with type()

type is a built-in function that reports the data type of whatever you give it. It is one of the most useful tools for understanding what your program is holding.

print(type(3))        # <class 'int'>
print(type(3.5))      # <class 'float'>
print(type('hello'))  # <class 'str'>
print(type(6 + 6j))   # <class 'complex'>
print(type([1, 2]))   # <class 'list'>
Tip

When a program behaves unexpectedly, checking type() on your values is often the fastest way to find the cause. You will see exactly this used to diagnose a bug later in this note.


Variables

A variable is a named container that holds a value so you can use it later.

The reason variables exist is that when you write a program, you do not know in advance what values it will handle. A website’s home page should greet whoever logs in, but you cannot know today whether that will be Rahul, Rohit, or Ankit. So you put a variable where the name belongs, and fill it in once someone logs in.

Creating a variable

In C or C++ you declare a variable by stating its type first:

int name = 5;

Python needs no type. Write the name, an equals sign, and the value.

name = 'Aarav'
print(name)
Aarav

The = here is the assignment operator. It stores the value on the right into the name on the left.

a = 5
b = 6
print(a + b)
11
Note

Python has no separate variable declaration step. You cannot reserve a name at the top of a program for later use. You create a variable at the moment you give it a value.

Dynamic typing

Dynamic typing means you do not state a variable’s data type; the interpreter works it out from the value you assign.

Python sees 5 and concludes int. It sees 5.5 and concludes float. It sees 'Aarav' and concludes str.

Static typing is the opposite, used by C, C++, and Java, where you declare the type when creating the variable.

Dynamic binding

Dynamic binding means a variable is not permanently tied to one data type. The same variable can hold different types at different points in the same program.

a = 5
print(a)        # 5

a = 'Aarav'
print(a)        # Aarav

No error occurs. The variable holds whatever you last put in it.

Both ideas make sense once you see what a variable is underneath. A variable is not a box that holds a value. It is a label pointing at an object stored in memory, and the data type belongs to that object, not to the label.

A variable is a label pointing at an object in memory; reassigning moves the label to a different object

This single picture explains both concepts. Dynamic typing works because Python reads the object to find the type, so you never have to declare it. Dynamic binding works because assigning again just moves the label to a different object, and the new object can be any type at all.

Static binding is the opposite: once a variable’s type is fixed, it cannot hold a different type anywhere in the program. C, C++, and Java work this way.

ConceptPythonC, C++, Java
TypingDynamic (type inferred)Static (type declared)
BindingDynamic (type can change)Static (type fixed)
Warning

Programmers from a Java background often dislike dynamic binding, because a variable silently changing type can hide bugs. It is a genuine tradeoff: you gain flexibility and lose a safety check.

Shorter ways to create variables

You can create several variables on one line.

a, b, c = 1, 2, 3
print(a, b, c)
1 2 3

You can also give several variables the same value in one statement.

a = b = c = 5
print(a, b, c)
5 5 5

Both are worth recognizing, because you will meet them in code other people wrote.


Comments

A comment is a note you write inside your code for humans to read. The interpreter ignores it completely, so it never runs and never causes an error.

In Python a comment starts with #. Everything after the # on that line is ignored.

# add two numbers and show the result
a = 5
b = 6
print(a + b)    # this prints 11

Comments can sit above the code they describe or at the end of a line. Placing them above is the more common convention in professional codebases.

Python has no true multi-line comment. For several lines of explanation, put # at the start of each line.

# this is the first line of explanation
# this is the second line
Tip

Write comments even when the code feels obvious. A programmer who writes no comments is like a batsman who scores freely but keeps getting his partner run out. Excellent individually, difficult for the team. Comments are how your teammates, and your future self, understand the logic you had in mind.


Keywords and identifiers

These two ideas come directly from how the interpreter reads your code.

Keywords

Recall that the interpreter must translate your English-like code into binary. To do that, it needs certain words to have fixed, guaranteed meaning. When it sees print, it knows the programmer wants to display something. When it sees if, it knows a decision is being made.

Keywords are the words Python reserves for itself for exactly this purpose. Python has roughly 32 of them, including if, else, for, True, False, and None.

You do not need to memorize the list. You need one rule: never use a keyword as a name in your own program.

Warning

The reason is confusion. If you named a variable if, your code could read if(if > 5), which is meaningless. The interpreter cannot tell your name from its own instruction, so it reports an error and the program does not run.

Identifiers

An identifier is any name you create in your program: a variable name, a function name, or a class name. Python has three rules for them.

Rule one: do not start with a digit.

1name = 'Aarav'    # error
name1 = 'Aarav'    # works

Rule two: use letters, digits, and underscores only. Uppercase and lowercase are both fine. Among special characters, only the underscore is allowed.

first_name = 'Aarav'    # works
first-name = 'Aarav'    # error

A name can even be a single underscore, _, which is valid and has conventional uses you will meet later. Characters such as -, @, and % are not allowed.

Rule three: an identifier cannot be a keyword. This follows from the previous section.

Note

Every variable is an identifier, but identifier is the broader term, since it also covers the names of functions and classes.


Taking input from the user

So far your programs only produce output. To be useful, most programs must also accept input.

Think of software in two categories.

Static software does not interact with the user. It presents information and you read it: a calendar, a clock, a blog, a college website.

Dynamic software takes input from the user and responds. Nearly all software you use daily is dynamic. On YouTube you type what you want to watch. On Ola you enter your destination. On Zomato you choose your order.

Building dynamic software starts with being able to read input, which in Python uses the built-in input function.

input()

Running this shows an input box, and whatever the user types comes back as the result.

There is a problem though: an empty box tells the user nothing. They cannot know whether to type a name, an email, or a password. As the programmer it is your responsibility to say what is expected, so pass a message to input.

input('Enter your email: ')

Now the user sees the prompt alongside the box.


Your first complete program

The goal: take two numbers from the user, add them, and display the result.

A useful habit when starting out is to think before typing. Programming happens in your head first and on the keyboard second. Write the steps as comments, then fill in the code under each one.

# take input from the user and store it in variables
fnum = input('Enter first number: ')
snum = input('Enter second number: ')

# add the two variables
result = fnum + snum

# print the result
print(result)

Enter 56 and 67, and the output is surprising:

5667

That is not the sum. The two values were joined end to end instead of added.

Diagnosing the bug

Use type() to inspect what the variables hold.

print(type(fnum), type(snum))
<class 'str'> <class 'str'>

Both are strings. The user typed digits, but input stored them as text.

This explains the output. For numbers, + means addition. For strings, + means joining, so 'Mumbai' + 'Kolkata' gives 'MumbaiKolkata', and '56' + '67' gives '5667'.

Note

Why does input always return a string? Because string is a universal format. Any value can be represented as text: a number, a decimal, even a complex number. The reverse is not true, since text like 'Kolkata' cannot become an integer. Since input cannot know what the user will type, returning a string is the only choice that never crashes.

The fix requires converting the text into numbers, which is the next concept.


Type conversion

Type conversion is changing a value from one data type to another. Python does this in two ways.

Implicit type conversion

Implicit conversion happens automatically. The interpreter recognizes what you intended and handles it without being asked.

print(5 + 5.6)
10.6

Here one value is an int and the other a float. Strictly, that is an operation across two different types. Python understands that this is mathematically sensible and converts for you.

Implicit conversion has limits. When the intent is not clear, Python refuses.

print(4 + '4')    # error: cannot add an integer and a string

Adding a number to text has no obvious meaning, so Python raises an error instead of guessing.

Explicit type conversion

Explicit conversion is when you ask for the change yourself, using a built-in function named after the target type.

print(int('4'))        # 4,   now an integer
print(int(4.5))        # 4,   decimal part dropped
print(str(5))          # '5', now a string
print(float(4))        # 4.0, now a float

There is one function per data type: int(), float(), str(), bool(), list(), set(), dict(), and tuple().

Conversion only works when it makes sense.

print(int(4 + 5j))    # error

A complex number has a real and an imaginary part. Keeping 44 and discarding 55 would lose information, and Python does not allow silent information loss.

Warning

Type conversion never modifies the original value. It creates a new one. This is a frequent source of confusion, so it is worth seeing directly.

fnum = input('Enter first number: ')    # user types 56
result = int(fnum) + 10
print(type(fnum))                       # still <class 'str'>

int(fnum) does not change fnum. It produces a new integer with the same numeric value, and the arithmetic uses that new object. fnum itself is never touched, so it remains a string.

Converting a value builds a new object while the original name keeps pointing at the unchanged value

Note

This differs from type casting in some other languages, where the conversion permanently changes the original value. Python’s type conversion always leaves the original alone and returns something new.

Fixing the program

Convert the input to integers. The cleaner approach is to convert at the moment you read the input, so the variable holds a number from the start.

# take input from the user and store it in variables
fnum = int(input('Enter first number: '))
snum = int(input('Enter second number: '))

# add the two variables
result = fnum + snum

# print the result
print(result)

With 56 and 67:

123

Converting during input is preferable whenever you are sure the values should always be numbers, because from then on the variables genuinely hold integers.


Literals

A literal is the raw value you assign to a variable. In a = 2, the parts are:

  • a is the variable
  • = is the operator
  • 2 is the literal

Python offers several notations for writing literals, and recognizing them prevents confusion when reading other people’s code.

Integer literals

You can write whole numbers in four number systems. The prefix tells Python which system you mean.

NotationPrefixExampleValue
Binary0b0b101010
Decimalnone100100
Octal0o0o310200
Hexadecimal0x0x12c300
a = 0b1010
print(a)        # 10

Python prints 10 because 0b1010 is binary notation for the decimal value 1010.

Tip

These alternative notations matter most in hardware work. When programming microcontrollers or configuring ports, binary and hexadecimal notation map directly onto the hardware, so they are the natural way to write values.

Float literals

Decimals can be written normally or in scientific notation using e.

b = 10.5
c = 1.5e2       # 1.5 × 10²  = 150.0
d = 1.5e-3      # 1.5 × 10⁻³ = 0.0015

The e notation means 1.5×1021.5 \times 10^{2}, and a negative exponent gives a tiny number. This is convenient when working with numbers at extreme scales.

Complex literals

You can write only the imaginary part, and read the two halves separately.

x = 3 + 4j
print(x.real)    # 3.0
print(x.imag)    # 4.0

String literals

Python accepts several ways to write text, all valid.

a = 'single quotes'
b = "double quotes"
c = '''triple quotes'''

Triple quotes are used for strings that span multiple lines.

Two special forms are worth knowing now.

A raw string is prefixed with r. Normally \n means a new line and \t means a tab; these are escape sequences. A raw string turns that off, so the characters appear literally.

print('hello\nworld')     # prints on two lines
print(r'hello\nworld')    # prints hello\nworld

A Unicode string is prefixed with u. Unicode is the standard that lets text represent far more than letters and digits, including symbols and emoji.

d = u'\U0001f600'    # an emoji

Boolean literals

True and False are the boolean literals. Internally Python treats True as 11 and False as 00, which means they work inside arithmetic.

a = True + 4     # 1 + 4
b = False + 10   # 0 + 10
print(a)         # 5
print(b)         # 10
Warning

This behavior appears in quiz questions designed to confuse. Remember that in a mathematical expression, Python treats booleans as the numbers 11 and 00.

The None literal

None means nothing. Printing it shows None, and it carries no value of its own.

Its practical use solves the declaration problem noted earlier. Python has no variable declaration, so you cannot reserve a name for later:

k           # error: Python does not know what k is
a = 5

Assigning None reserves the name without committing to a value.

k = None    # reserved for later; no error
a = 5
Example

This is genuinely useful when writing an algorithm from scratch and you do not yet know which variables you will need. Declare them as None at the top, then fill them in as the logic takes shape. No error occurs and the program’s behavior is unaffected.


Summary

  1. Python became dominant through readable design, built-in functionality, general purpose reach, and a large library ecosystem. It leads data science because it is easy to learn, already close to mathematics, and backed by an unmatched ecosystem.
  2. Python is interpreted, translating your code to machine code line by line, which is why an error stops the run only when execution reaches that line.
  3. print() displays values, and its sep and end settings control what goes between values and after the line.
  4. Data types define what Python can represent: int, float, bool, str, complex, list, tuple, set, dict, and None. Use type() to inspect any value.
  5. A variable is a label pointing at an object. Python uses dynamic typing, so you never declare a type, and dynamic binding, so the same variable can later point at a different type.
  6. Comments start with # and are ignored by the interpreter. Write them for the people who read your code later.
  7. Keywords are reserved for Python. Identifiers are names you create, and they cannot start with a digit, cannot use special characters other than the underscore, and cannot be keywords.
  8. input() reads from the user and always returns a string, so convert it before doing arithmetic.
  9. Type conversion is implicit when Python can infer intent, and explicit when you call int(), float(), or str(). It always creates a new value and leaves the original unchanged.
  10. Literals are the raw values you assign, and Python provides multiple notations for numbers and strings.

Continues to

With values, variables, and the type system in hand, the next step is Operators & Control Flow, where operators combine these values and conditional logic with if and else lets a program make decisions.

Test yourself

Quiz me is a timed test of 8 questions drawn from a pool of 16 (~8 mins, score 6+ to complete the note; miss it and it locks until review). Each attempt is a fresh mix. Flashcards is untimed recall practice over the whole pool.

Completion

Private to you, stored in this browser, never uploaded.

© 2026 Cortex. A personal notes project.