Skip to content

Commit 8596ff4

Browse files
authored
Merge branch 'main' into Match-Case
2 parents fe4ce4a + ebaff12 commit 8596ff4

29 files changed

+2157
-1
lines changed

contrib/advanced-python/closures.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# Closures
2+
In order to have complete understanding of this topic in python, one needs to be crystal clear with the concept of functions and the different types of them which are namely First Class Functions and Nested Functions.
3+
4+
### First Class Functions
5+
These are the normal functions used by the programmer in routine as they can be assigned to variables, passed as arguments and returned from other functions.
6+
### Nested Functions
7+
These are the functions defined within other functions and involve thorough usage of **Closures**. It is also referred as **Inner Functions** by some books. There are times when it is required to prevent a function or the data it has access to from being accessed from other parts of the code, and this is where Nested Functions come into play. Basically, its usage allows the encapsulation of that particular data/function within another function. This enables it to be virtually hidden from the global scope.
8+
9+
## Defining Closures
10+
In nested functions, if the outer function basically ends up returning the inner function, in this case the concept of closures comes into play.
11+
12+
A closure is a function object that remembers values in enclosing scopes even if they are not present in memory. There are certain neccesary condtions required to create a closure in python :
13+
1. The inner function must be defined inside the outer function.
14+
2. The inner function must refer to a value defined in the outer function.
15+
3. The inner function must return a value.
16+
17+
## Advantages of Closures
18+
* Closures make it possible to pass data to inner functions without first passing them to outer functions
19+
* Closures can be used to create private variables and functions
20+
* They also make it possible to invoke the inner function from outside of the encapsulating outer function.
21+
* It improves code readability and maintainability
22+
23+
## Examples implementing Closures
24+
### Example 1 : Basic Implementation
25+
```python
26+
def make_multiplier_of(n):
27+
def multiplier(x):
28+
return x * n
29+
return multiplier
30+
31+
times3 = make_multiplier_of(3)
32+
times5 = make_multiplier_of(5)
33+
34+
print(times3(9))
35+
print(times5(3))
36+
```
37+
#### Output:
38+
```
39+
27
40+
15
41+
```
42+
The **multiplier function** is defined inside the **make_multiplier_of function**. It has access to the n variable from the outer scope, even after the make_multiplier_of function has returned. This is an example of a closure.
43+
44+
### Example 2 : Implementation with Decorators
45+
```python
46+
def decorator_function(original_function):
47+
def wrapper_function(*args, **kwargs):
48+
print(f"Wrapper executed before {original_function.__name__}")
49+
return original_function(*args, **kwargs)
50+
return wrapper_function
51+
52+
@decorator_function
53+
def display():
54+
print("Display function executed")
55+
56+
display()
57+
```
58+
#### Output:
59+
```
60+
Wrapper executed before display
61+
Display function executed
62+
```
63+
The code in the example defines a decorator function: ***decorator_function*** that takes a function as an argument and returns a new function **wrapper_function**. The **wrapper_function** function prints a message to the console before calling the original function which appends the name of the called function as specified in the code.
64+
65+
The **@decorator_function** syntax is used to apply the decorator_function decorator to the display function. This means that the display function is replaced with the result of calling **decorator_function(display)**.
66+
67+
When the **display()** function is called, the wrapper_function function is executed instead. The wrapper_function function prints a message to the console and then calls the original display function.
68+
### Example 3 : Implementation with for loop
69+
```python
70+
def create_closures():
71+
closures = []
72+
for i in range(5):
73+
def closure(i=i): # Capture current value of i by default argument
74+
return i
75+
closures.append(closure)
76+
return closures
77+
78+
my_closures = create_closures()
79+
for closure in my_closures:
80+
print(closure())
81+
82+
```
83+
#### Output:
84+
```
85+
0
86+
1
87+
2
88+
3
89+
4
90+
```
91+
The code in the example defines a function **create_closures** that creates a list of closure functions. Each closure function returns the current value of the loop variable i.
92+
93+
The closure function is defined inside the **create_closures function**. It has access to the i variable from the **outer scope**, even after the create_closures function has returned. This is an example of a closure.
94+
95+
The **i**=*i* argument in the closure function is used to capture the current value of *i* by default argument. This is necessary because the ****i** variable in the outer scope is a loop variable, and its value changes in each iteration of the loop. By capturing the current value of *i* in the default argument, we ensure that each closure function returns the correct value of **i**. This is responsible for the generation of output 0,1,2,3,4.
96+
97+
98+
For more examples related to closures, [click here](https://dev.to/bshadmehr/understanding-closures-in-python-a-comprehensive-tutorial-11ld).
99+
100+
## Summary
101+
Closures in Python provide a powerful mechanism for encapsulating state and behavior, enabling more flexible and modular code. Understanding and effectively using closures enables the creation of function factories, allows functions to have state, and facilitates functional programming techniques
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Understanding the `eval` Function in Python
2+
## Introduction
3+
4+
The `eval` function in Python allows you to execute a string-based Python expression dynamically. This can be useful in various scenarios where you need to evaluate expressions that are not known until runtime.
5+
6+
## Syntax
7+
```python
8+
eval(expression, globals=None, locals=None)
9+
```
10+
11+
### Parameters:
12+
13+
* expression: String is parsed and evaluated as a Python expression
14+
* globals [optional]: Dictionary to specify the available global methods and variables.
15+
* locals [optional]: Another dictionary to specify the available local methods and variables.
16+
17+
## Examples
18+
Example 1:
19+
```python
20+
result = eval('2 + 3 * 4')
21+
print(result) # Output: 14
22+
```
23+
Example 2:
24+
25+
```python
26+
x = 10
27+
expression = 'x * 2'
28+
result = eval(expression, {'x': x})
29+
print(result) # Output: 20
30+
```
31+
Example 3:
32+
```python
33+
x = 10
34+
def multiply(a, b):
35+
return a * b
36+
expression = 'multiply(x, 5) + 2'
37+
result = eval(expression)
38+
print("Result:",result) # Output: Result:52
39+
```
40+
Example 4:
41+
```python
42+
expression = input("Enter a Python expression: ")
43+
result = eval(expression)
44+
print("Result:", result)
45+
#input= "3+2"
46+
#Output: Result:5
47+
```
48+
49+
Example 5:
50+
```python
51+
import numpy as np
52+
a=np.random.randint(1,9)
53+
b=np.random.randint(1,9)
54+
operations=["*","-","+"]
55+
op=np.random.choice(operations)
56+
57+
expression=str(a)+op+str(b)
58+
correct_answer=eval(expression)
59+
given_answer=int(input(str(a)+" "+op+" "+str(b)+" = "))
60+
61+
if given_answer==correct_answer:
62+
print("Correct")
63+
else:
64+
print("Incorrect")
65+
print("correct answer is :" ,correct_answer)
66+
67+
#2 * 1 = 8
68+
#Incorrect
69+
#correct answer is : 2
70+
#or
71+
#3 * 2 = 6
72+
#Correct
73+
```
74+
## Conclusion
75+
The eval function is a powerful tool in Python that allows for dynamic evaluation of expressions.
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Filter Function
2+
3+
## Definition
4+
The filter function is a built-in Python function used for constructing an iterator from elements of an iterable for which a function returns true.
5+
6+
**Syntax**:
7+
```python
8+
filter(function, iterable)
9+
```
10+
**Parameters**:<br>
11+
*function*: A function that tests if each element of an iterable returns True or False.<br>
12+
*iterable*: An iterable like sets, lists, tuples, etc., whose elements are to be filtered.<br>
13+
*Returns* : An iterator that is already filtered.
14+
15+
## Basic Usage
16+
**Example 1: Filtering a List of Numbers**:
17+
```python
18+
# Define a function that returns True for even numbers
19+
def is_even(n):
20+
return n % 2 == 0
21+
22+
numbers = [1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
23+
even_numbers = filter(is_even, numbers)
24+
25+
# Convert the filter object to a list
26+
print(list(even_numbers)) # Output: [2, 4, 6, 8, 10]
27+
```
28+
29+
**Example 2: Filtering with a Lambda Function**:
30+
```python
31+
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
32+
odd_numbers = filter(lambda x: x % 2 != 0, numbers)
33+
34+
print(list(odd_numbers)) # Output: [1, 3, 5, 7, 9]
35+
```
36+
37+
**Example 3: Filtering Strings**:
38+
```python
39+
words = ["apple", "banana", "cherry", "date", "elderberry", "fig", "grape" , "python"]
40+
long_words = filter(lambda word: len(word) > 5, words)
41+
42+
print(list(long_words)) # Output: ['banana', 'cherry', 'elderberry', 'python']
43+
```
44+
45+
## Advanced Usage
46+
**Example 4: Filtering Objects with Attributes**:
47+
```python
48+
class Person:
49+
def __init__(self, name, age):
50+
self.name = name
51+
self.age = age
52+
53+
people = [
54+
Person("Alice", 30),
55+
Person("Bob", 15),
56+
Person("Charlie", 25),
57+
Person("David", 35)
58+
]
59+
60+
adults = filter(lambda person: person.age >= 18, people)
61+
adult_names = map(lambda person: person.name, adults)
62+
63+
print(list(adult_names)) # Output: ['Alice', 'Charlie', 'David']
64+
```
65+
66+
**Example 5: Using None as the Function**:
67+
```python
68+
numbers = [0, 1, 2, 3, 0, 4, 0, 5]
69+
non_zero_numbers = filter(None, numbers)
70+
71+
print(list(non_zero_numbers)) # Output: [1, 2, 3, 4, 5]
72+
```
73+
**NOTE**: When None is passed as the function, filter removes all items that are false.
74+
75+
## Time Complexity:
76+
- The time complexity of filter() depends on two factors:
77+
1. The time complexity of the filtering function (the one you provide as an argument).
78+
2. The size of the iterable being filtered.
79+
- If the filtering function has a constant time complexity (e.g., O(1)), the overall time complexity of filter() is linear (O(n)), where ‘n’ is the number of elements in the iterable.
80+
81+
## Space Complexity:
82+
- The space complexity of filter() is also influenced by the filtering function and the size of the iterable.
83+
- Since filter() returns an iterator, it doesn’t create a new list in memory. Instead, it generates filtered elements on-the-fly as you iterate over it. Therefore, the space complexity is O(1).
84+
85+
## Conclusion:
86+
Python’s filter() allows you to perform filtering operations on iterables. This kind of operation consists of applying a Boolean function to the items in an iterable and keeping only those values for which the function returns a true result. In general, you can use filter() to process existing iterables and produce new iterables containing the values that you currently need.Both versions of Python support filter(), but Python 3’s approach is more memory-efficient due to the use of iterators.

contrib/advanced-python/index.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
- [OOPs](oops.md)
44
- [Decorators/\*args/**kwargs](decorator-kwargs-args.md)
5+
- ['itertools' module](itertools.md)
6+
- [Type Hinting](type-hinting.md)
57
- [Lambda Function](lambda-function.md)
68
- [Working with Dates & Times in Python](dates_and_times.md)
79
- [Regular Expressions in Python](regular_expressions.md)
@@ -10,4 +12,9 @@
1012
- [Protocols](protocols.md)
1113
- [Exception Handling in Python](exception-handling.md)
1214
- [Generators](generators.md)
13-
- [Match Case Statement](match_case_statement.md)
15+
- [Match Case Statement](match_case_statement.md)
16+
- [Closures](closures.md)
17+
- [Filter](filter-function.md)
18+
- [Reduce](reduce-function.md)
19+
- [List Comprehension](list-comprehension.md)
20+
- [Eval Function](eval_function.md)

0 commit comments

Comments
 (0)