Python is a high-level, interpreted programming language known for its emphasis on code readability and simplicity. This pretty much summarizes the key characteristics of the language, and explains why it stood out among other programming languages recently.
In computer science, a high-level programming language refers to one that provides strong abstraction from the underlying hardware details. This means that programmers can focus on logic and functionality of their programs without needing to worry about the specific instructions that the computer’s processor will execute. Python is one such language. It has human-readable syntax, hides complicated details (e.g., memory management), and is completely portable across different types of operating systems, including Windows, Mac, and Linux, with no code modification.
It is also an interpreted language. This further sets Python apart from other high-level languages like Java or C. When you install Python, a special program called the Python interpreter is bundled. This program directly translates Python into machine code without compilation. This contrasts with compiled languages which requires the entire code to be converted into machine code before execution. Instead of compiling the entire set of code as a whole and generating executable file, Python executes the code line by line at runtime, making it more flexible and interactive.
Python’s syntax is designed to be intuitive and straightforward. It employs elements from natural languages. For example, in Python, code indentation not just organizes the code but also defines the level of the code. In contrast to many other languages that use symbols like curly brackets or keywords to denote code blocks, Python uses different levels of indentations to indicate hierarchy and scope. Its syntax is also very simple. For example, to print out “Hello, World!” using Java programming language:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
The same result can be done by the running Python code below:
print('Hello World!')
## Hello World!
We can clearly see that Python’s syntax is much simpler than that of Java.
All these defining characteristics of Python have been driven its increasing popularity among programmers. Its simple syntax and interpreted nature enables developers to quickly prototype their ideas. Particularly, in the field of data science and machine learning, where frequent adjustments are required, Python allows for quicker development cycle, as you can test code changes immediately without compilation.
Basic Building Blocks of Python
Python’s syntax is designed to be readable and easy to learn. Here’s a breakdown of its elements:
- Literals: Values that are directly written in the Python code scripts.
- Identifiers: Python is an object
oriented programming (OOP) language and nearly everything
in Python, including literals, variables, or functions, is considered as
an object. Each of these objects has a given name, called
identifier.
- Variables: A variable is a name that refers to a literal value. In Python, variables do not require explicit declaration and are dynamically typed,“ meaning you can reuse the same variable name for different object; reassignment is allowed during program execution.
- Functions: A function is a block of reusable code
whenever it is called. Python supports regular functions (defined with
the
def
keyword), lambda functions (defined withlambda
keyword), as well as many built-in functions for common tasks. - Modules and Packages: A module is a
.py
file that contains related functions and classes. A package is an organized collection of modules and/or other sub-packages. Both can be imported and used in a Python program for execution.
- Data Types: Python supports several native types
like
int
,floats
,strings
,lists
,tuples
,sets
,dictionaries
, and more. These types determine the kind of operations you can perform on variables. - Operators: Symbols that perform operations on variables and literals.
- Reserved Words: These have some predefined meanings
and cannot be used as an identifier. Reserved words are part of the
Python syntax and serve specific purpose within the language. Examples
include
if
,else
,while
,for
,def
, andclass
. - Indentation: In computer programming, indentation refers to the use of spaces or tabs at the beginning of code lines to indicate how they are structured. Particularly, in Python, indentation is not just for readability; it serves as a syntactical element to define the scope of code blocks. For each level, you can use either a tab or four spaces1. Note that mixing spaces and tabs to indicate multiple indent levels within a single block is not allowed.
- Comments: Non-executable lines in code, helping
with documentation. They start with
#
for single-line comments, and triple quotes ('''
or"""
) can be used for multi-line comments.
Operators combined with variables and/or literals are called expressions. Objects placed on left and right sides of the operators are evaluated into a single value, containing the outputs from the supposed calculations. For example:
3 + 4
is evaluated into a single number7
."Hello, " + "World!"
is evaluated into a single string"Hello, World!"
.True and False
is evaluated intoFalse
.
When Python expressions are combined with some other expressions, reserved words, and/or variables, it becomes a Python statement,2 which represents a complete line of code performing an operation. For example:
my_var = 3 + 4
print("Hello, " + "World!")
if True and False: print("Won't be printed")
In the examples, the +
operator adds 4
to
3
and =
operator assigns the calculated value
into a variable named my_var
. Similarly,
print("Hello, " + "World!")
is a statement that takes the
string output from the +
operation. and passes it to the
print()
function to display the result. Observe that the
same operator (+
) works differently, depending on which
context it is used: when applied to numeric literals, it sums the
values, while it performs concatenations when applied to strings.
A Python function refers to a collection of related Python statements, grouped under an indentation. For example:
def add_nums(a, b):
result = a + b
return result
This function takes two parameters a
and b
,
adds them together, and returns the result. By grouping the Python
statements as a function, you can reuse them whenever needed.
Variable Assignments in Python
In Python, variable assignments can be done using the assignment
operator (=
). It assigns the objects placed on its right
side into a name specified on its left side. Unlike other programming
languages, Python do not require explicit declaration of a
variable with its data type, Instead, the Python
interpreter infers the data type dynamically based on the contexts. For
example, in Java, to declare a variable you should also specify the data
type (e.g., int x = 5;
) and the variable cannot change its
type once it has been declared. This means that if you declare a
variable as an integer, you cannot later assign a string or other data
type to it. However, in Python, the data type of a variable is flexible,
and it can change during runtime3:
x = 5 # Python infers that x is an integer
y = "Hello" # Python infers that y is a string
In this example, Python allows x
to change from an
integer to a string, which is not possible statistically typed languages
like Java.
This property often leads to some unexpected behaviors. For example:
x = 5
y = 6
add_nums(x, y)
x = 'Hello" # Now x is reassigned as an integer
add_nums(x, y)
## unterminated string literal (detected at line 6) (<string>, line 6)
Nevertheless, dynamic typing of Python makes its syntax concise and readable compared to that of other programming languages.
Naming Rules and Conventions
To be a valid name for a variable, it must adhere to the following naming rules:
- Start with a letter or an
underscore(
_
): Variable names cannot begin with a number.- Valid:
_my_var
,myVar
- Invalid:
1st_var
- Valid:
- Contain only letters, numbers, or underscores:
Special characters like
@
,#
,!
, or spaces are not allowed.- Valid:
my_var
,var123
- Invalid:
my-var
,my var
- Valid:
- Cannot use reserved words: You cannot assign
Python’s reserved words to a variable.
- Invalid:
for
,if
- Invalid:
In addition to the naming rules, Although not strictly enforced by Python, following these conventions makes your code more readable and maintainable:
- Use descriptive names: Choose names that clearly
indicate the purpose of the variable. This practice also helps avoiding
errors caused from the dynamic typing.
- Good:
student_count
(should be an integer),total_price
(should be a float) - Poor:
data
- Good:
- Follow snake_case: Use lowercase letters with
underscores to separate words.
- Example:
employee_name
,max_value
- Example:
- Constants in UPPERCASE: Python do not support a
distinct constant and all variables are dynamically typed. So, if your
variable is intended to act like a constant through out your program,
use all uppercase letters
- Example:
UPPER_LIMIT = 100
- Example:
- Avoid single-character names: Except for loops,
avoid using single leters for descriptive variables.
- Good:
index
,counter
- Poor:
x
,y
- Good:
- Avoid names starting with an underscore unless
necessary: Variables starting with
_
are typically used for private or special purposes.
All these conventions aim to make code “Pythonic,” a term that embodies writing clean, readable, and efficient code that adheres to Python’s philosophy and best practices.
import this
## The Zen of Python, by Tim Peters
##
## Beautiful is better than ugly.
## Explicit is better than implicit.
## Simple is better than complex.
## Complex is better than complicated.
## Flat is better than nested.
## Sparse is better than dense.
## Readability counts.
## Special cases aren't special enough to break the rules.
## Although practicality beats purity.
## Errors should never pass silently.
## Unless explicitly silenced.
## In the face of ambiguity, refuse the temptation to guess.
## There should be one-- and preferably only one --obvious way to do it.
## Although that way may not be obvious at first unless you're Dutch.
## Now is better than never.
## Although never is often better than *right* now.
## If the implementation is hard to explain, it's a bad idea.
## If the implementation is easy to explain, it may be a good idea.
## Namespaces are one honking great idea -- let's do more of those!
Augmented Assignments
In Python, augmented assignments are shorthand operators that combine an operation with assignment. They allow you to modify a variable by performing an operation and then reassigning the result to the same variable. These operators can be used to simplify code and improve readability, especially when performing arithmetic or other operations on variables.
Common augmented assignment operators include:
+=
: Add and assign-=
: Subtract and assign*=
: Multiply and assign/=
: Divide and assign//=
: Floor divide and assign%=
: Modulus and assign**-
: Exponentiate and assign
For example:
x = 10
x += 5 # x = x + 5, so x becomes 15
print("Current value of x is", x)
## Current value of x is 15
y = 20
y *= 3 # y = y * 3, so y becomes 60
print("Current value of y is", y)
## Current value of y is 60
z = 100
z /= 4 # z = z / 4, so z becomes 25.0 (result is a float)
print("Current value of z is", z)
## Current value of z is 25.0
Native Data Types in Python
Python has a rich set of native data types to represent different kinds of data. Here’s an overview:
Basic Data Types
Basic data types are used to represent individual values like numbers, Booleans, or null-like data values. They are atomic and cannot be broken into smaller data elements. Basic data types are also immutable, meaning their values cannot be changed after they are created. Instead, any operation that “modifies” a basic data type will create a new object with the updated value.
- Numbers
int
: Represent integers (e.g.,42
,7
). Constructor for the type isint(value=0)
. For example:int("42")
\(\rightarrow\)42
float
: Represents floating-point numbers (e.g.,3.14
,-0.001
). Constructor for the type isfloat(value=0.0)
. For example:float("3.14")
\(\rightarrow\)3.14
complex
: Represents complex numbers with real and imaginary parts (e.g.,1+2j
). Constructor for the type iscomplex(real=0, imag=0)
. For example:complex(1, 2)
\(\rightarrow\)(1+2j)
.
- Boolean (
bool
): Represents Boolean values (True
orFalse
). Constructor for the type isbool(value)
. For example:bool(0)
\(\rightarrow\)False
. - NoneType (
None
): Represents the absence of a value. Constructor for the type is not applicable; only one instance exists for the type:None
.
Sequence Data Types
Sequence types represent ordered collection of elements. These types allow indexed access, slicing, and iteration. They can store atomic values like basic data types we saw earlier or composite data.
- Strings (
str
): Immutable sequences of Unicode characters. Constructor for the type isstr(object='')
. For example:str(42)
\(\rightarrow\)"42"
- Lists (
list
): Mutable ordered collections of items. Constructor for the type islist(iterable=[])
4. For example:list("abc")
\(\rightarrow\)['a', 'b', 'c']
. - Tuples (
tuple
): Immutable ordered collections of items. Constructor for the type istuple(iterable = ())
. For example:tuple([1, 2, 3])
\(\rightarrow\)(1, 2, 3)
. - Ranges (
range
): Represents a sequence of numbers. Constructor for the type isrange(start, stop[, step])
. For example:range(0, 10, 2)
\(\rightarrow\)0, 2, 4, 6, 8
For the sequence data types, you can index to access individual
elements contained in the object. Python uses zero-based
indexing, meaning the first element in a sequence has an index
of 0
. For example:
my_str = "Hello, World!"
print(my_str[0])
## H
Python allows you to use negative indices to access elements from the
end of a sequence. -1
refers to the las t element,
-2
to the second last, and so on. For example:
my_list = [10, 20, 30, 40]
print(my_list[-1]) # Last element: 40
## 40
print(my_list[-2]) # Second last element: 30
## 30
You can retrieve multiple elements using slicing, which specifies a range of indices:
sequence[start:stop:step]
Where:
start
: The index of the first element to include (default is0
).stop
: The index where slicing ends (exclusive).step
: The interval between elements (default it1
).
For example:
my_list = [10, 20, 30, 40, 50]
print(my_list[1:4]) # Elements from index 1 to 3: [20, 30, 40]
## [20, 30, 40]
print(my_list[:3]) # First three elements: [10, 20, 30]
## [10, 20, 30]
print(my_list[::2]) # Every second element: [10, 30, 50]
## [10, 30, 50]
print(my_list[::-1]) # Reversed list: [50, 40, 30, 20, 10]
## [50, 40, 30, 20, 10]
Set Data Types
Set types represent unordered collections of unique elements. They are used for mathematical set operations and ensuring data uniqueness.
- Sets (
set
): Mutable collections of unique, unordered elements. Constructor for the type isset(iterable=[])
. For example:set([1, 1, 2, 3])
\(\rightarrow\){1, 2, 3}
. - Frozen Sets (
frozenset
): Immutable sets that can be used as dictionary keys or elements of other sets. Constructor for the type isfrozenset(iterable=[])
. For example:frozenset("abc")
\(\rightarrow\)frozenset({'a', 'b', 'c'})
.
Mapping Data Types
Mapping types store key-value pairs for fast lookups. Keys must be unique and hashable.
- Dictionaries (
dict
): Mutable collections of key-value pairs. Constructor for the type isdict(mapping_or_iterable)
. For example:dict([("name", "Alice"), ("age", 25)])
\(\rightarrow\){'name': 'Alice', 'age': 25}
.
Binary Data Types
Binary types are designed to handle raw binary data. They are useful for low-level operations such as file handling or network protocols.
- Bytes (
bytes
): Immutable sequences of bytes. Constructor for the type isbytes(source[, encoding[, errors]])
. For example:bytes("hello", "utf-8")
\(\rightarrow\)b'hello'
. - Byte Arrays (
bytearray
): Mutable sequences of bytes. Constructor for the type isbytearray(sequence[, encoding[], errors]])
. For example:bytearray("hello", "utf-8")
\(\rightarrow\)bytearray(b'hello')
- Memory Views (
memoryview
): Provides a view of another binary data type without copying data. Constructor for the type ismemoryview(obj)
. For example:memoryview(b'hello')
.
To check the data type of a variable or any other Python object, you
can use the type()
function. This function is frequently
employed for the purpose of debugging, along with the
print()
.
type(True) # Output: Boolean
## <class 'bool'>
type(5) # Output: integer
## <class 'int'>
type(12.345) # Output: float
## <class 'float'>
type('12.345') # Output: string
## <class 'str'>
type(print) # Output: builtin_function_or_method
## <class 'builtin_function_or_method'>
type(list) # Output: type
## <class 'type'>
The isinstance()
function, on the other hand, checks
whether an object belongs to a specific data type and returns
True
or False
. This function is particularly
useful for validating inputs or conducting unit tests.
isinstance(-11, int) # Checks if -11 is an instance of int
## True
isinstance(3.14, int) # Checks if 3.14 is an instance of int
## False
However, Google’s Python style guide recommends using four spaces. This ensures consistent formatting across different editors and environments.↩︎
The distinction between expressions and statements could be little ambiguous. For example, you can also think of
3 + 4
as a statement. This is called an expression statement, which evaluates and executes the expression. In essence, expressions are code snippets used to apply an operator and calculate a value, while statements are complete instructions that perform actions of a program.↩︎In Python, a variable can be mutable or immutable depending on its data type. Variables with mutable data types can be changed in place, meaning their content can be modified without creating a new object. Examples include lists, dictionaries, and sets. On the other hand, variables with immutable data types cannot be altered once created. Any modification attempt results in the creation of a new object. So, technically, for immutable data types like
int
, the created literal object cannot be modified. If you reassign the same variable name to the object, Python creates a new object and associate the variable name with it. You can verify this behavior using theid()
function, which returns the unique identifier of an object in the computer memory. If you apply the function to an immutable object, before and after reassignments, you’ll notice that the object IDs differ. This is because reassignment creates a new object rather than modifying the existing one. For mutable data types likelist
, however, the object itself can be modified without creating a new one.↩︎In Python, an iterable is any object capable of returning its members one at a time, allowing it to be looped over. Common examples include lists, strings, tuples, dictionaries, sets, and even file objects.↩︎