Added Refresher Functions

This commit is contained in:
gparidhi51 2024-03-28 12:11:55 +05:30 committed by GitHub
parent 8a939e4210
commit 6d8ff5ca21
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -0,0 +1,601 @@
# Refresher: Functions
### Recap
* DRY RUN - Running code line by line, we run the code just like the compiler does without using human intelligence.
* Loops - instead of writing the code multiple times, we use loops to perform the same task
* Nested Loops - These are loops inside loops.
* We usually use `i` for rows and `j` for columns.
---
### QUIZ 1
What will the sequence be generated by the following?
```c
range(-5,0,1)
```
### Choices
- [ ] -5,-4,-3,-2,-1,0
- [ ] Nothing
- [ ] 0,-1,-2,-3,-4,-5
- [x] -5,-4,-3,-2,-1
---
### QUIZ 2
What will the sequence be generated by the following?
```c
range(-10,-5,-1)
```
### Choices
- [ ] -10,-9,-8,-7,-6,-5
- [ ] -10,-9,-8,-7,-6
- [x] Nothing
- [ ] -6,-7,-8,-9,-10
---
### QUIZ 3
What will be the output of the following?
```cpp
for i in range(1,10):
if(i % 3 == 0):
break
print(i, end = ' ')
```
### Choices
- [ ] 1 2 3 4 5 6 7 8 9
- [x] 1 2
- [ ] 1 2 4 5 7 8 9
- [ ] 1 2 4 5 6 7 8
---
### QUIZ 4
What will be the output of the following?
```cpp
for i in range(0,4):
for j in range(0,i):
print('a', end = '')
print()
```
### Choices
- [ ] a
aa
aaa
- [x] aaaa
aaaa
aaaa
aaaa
- [ ] aaa
aa
a
---
## Need for functions
<img src="https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/068/628/original/upload_6b000fa46e9e4e2cfb7a880d2397b9ee.jpg?1711016664" width=500 />
* We are working at a banking facility. We are to code the receipt that is printed after the ATM transaction. It is something like:
```cpp
******************
Transaction Complete
Thank you for visiting
******************
```
so we will write the code for this:
```python
print('*' * 5)
print("Transaction complete")
print("Thank you for visiting")
print('*' * 5)
```
* Now for every type of transaction same message will be printed. And for every transaction contained in the big file of 10000 lines of code, we have the same 4 lines for different transactions.
* This is not following the DRY(Do not repeat yourself) principle. Which is a bad practice.
* Let us say the back says they don't want to print `thank you` they wish to print `thanks` instead. So we will have to update it at all the places separately.
* Functions are like alias - I can write a line of code and I can name it `abc`. Everywhere I can call abc the same piece of code will be executed.
* Functions make code modular.
* Now if there are any changes, we change it in one place and it will reflect in all the other places.
## Syntax of Defining a Function
**Defining a function**
```python
def function_name():
# actions
```
**To Call the function**
```python
function_name()
```
<img src="https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/068/629/original/upload_b7ac907afcf96335954b43b7261fffb8.jpg?1711017155" width=500 />
* The naming convention for a function is the same as variables.
* It should be composed of alphabet, number, and underscore
* should start with an alphabet or underscore
* It should not be a keyword
* In Python we use snake case. (there are two cases camel case and snake case).
## Return Statement
* Functions not only put some code in a block they return something.
* Example function
```python
def area_circle_rad_5(){
print(3.14 * 5 * 5)
}
area_circle_rad_5()
```
**Output**
```plaintext
78.5
```
* This is how we define a function and call it. Now we want to add `1` to it or `2` to it. Can't we take it to a variable?
* This is what return statements are for. It is like a black box where you want some task to be done. But after the task is done you want it to return some value as well.
* So the syntax is something like:`
```python
def function_name():
return 5;
abc()
a = abc()
print(a)
```
**Output**
```plaintext
5
```
* We are storing the return value of the function in a variable `a`. Now we can print this variable as usual.
* Unlike other programming languages in Python we are not required to define the return type with the function name.
<img src="https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/068/630/original/upload_ae1b2652f049d3b49fca0fee9f86188b.png?1711017411" width=500 />
**Note:** Functions execution ends at return. Once a return statement is found rest of the lines of the code will not be executed. It is just like a break in loops.
If you do return without any value, it will return `None`.
```python
def abc():
return
abc()
```
## Parameter and Argument in Function
* Let us say we want to calculate the area of a circle whose radius `10`. We will again write the code as
```python
def area_circle_rad_10():
print(3.14 * 10 * 10)
```
* So for every different radius we will write a different code? This is not a good practice.
* In Python we can take as many parameters as required. So we can simply take radius as a parameter from the use.
```python
def area_circle(radius):
return (3.14 * (radius ** 2))
area = area_circle(5)
```
* If you want multiple parameters you can simply separate them by comma, their types are not required.
* If the function is not returning anything by default it will return `None`.
* In Python, a parameter is a variable used in a function definition, while an argument is an actual value passed to the function during a call.
* About the above function `radius` used in the `area_circle()` function is a parameter, the `5` passed to it while calling is an argument.
* But people use it interchangeably.
## Execution of A Function in Python
* Python compiler executes line-by-line
* Everything in Python is an object of a class.
* Function is also a class.
* Function is just like a variable, a variable gets declared in a single line, and functions get declared in multiple lines.
* In Python if you call a function without defining it, it will show an error.
* We can call a function inside a function.
* Let us say we have a bank function to do transactions for saving accounts. We have multiple functions to check the balance, to execute the transaction, to print the thank you message, etc.
## Scope of a Variable
```python
a = 1
def arae_circle(radius):
area = 3.14 * (radius ** 2)
return area
b = area_circle(10)
print(a)
print(area)
print(b)
```
* Whatever we have done so far, we have done it in global scope.
* Here `a` and `b` are global variables. But `area` is a local variable to the function `area_circle`. It can only be accessed in the function. As the execution of the function is over the Python compiler frees up the memory. Thus `area` is no longer a valid memory location.
* Though we can do this:
```python
a = 1
def arae_circle(radius):
area = 3.14 * (radius ** 2)
print(a)
return area
b = area_circle(10)
print(a)
print(area) # this will give error
print(b)
```
* This is because `a` is a global variable and can be accessed everywhere.
<img src="https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/068/631/original/upload_41ba15091ecbf33a56f68319d2098e4c.png?1711017589" width=500 />
* In Python variables defined in `if` or `for` loops can be used outside their block as well but it is not true for the functions.
```python
a = 1
def abd():
a = 2
print(a)
abc()
```
**Output**
```plaintext
2
1
```
* So, this will have two variables called `a`. One is global and another is local. When we say `print(a)` it will refer to the local variable and print its value.
* To update or use global we use the following syntax:
```python
a = 1
def abc():
global a
a = 2
print(a)
abc()
print(a)
```
**Output**
```plaintext
2
2
```
Here global variable `a` is reused and its value is changed inside a function.
---
### QUIZ 5
Is this a valid function?
```python
def print_hello:
print('Hello')
```
### Choices
- [ ] Yes
- [x] No
There are no paranthesis in the function and they are must in a function.
```python
def print_hello():
print('Hello')
```
---
### QUIZ 6
Is this a valid function?
```python
def print_name():
print('Hello', name)
```
# Choices
- [ ] Yes
- [x] No
The variable name must be taken as an argument.
---
### QUIZ 7
How many times the function foo is called?
```python
foo()
foo()
for i in range(1,5):
foo()
```
### Choices
- [ ] 5
- [x] 6
- [ ] 7
- [ ] 8
---
### QUIZ 8
What will be the output of the following?
```python
def area_rectangle(l, b):
area = l * b
area_circle(3, 4)
print(area)
```
# Choices
- [ ] 12
- [ ] 7
- [x] Error
---
There is no function named `area_cirle()`.
### QUIZ 9
What will be the output of the following?
```python
def foo(a):
if(a):
return 100
a += 20
return a
print(foo(0))
```
### Choices
- [ ] 100
- [ ] 120
- [x] 20
- [ ] Nothing
A function's execution ends once a `return` is encountered.
If you do return without any value, it will return None. Though this is not helpful it is still valid.
```python
def abc():
return
abc()
```
### QUIZ 10
What will be the output of the following?
```python
def solve(a, b):
print('Function Started')
return 0
c = a + b
print('Function Ends')
c = solve(2, 3)
print(c)
```
### Choices
- [ ] Function Started
Function Ends
5
- [ ] Function Started
Function Ends
0
- [ ] Function Started
0
Function Ends
- [x] Function Started
0
We are doing early exit via return `0` and therefore the result is `0`.
## Positional and Keyword Arguments
Let us consider an example:
```python
def bio_data(name, age, gender):
print("Name: ", name)
print("Age: ", age)
print("Gender: ", gender)
bio_data(23, "Male", "Aakar")
```
#### **`What is the problem with the above code?`**
* **The order of the parameter matters**, age will printed with the name, and so on
* Python has two types of arguments **Positonal** and **Keyword**.
* The above function call is referred to as positional arguments. Where order or position of arguments matters.
* The other one is keyword argument. Here we have to give the name of the argument but the order doesn't matter.
* The name must be the same as given in the function definition.
```python
bio_data(name = "Aakar", gender = "Male", age = 23)
```
**Note:** A single call can have both together, but the Keyword argument must always be after positional arguments. Python will show an error if not done this way.
**Cannot Do**
```python
bio_data("Aakar", age = 23, "Male")
```
**Must Do**
```python
bio_data("Aakar", age = 23,gender = "Male")
```
## Default and Non-default Arguments
* Let us say we are writing the above function. For example, people don't like having to declare their gender. So, we can give the default argument gender with the value `Unspecified` in Python.
```python
def bio_data(name, age, gender = "Unspecified"):
print("Name: ", name)
print("Age: ", age)
print("Gender: ", gender)
bio_data(23, "Aakar")
```
Now, it is both ways okay even if we define or do not define the argument.
**Note:** A single call can have both together, but the Non-default argument must always be after default arguments. Python will show an error if not done this way.
**Cannot Do**
```python
bio_data(name, age = 23, gender)
```
**Must Do**
```python
def bio_data(name, age, gender = "Unspecified"):
```
### QUIZ 11
What is the correct way of calling this function?
```python
def print_biodata(name, age, gender):
print('Name', name)
print('Age', age)
print('Gender', gender)
```
### Choices
- [ ] print_biodata('Hari', 'Male', 23)
- [ ] print_biodata('Male', 'Hari', 23)
- [x] print_biodata('Hari', 23, 'Male')
- [ ] print_biodata(23, 'Hari', 'Male')
---
### QUIZ 12
What will be the output of the following?
```python
def print_biodata(name, age = 23, gender = 'Female'):
print('Name', name)
print('Age', age)
print('Gender', gender)
```
### Choices
- [x] Yes
- [ ] No
First there should be non-default arguments and then the default arguments.
### QUIZ 13
Which of the function call is correct?
```python
def print_biodata(name, age = 23, gender = 'Female'):
print('Name', name)
print('Age', age)
print('Gender', gender)
```
### Choices
- [ ] `print_biodata(name='Hari', 23)`
- [ ] `print_biodata('Hari', 23, age=23)`
- [x] `print_biodata('Hari')`
- [ ] `print_biodata()`
* 1st option - `name` is a keyword argument and the age is a positional argument. Positional argument cannot come after keyword argument.
* 2nd option - In the above quiz we are defining age twice which is not valid.
* 3rd argument - Rest two arguments are default
* 4th option - We still need name argument as name is not a default argument.
* `*args` - opens a list/tuple (arguments)
* **`kwags` - opens a dictionary (keyword arguments)
* `*` is used for opening a single-dimension iterator.
* Let us say there exists a function that takes an unspecified number of parameters.
* This can be achieved with the help of `*args` and `**kwargs`. This lets us pass as many arguments as we want.
```python
def abc(a, b, *args, **kwargs):
print(a, b)
print(args)
print(kwargs)
abc(2,3,4,5, name = "Hari",age = 23)
```
**Output**
```plaintext
2 3
[4, 5]
{"name" : "Hari"
"age" : 23}
```
* You cannot have more than one `*args` or `**kwargs` as their behavior of it is unspecified.
## Docstrings
* Python provides a special functionality **doc strings** just like comments but slightly different than multiline comments.
* If someone wants to know how the function works they have to come to the code and see. So many Python code readers and default Python provides a documentation of functions and classes and these are called **Doc String**
* You have to write a multiline comment right after the function definition.
```python
def bio_data(name, age, gender = "Unspecified"):
"""
This function prints the bio-data using the information provided
Args:
name
age
gender
Returns:
None
"""
print("Name: ", name)
print("Age: ", age)
print("Gender: ", gender)
```
To read the doc string, just add a `?` after it.
```python
bio_data?
```
## Question - Simple Interest
* Take two parameters, how much they want to invest, and how long they want to invest it for.
* Simple interest - 7%.
* Write a function `print_interest`
```python
si = 7
principal = int(input("How much you want to invest>"))
time = float(input("How long you want to invest it for (in years)?"))
def print_interest(principle, time):
result = principle * time * si / 100
return result
result = print_interest(principle, time)
print(result)
```
### Question - Simple Interest
* **Round function** in Python rounds the number. It takes the number and the precision we want. It rounds off this number and returns it.
```python
round(3.1415,2) -> 3.14
```
* Given a radius `R`, print the area of a circle but up to two decimal places only.
```python
PI = 3.14159
def print_area(radius):
area = PI * (radius ** 2)
result = print_area(5)
print(result)
```