3 Python Concepts That Might Be Challenging for Newcomers
Learn these early on for a smoother coding journey.

Python is one of the most popular programming languages thanks to its clear syntax, powerful capabilities, and active community. It is being used in projects across a multitude of industries, with applications ranging from web development, data analysis, artificial intelligence, and more.
Despite its user-friendly nature, Python, like any language, presents a few nuances and concepts that can be challenging for newcomers.
In this article, we will delve into 3 such Python concepts, which are:
- Mutable versus immutable types
- The importance of indentation and scope
- List comprehensions
Understanding these fundamental concepts can greatly enhance your coding efficiency and effectiveness. We will be going through clear examples and highlighting common pitfalls.
Let’s start.
Mutable versus immutable types
In Python, some objects are mutable, which means they can be altered after they are created. Some examples of mutable types are lists and dictionaries. There are also immutable objects such as strings and tuples. They can’t be altered after they are created.
This difference can lead to unexpected behavior for newcomers. For example, when a mutable object is used as a default argument in a function, it can lead to what appears to be “persistent” state across function calls, which can be very confusing.
Let’s go over a couple of examples to demonstrate this case.
lst1 = [1, 2, 3, 4]
lst2 = lst1
lst2.append(5)
print(lst1)
# output
[1, 2, 3, 4, 5]
You might expect that lst1
to remain as [1, 2, 3, 4]
. However, since lists are mutable and lst1
and lst2
point to the same list, changes made through lst2
are reflected in lst1
.
Let’s do a similar example using strings, which are immutable.
str1 = "python"
str2 = str1
str2 += " is awesome"
print(str1)
# output
python
print(str2)
# output
python is awesome
We do not see the changes made to str2
reflected in str1
because strings are immutable.
Indentation and scope
In Python, the scope of loops, functions, and classes are determined by using indentation whereas many other languages use braces {}
or specific keywords to denote scope.
Understanding the effect of indentation on the control flow of a program is very important and can lead to unexpected results if not handled correctly.
Also, understanding the concept of scope (global vs. local scope) and how it affects the visibility of variables within different parts of a program can be challenging for beginners.
In the following example, the print statement is not indented properly so it is executed after the execution of the for loop. Hence, it only prints the final value of the variable x.
for i in [5, 10, 15, 20]:
x = i*2
print(x)
# output
40
If we want to print the value of x for each iteration in the loop, we need to write the print statement as follows:
for i in [5, 10, 15, 20]:
x = i*2
print(x)
# output
10
20
30
40
Let’s also go over a couple of examples to illustrate the difference of local and global scope.
x = 10 # global scope
def foo():
x = 5 # local scope
print(x) # prints: 5
foo()
print(x) # prints: 10
# output
5
10
You might expect the second print statement to output 5
, but the value of x inside the function foo
is a separate local variable, which does not affect the global variable x. Hence, when you call the function foo
, it prints the value of local x, which is 5. When you print the value of x outside the function, the output is 10.
Here is a slightly modified version of this code block:
x = 10 # global scope
def foo():
print(x) # prints: 10
foo()
print(x) # prints: 10
# output
10
10
In this example, we do not assign a value to variable x inside the function foo
. When we print the value of x inside the function, it first looks for a local variable x and since there is no x inside the function, it checks the global scope and prints the value of global x. Therefore, both print statements print 10.
List comprehension
List comprehensions are a powerful feature of Python, allowing more efficient execution thanks to vectorized operations. However, they can be quite hard to grasp for newcomers, especially for more complex ones with conditional logic or nested loops, which can be a challenge.
Understanding how to write and read list comprehensions is a great enhancement for your coding skills, and it’s also a Pythonic way of doing things, which can be quite different from how other languages handle similar tasks.
Here is an example that shows how to convert a for loop to a list comprehension.
# for loop
numbers = [5, 8, 10, 13, 24, 30]
even_numbers = []
for number in numbers:
if number%2==0:
even_numbers.append(number)
# same task with a list comprehension
numbers = [5, 8, 10, 13, 24, 30]
even_numbers = []
even_numbers = [number for number in numbers if number%2==0]
It checks each number in the numbers list and creates a new list that contains only the even numbers.
In the following example, the for loop iterates over a list of tuples, finds the maximum value in each tuple, and appends it to a list called max_values
.
# for loop
groups = [(13, 4, 20), (8, 11, 9), (5, 5, 7), (24, 8, 17)]
max_values = []
for group in groups:
max_values.append(max(group))
We can do the same task using a list comprehension as follows:
# list comprehension
groups = [(13, 4, 20), (8, 11, 9), (5, 5, 7), (24, 8, 17)]
max_values = [max(group) for group in groups]
Let’s do a final example that contains both a for loop and an if-condition.
# for loop
names = ["james", "jane", "matt", "ashley", "jennifer"]
j_names = []
for name in names:
if name.startswith("j"):
j_names.append(name)
print(j_names)
# output
['james', 'jane', 'jennifer']
It checks the strings in the names
list and appends the ones starting with the letter j to the j_names
list. Here is how we do it using a list comprehension:
# list comprehension
names = ["james", "jane", "matt", "ashley", "jennifer"]
j_names = [name for name in names if name.startswith("j")]
print(j_names)
# output
['james', 'jane', 'jennifer']
Final words
In this article, we have learned about 3 key Python concepts that often pose challenges for beginners: mutable versus immutable types, understanding indentation and scope, and list comprehensions.
The examples help illustrate these concepts and how they come into play in Python programming. By recognizing common mistakes and misunderstandings, we can foster better coding habits and develop more robust programs.
Mastering these fundamentals early in your Python journey will not only enhance your learning process but also set a solid foundation for tackling more complex problems in the future.
You can become a Medium member to unlock full access to my writing, plus the rest of Medium. If you already are, don’t forget to subscribe if you’d like to get an email whenever I publish a new article.
Thank you for reading. Please let me know if you have any feedback.
More content at PlainEnglish.io.
Sign up for our free weekly newsletter. Follow us on Twitter, LinkedIn, YouTube, and Discord.