Understanding The 10 Most Difficult Python Concepts - by Joanna - Geek Culture

Download as pdf or txt
Download as pdf or txt
You are on page 1of 24

This member-only story is on us. Upgrade to access all of Medium.

Member-only story

Understanding the 10 Most Difficult


Python Concepts
Joanna · Follow
Published in Geek Culture
8 min read · Apr 4

Listen Share More

Python has a simple syntax and is easy to learn, making it an ideal choice
for beginners. However, as you delve deeper into Python, you may
encounter some challenging concepts that can be difficult to understand.

In this article, I will explain the 10 most difficult Python concepts including
recursion, generators, decorators, object-oriented programming, threading,
exception handling, *args and **kwargs, functional programming,
comprehensions, and collections.

1. Recursion
Recursion is a technique in programming where a function calls itself
repeatedly until a certain condition is met. In Python, recursive functions
are functions that call themselves within their own code block.
Here is an example of a recursive function in Python that calculates the
factorial of a number:

def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n-1)

In this example, the function factorial() takes an argument n and checks


if it's equal to zero. If n is zero, it returns 1 because the factorial of 0 is 1. If
n is not zero, it calls itself with the argument n-1 and multiplies the result
with n . This continues until n becomes 0 and the function returns the final
result.
2. Generators
Generators are functions that produce a sequence of results, but don’t create
a list. They can be more memory-efficient than lists.

Specifically, generators are created using a special kind of function called a


generator function. These functions are defined like regular functions, but
instead of returning a value, they use the “yield” keyword to return a
generator object. The generator object can then be used in a loop to
produce values one at a time, as needed.

def my_generator():
for i in range(10):
yield i

for num in my_generator():


print(num)

# Output
# 0
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9

In this example, the my_generator function generates a sequence of


numbers from 0 to 9. When the function is called, it returns a generator
object that can be used to iterate over the values of the sequence.
3. Decorators
Decorators are functions that modify the behavior of other functions. One
of the most common uses of decorators is to add functionality to existing
functions without modifying the original code.

In Python, decorators are functions that take another function as an


argument, modify it, and return it. They are written with the “@” symbol
followed by the name of the decorator function.

def my_decorator(func):
def wrapper():
print("Before the function is called.")
func()
print("After the function is called.")
return wrapper

@my_decorator
def say_hello():
print("Hello World!")

# Call the decorated function


say_hello()

# Output:
# Before the function is called.
# Hello World!
# After the function is called.

In this example, my_decorator is a decorator function that takes a function


as its argument and returns a new function wrapper . The wrapper function
adds some extra functionality before and after the original function is
called.

The @my_decorator syntax is a shorthand way of applying the my_decorator


function to the say_hello function. When say_hello is called, it is actually
calling the wrapper function returned by my_decorator , which in turn calls
the original say_hello function. This allows us to add additional behavior to
the say_hello function without modifying its code directly.
4. Object-Oriented Programming
Python is an object-oriented programming (OOP) language. OOP is a
programming paradigm that emphasizes the use of objects and classes to
organize and structure code.

OOP is about creating reusable code by creating reusable code using classes.
Objects are essentially instances of a class and are equipped with both
attributes (data) and methods (functions) that define their behavior.

To create a class in Python, you use the class keyword, followed by the
name of the class and a colon. Inside the class, you define its attributes and
methods using functions.

For example, let’s say we want to create a class called Person that has a
name attribute and a greet method that prints a greeting message. We can
define it like this:

class Person:
def __init__(self, name):
self.name = name

def greet(self):
print("Hello, my name is", self.name)
# Create a new Person object with the name John
person = Person("John")
print(person.name) # John
person.greet() # Hello, my name is John
5. Threading
Threading is a technique used to execute multiple threads concurrently. It
can significantly improve the performance of the program. Here’s an
example:

import threading

def print_numbers():
for i in range(1, 11):
print(i)

def print_letters():
for letter in ['a', 'b', 'c', 'd', 'e']:
print(letter)

thread1 = threading.Thread(target=print_numbers)
thread2 = threading.Thread(target=print_letters)

thread1.start()
thread2.start()

thread1.join()
thread2.join()

print('Finished')

In this example, we define two functions print_numbers and print_letters


that simply print some numbers and letters to the console, respectively. We
then create two Thread objects, passing the target functions as arguments,
and start them using the start() method. Finally, we use the join()
method to wait for both threads to finish before printing "Finished" to the
console.

6. Exception Handling
6. Exception Handling
Exception handling is the process of handling runtime errors or exceptions
that may occur in a program during its execution. Python provides a
mechanism to catch and handle exceptions that occur during program
execution, ensuring that the program can continue running even if an error
occurs.

try:
numerator = int(input("Enter numerator: "))
denominator = int(input("Enter denominator: "))
result = numerator / denominator
print("Result: ", result)
except ZeroDivisionError:
print("Error: Cannot divide by zero!")
except ValueError:
print("Error: Invalid input. Please enter an integer.")
except Exception as e:
print("An error occurred:", e)

In this example, the try block contains the code that may raise an
exception. If an exception is raised, it will be caught by the corresponding
except block.

By using exception handling, we can handle errors in our code and prevent
the program from crashing. It provides feedback to the user and takes
appropriate actions based on the type of error that occurred.
7. *args and **kwargs
In Python, *args and **kwargs are used to pass an unspecified number of
arguments to a function. So when writing the function definition, you do
not have to know how many arguments will be passed to the function.

*args is used to pass a variable number of non-keyword arguments to a


function. The * operator is used to unpack the arguments passed to the
function into a tuple. This allows you to pass any number of arguments to a
function.

def my_function(*args):
for arg in args:
print(arg)
my_function('hello', 'world', '!')

# Output:
# hello
# world
# !

**kwargs is used to pass a variable number of keyword arguments to a


function. The ** operator is used to unpack the keyword arguments passed
to the function into a dictionary. This allows you to pass any number of
keyword arguments to a function.

def my_function(**kwargs):
for key, value in kwargs.items():
print(key, value)

my_function(name='John', age=30, city='New York')

# Output:
# name John
# age 30
# city New York

8. Functional programming
Functional programming is a programming paradigm that emphasizes the
use of functions to solve problems. Python provides support for functional
programming through several built-in functions and features, including
lambda functions, map(), filter(), and reduce().

Lambdas are one-line functions.


# A lambda function to square a number
square = lambda x: x**2

# Using the lambda function


print(square(5)) # Output: 25

map() applies a function to each element of an iterable and returns a new


iterable containing the results.

nums = [1, 2, 3, 4, 5]
squared_nums = list(map(lambda x: x**2, nums))
print(squared_nums) # Output: [1, 4, 9, 16, 25]

filter() creates a list of elements for which a function returns true.

nums = [1, 2, 3, 4, 5]
even_nums = list(filter(lambda x: x % 2 == 0, nums))
print(even_nums) # Output: [2, 4]

reduce() applies a function to the elements of an iterable in a cumulative


way and returns a single value.

from functools import reduce

nums = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x*y, nums)
print(product) # Output: 120
9. Comprehensions
In Python, comprehension is a concise and efficient way to create a new
list, dictionary, or set from an iterable object by applying a transformation
or filtering condition to its elements.

List comprehension:

# Create a list of squares for the first 10 positive integers


squares = [x**2 for x in range(1, 11)]
print(squares)

# Output: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]


Dictionary comprehension:

# Create a dictionary with keys from a list and values as the length of each key
fruits = ['apple', 'banana', 'kiwi', 'mango']
fruit_lengths = {fruit: len(fruit) for fruit in fruits}
print(fruit_lengths)

# Output: {'apple': 5, 'banana': 6, 'kiwi': 4, 'mango': 5}

Set comprehension:

# Create a set of all even numbers between 1 and 20


evens = {x for x in range(1, 21) if x % 2 == 0}
print(evens)

# Output: {2, 4, 6, 8, 10, 12, 14, 16, 18, 20}

Generator comprehension:

# Create a generator that yields the square of each number from 1 to 10


squares_gen = (x**2 for x in range(1, 11))
for square in squares_gen:
print(square)

# Output:
# 1
# 4
# 9
# 16
# 25
# 36
# 49
# 64
# 81
# 100
10. Collections
In Python, the collections module provides alternatives to built-in types
that are more efficient and offer additional functionality, such as counters,
default dictionaries, and named tuples.
Open in app
The Counter class in the collections module is used to count the
occurrences of elements in a list.

from collections import Counter

lst = ['apple', 'banana', 'cherry', 'apple', 'cherry', 'cherry']


count = Counter(lst)

print(count)
# Output: Counter({'cherry': 3, 'apple': 2, 'banana': 1})
print(count['cherry'])
# Output: 3

Defaultdict class is a subclass of the built-in dict class that provides a


default value for missing keys.

from collections import defaultdict

d = defaultdict(int)

d['a'] = 1
d['b'] = 2

print(d['a'])
# Output: 1

print(d['c'])
432 1
# Output: 0 (default value for missing keys is 0 because of int argument)

The namedtuple class is used to create named tuples, which are like regular
tuples, but the fields are named, making it easier to access them.

from collections import namedtuple

Person = namedtuple('Person', ['name', 'age', 'gender'])


p1 = Person(name='Alice', age=30, gender='Female')
p2 = Person(name='Bob', age=25, gender='Male')

print(p1.name)
# Output: Alice

print(p2.age)
# Output: 25
Thanks for reading, and I hope this article has helped you gain a better
understanding of the most challenging Python concepts!

Python Python Programming Data Science Programming Oop

Follow

Written by Joanna
574 Followers · Writer for Geek Culture

Data Scientist, Technical Product Manager | Python, R, ML, DL, RecSys, RL

More from Joanna and Geek Culture


Joanna

8 Python Libraries for Time-Series Analysis [with Code Examples]


Time series analysis involves examining data points collected over time, with the goal
of identifying patterns and trends that can inform…

· 5 min read · Apr 6

262 1

Jacob Bennett in Geek Culture

The 5 paid subscriptions I actually use in 2023 as a software


engineer
Tools I use that are cheaper than Netflix

· 4 min read · Mar 25


· 4 min read · Mar 25

4.1K 38

Mohit Malhotra in Geek Culture

Why gRPC is the future of software architecture


Discussion about advantages of choosing gRPC over REST based architecture

· 4 min read · Mar 11

887 20
Joanna in Stackademic

apply(), lappy(), sapply(), tapply(), and mapply() in R


In this article, we will discuss functions in R apply family. They allow you to apply
function operations to vectors, matrices, and data…

· 3 min read · Aug 7

124

See all from Joanna

See all from Geek Culture

Recommended from Medium


The PyCoach in Artificial Corner

Python in Excel Will Reshape How Data Analysts Work


Microsoft just announced Python in Excel. Here’s how it’ll change the way Python and
Excel analysts work.

· 5 min read · 4 days ago

1.1K 19

Salvatore De Luca in Stackademic

Python: Unleashing the Magic (1—Decorators)


A series dedicated to Python underrated and overlooked features

7 min read · Jul 9

99 2
Lists

Coding & Development


11 stories · 129 saves

Predictive Modeling w/ Python


20 stories · 313 saves

New_Reading_List
174 stories · 83 saves

General Coding Knowledge


20 stories · 251 saves

Saikat Dutta in Data Engineer Things

How to Create First Data Engineering Project? An Incremental


Project Roadmap
Build Data Engineering projects in this incremental approach for guaranteed success.
Break tutorial hell and stop procrastinating..

15 min read · Aug 21


15 min read · Aug 21

448 5

Maksym Bekuzarov in Better Programming

Python Profiling—Why and Where Your Code is Slow


Pinpoint your bottlenecks with these powerful tools

11 min read · May 12

1K 11
Prathamesh Gadekar

Seaborn charts that every Data Scientist Knows!


Seaborn charts that every Data Scientist Knows!

7 min read · Apr 3

196

Avi Chawla in Towards Data Science

It’s Time to Say GoodBye to pd.read_csv() and pd.to_csv()


Discussing another major caveat of Pandas

4 min read · May 26, 2022

2.5K 49
See more recommendations

You might also like