š Key Concepts Overview
| Concept | One-Line Definition |
|---|---|
| Function | A reusable, named block of code that runs when called |
| Parameter vs Argument | Parameter = name in definition. Argument = value passed at call time |
| Local variable | Exists only inside the function it's defined in |
| Global variable | Exists outside any function, accessible everywhere |
global keyword |
Lets a function modify a global variable |
return |
Sends a value back from the function and ends it |
*args |
Collects extra positional arguments into a tuple |
**kwargs |
Collects extra keyword arguments into a dict |
lambda |
A small, unnamed (anonymous) one-line function |
filter() |
Keeps only elements that satisfy a condition |
map() |
Applies an operation to every element |
reduce() |
Aggregates an iterable into a single value |
| Module | A .py file containing reusable functions/classes |
š§© Part 1 ā Why Functions?
# WITHOUT a function ā code duplicated everywhere
a, b = 10, 20
print(a + b)
str1 = input('Enter a string: ')
if str1 == str1[::-1]:
print('Palindrome')
# ... later in the program, same logic copy-pasted again ...
Functions exist to:
- Avoid repeating code (write once, call many times)
- Reduce program size
- Organize logic into reusable, testable units
def add(a, b):
c = a + b
print(c)
def is_palindrome():
str1 = input('Enter a string: ')
if str1 == str1[::-1]:
print('Palindrome')
else:
print('Not a Palindrome')
# Now reuse anywhere:
add(327, 46)
is_palindrome()
Two Types of Functions
| Type | Example |
|---|---|
| In-built (Python provides) |
print(), len(), type(), input()
|
| User-defined (you write) | def add(a, b): ... |
The 2 Components of Every Function
-
Function Definition ā written using
def, contains the logic. Does NOT run on its own. -
Function Call ā
function_name()ā this is what actually executes the code.
def add(): # ā definition (just creates it, doesn't run it)
print('Hello')
add() # ā call (THIS runs it)
ā ļø Don't Shadow Built-in Functions (Recap + New Example)
# ā DANGEROUS ā overwrites Python's built-in print/len
def print():
print('Hello') # this would now infinitely recurse / break
def len():
print('Hello')
len('Python') # ā TypeError ā len() no longer works as expected,
# it now expects ZERO arguments because you redefined it
Lesson: Never name your functions print, len, list, input, type, etc. ā you permanently break the built-in within that scope.
šÆ Parameterised vs Non-Parameterised Functions
# Non-parameterised ā takes no input, asks inside the function
def add():
a = int(input('Enter a number: '))
b = int(input('Enter the next number: '))
c = a + b
print(c)
# Parameterised ā takes input directly via parameters
def add1(x, y):
c = x + y
print(c)
add1(18, 46) # 18 and 46 are ARGUMENTS passed to PARAMETERS x and y
Parameter vs Argument ā exact definition:
| Term | Where it appears | Example |
|---|---|---|
| Parameter | In the function definition |
def add1(x, y): ā x, y
|
| Argument | In the function call |
add1(18, 46) ā 18, 46
|
def even_odd(x):
if x % 2 == 0:
print('Even')
else:
print('odd')
even_odd(37) # 'odd'
āļø DevOps-Flavoured Function Examples
def restart_service(service_name):
print(f"Restarting {service_name} service......")
print(f"{service_name} restarted successfully")
restart_service("nginx")
restart_service("Docker")
def check_disk_usage():
print("Checking disk usage...")
print("Disk usage is 75%")
# Real system command execution
import os
def check_disk():
os.system("df -h") # runs actual shell command
lists have .append() but strings do NOT ā str1.append('xyz') ā AttributeError. Strings are immutable, so there's no in-place method to add to them; use concatenation or += instead.
š Part 2 ā Local vs Global Variables
Local Variables
def add(a, b): # a, b, c are LOCAL ā only exist inside this function
c = a + b
print(c)
print(a) # ā NameError: name 'a' is not defined ā 'a' doesn't exist outside the function
print(c) # ā NameError ā same reason
Global Variables
x = 47 # global variable
y = 48 # global variable
def add1(x, y): # these x, y are LOCAL parameters ā shadow the global ones
c = x + y
print(c)
add1(x, y) # add1(47, 48) ā prints 95
print(x) # 47 ā global x is untouched, local x inside function was separate
Key rule: A local variable and a global variable can share the same name ā they are still two completely different variables. The function's local one "shadows" the global one only inside the function body.
Reading a Global Variable Inside a Function ā Works Fine
count = 10
def update1():
global count
print("Inside function:", count) # can READ global without 'global' keyword too
update1() # Inside function: 10
Modifying a Global Variable Without global ā Creates a NEW Local Variable
count = 10
def update():
count = 20 # this creates a NEW local 'count'
print("Inside function:", count) # Inside function: 20
update()
print(count) # 10 ā the GLOBAL count is untouched!
The global Keyword ā Actually Modify the Global Variable
count = 10
def update2():
global count # tells Python: use the OUTER 'count', don't create a local one
count = 20
print("Inside function:", count)
update2()
print(count) # 20 ā global count WAS modified this time
The #1 confusion point in this topic:
| Code | Effect on global variable |
|---|---|
count = 20 (no global) inside function |
Creates a separate LOCAL variable ā global untouched |
global count then count = 20
|
Modifies the actual GLOBAL variable |
ā©ļø Part 3 ā return Statement
Print vs Return ā The Critical Difference
def add1(x, y):
c = x + y
return c # sends value BACK to the caller
result1 = add1(10, 20) # result1 now HOLDS the value 30
print(result1) # 30
print(result1 ** 2) # 900 ā
ā can use the result further
def add2(x, y):
c = x + y
print(c) # just prints ā doesn't send value back
result2 = add2(10, 20) # prints 30, but returns nothing
print(result2) # None ā ļø ā function with no return gives None
print(result2 ** 2) # ā TypeError: unsupported operand for None
Golden Rule: Use print() inside a function only for display. Use return when you need to use the result later in your program (further calculations, conditions, storing in variables/lists).
return Terminates the Function Immediately
def add1(x, y):
c = x + y
return c
print('Hello') # ā ļø NEVER runs ā return already exited the function
def add2(x, y):
c = x + y
print('Hello') # runs FIRST ā this line is before return
return c
add2(10, 20) # prints 'Hello', then returns c (silently, unless captured)
Returning Multiple Values (as a Tuple)
def calc(x, y):
c = x + y
d = x - y
return c, d # returns BOTH ā Python packs them into a tuple
t = calc(20, 10)
print(t, type(t)) # (30, 10) <class 'tuple'>
Practical Functions ā Factorial & Prime Check
# Factorial
def factorial(n):
f = 1
for i in range(1, n + 1):
f *= i
return f
x = factorial(5)
print(x) # 120
# Prime check
def is_prime():
n = int(input('Enter a number: '))
if n < 2:
return False
for i in range(2, n):
if n % i == 0:
return False
else:
return True
print(is_prime())
š„ Part 4 ā Types of Arguments
1. Positional argument
2. Keyword argument
3. Default argument
4. Variable-length argument
a. *args ā variable positional args (tuple)
b. **kwargs ā variable keyword args (dict)
1. Positional Arguments ā Order Matters
def emp_details(name, age, salary):
print('Name :- ', name)
print('Age :- ', age)
print('Salary :- ', salary)
emp_details('Sourav', 25, 75000) # ā
correct order
emp_details('Sourav', 75000, 25) # ā ļø runs but WRONG ā age=75000, salary=25 (logic bug!)
emp_details(25, 75000, 'Sourav') # ā ļø runs but completely scrambled
emp_details('Sourav', 75000) # ā TypeError: missing required argument 'salary'
Rule: Number of arguments must exactly match number of parameters, and order determines which value goes to which parameter.
2. Keyword Arguments ā Name the Parameter Explicitly
emp_details('Sourav', 25, salary=75000) # ā
mix positional + keyword
emp_details('Sourav', age=25, salary=75000) # ā
all named after first
emp_details(salary=75000, age=25, name='Sourav') # ā
order doesn't matter when all keyworded
emp_details(salary=75000, age=25, Name='Sourav') # ā TypeError ā 'Name' ā 'name' (case-sensitive!)
emp_details(salary=75000, age=25, 'Sourav') # ā SyntaxError ā positional AFTER keyword not allowed
ā ļø Critical Rule: If mixing positional and keyword arguments, all positional arguments must come BEFORE any keyword arguments.
3. Default Arguments ā Fallback Value if Not Provided
def emp_details(name, age, salary, loc='Bangalore'): # loc has a default
print('Name :- ', name)
print('Age :- ', age)
print('Salary :- ', salary)
print('Location :- ', loc)
emp_details('Sourav', salary=75000, age=25) # loc defaults to 'Bangalore'
emp_details('Sourav', salary=75000, age=25, loc='Delhi') # loc overridden to 'Delhi'
DevOps relevance: Default arguments are everywhere ā region='ap-south-1', timeout=30, retries=3 ā sensible defaults that can be overridden when needed.
4. Variable-Length Arguments
def add(x, y):
return x + y
add(10, 38) # ā
works
add(37, 25, 58) # ā TypeError ā too many arguments, only 2 parameters defined
*args ā Variable Positional Arguments ā packed into a TUPLE
def xyz(*args):
print(args, type(args))
xyz(10, 49, 28, 'Python') # (10, 49, 28, 'Python') <class 'tuple'>
def add(*args):
c = sum(args)
return c
add(20, 49) # 69
add(18, 437, 28) # 483
add(37, 483, 746, 276, 373, 483, 27893) # works with ANY number of arguments
`kwargs` ā Variable Keyword Arguments ā packed into a DICT**
def abc(**kwargs):
print(kwargs, type(kwargs))
abc(a=10, b=20, c=30, d=40)
# {'a': 10, 'b': 20, 'c': 30, 'd': 40} <class 'dict'>
DevOps relevance: *args/**kwargs are everywhere in real tools ā e.g., Boto3 functions, Django views, decorators ā to accept flexible config without hardcoding every possible parameter.
ā” Part 5 ā Lambda (Anonymous Functions)
# Syntax: lambda arguments: expression
# Called immediately: (lambda arguments: expression)(call_arguments)
# Add two numbers
(lambda x, y: x + y)(20, 48) # 68
a = (lambda x, y: x * y)(20, 20)
print(a) # 400
# Conditional (ternary) inside lambda
(lambda a, b, c: a if a > b and a > c else b if b > a and b > c else c)(28, 37, 18)
# 37 ā finds the maximum of 3 numbers
(lambda x: 'Even' if x % 2 == 0 else 'Odd')(23)
# 'Odd'
When to use lambda: Quick, throwaway, single-expression functions ā especially as arguments to filter(), map(), reduce(), or sorted(key=...). NOT meant for complex multi-line logic (use a regular def for that).
š Part 6 ā filter(), map(), reduce()
filter() ā Keep Elements That Match a Condition
# filter(lambda argument: condition, iterable)
# Returns a filter OBJECT ā wrap with list() or tuple() to see values
# Manual for-loop equivalent (what filter replaces):
lst = [1,2,3,4,5,6,7,8,9,10]
lst1 = []
for i in lst:
if i % 2 == 0:
lst1.append(i)
print(lst1) # [2,4,6,8,10]
# Same thing with filter() ā one line
print(list(filter(lambda x: x % 2 == 0, lst))) # [2,4,6,8,10]
# DevOps example: flag high CPU usage servers
cpu_usage = [48, 27, 93, 14, 86]
high_cpu = list(filter(lambda x: x > 80, cpu_usage))
print(high_cpu) # [93, 86]
# Extract vowels from a string
str1 = 'ncihvewc cnoejife2oiyfecndlncjihuhew'
print(tuple(filter(lambda x: x.lower() in 'aeiou', str1)))
map() ā Apply an Operation to Every Element
# map(lambda argument: expression, iterable)
# Returns a map OBJECT ā wrap with list() or tuple()
# Manual for-loop equivalent:
lst = [1,2,3,4,5,6,7,8,9,10]
lst1 = []
for i in lst:
lst1.append(i**2)
print(lst1) # [1,4,9,16,25,36,49,64,81,100]
# Same with map() ā one line
print(list(map(lambda x: x**2, lst))) # [1,4,9,16,25,36,49,64,81,100]
# map() on heterogeneous list ā operation applies to EVERY element
lst = [1, 2, 3, 'Python', 4, 5, 6, 7, 'DevOps', 8, 9, 10]
print(list(map(lambda x: x*2, lst)))
# [2,4,6,'PythonPython',8,10,12,14,'DevOpsDevOps',16,18,20]
# Note: x*2 means NUMERIC doubling for numbers, STRING repetition for strings
# map() on a string ā applies to each character
str1 = "python"
print(list(map(lambda x: x*2, str1)))
# ['pp','yy','tt','hh','oo','nn']
filter() vs map() ā Core Difference:
| Function | Purpose | Output size |
|---|---|---|
filter() |
Keep only items matching a condition | ⤠original (may shrink) |
map() |
Transform every item | = original (same size) |
reduce() ā Aggregate to a Single Value
from functools import reduce # must import ā not built-in like filter/map
# reduce(lambda x, y: expression, iterable)
lst = [1,2,3,4,5,6,7,8,9,10]
res = reduce(lambda x, y: x + y, lst)
print(res) # 55 ā sum of all elements
# Find minimum
reduce(lambda x, y: x if x < y else y, lst) # 1
# Find maximum
reduce(lambda x, y: x if x > y else y, lst) # 10
How reduce() works internally: It takes the first two elements, applies the lambda, takes that result + the next element, applies the lambda again ā repeating until one value remains.
š¦ Part 7 ā Modules
# A module = a .py file containing functions/classes
# Access with: module_name.function_name()
import Mod # imports Mod.py
Mod.greet() # calls greet() function inside Mod.py
Mod.adding(37, 27)
Mod.mul(37, 17)
Best practice: Don't put "free executable code" (code that runs immediately on import) inside a module ā only function/class definitions. This keeps the module reusable and side-effect-free when imported elsewhere.
DevOps relevance: This is exactly how you'd structure a utils.py or aws_helpers.py module with reusable functions like get_ec2_status(), restart_service(), parse_log() ā imported across multiple automation scripts.
āļø DevOps / Cloud Use Cases
# 1. Reusable service restart function with default region
def restart_service(service_name, region='ap-south-1'):
print(f"Restarting {service_name} in {region}...")
restart_service('nginx')
restart_service('nginx', region='us-east-1')
# 2. *args to accept any number of servers to health-check
def health_check(*servers):
for s in servers:
print(f'Checking {s}...')
health_check('web-01', 'web-02', 'db-01')
# 3. **kwargs to accept flexible AWS-style config
def launch_instance(**config):
print(config)
launch_instance(instance_type='t2.micro', region='ap-south-1', count=2)
# 4. filter() to find unhealthy servers
server_status = {'web-01': 200, 'web-02': 500, 'db-01': 200, 'cache-01': 503}
unhealthy = list(filter(lambda s: server_status[s] != 200, server_status))
print(unhealthy) # ['web-02', 'cache-01']
# 5. map() to convert a list of instance IDs into ARNs
instance_ids = ['i-001', 'i-002', 'i-003']
arns = list(map(lambda i: f'arn:aws:ec2:ap-south-1:123456789:instance/{i}', instance_ids))
print(arns)
# 6. reduce() to sum total monthly AWS costs across services
from functools import reduce
service_costs = [120.50, 45.25, 300.10, 15.00]
total = reduce(lambda x, y: x + y, service_costs)
print(f'Total monthly cost: ${total}')
# 7. global + counter pattern for tracking retries across calls
retry_count = 0
def attempt_connection():
global retry_count
retry_count += 1
print(f'Attempt #{retry_count}')
attempt_connection()
attempt_connection()
print(f'Total retries: {retry_count}')
ā Common Mistakes
| Mistake | Code | Fix |
|---|---|---|
Confusing print() and return
|
Function uses print(), then tries result = func() and uses result
|
Use return when you need the value later |
Forgetting global keyword |
count = 20 inside function ā global stays unchanged |
Use global count before modifying |
Code after return
|
Lines after return never execute |
Put cleanup/logging BEFORE return
|
| Positional after keyword | f(a=1, 2) |
All positional args must come first |
| Case-sensitive keyword names |
f(Name='x') when param is name
|
Match exact parameter name and case |
| Shadowing built-ins with function names | def len(): ... |
Never name functions after built-ins |
Forgetting list()/tuple() around filter/map
|
print(filter(...)) ā shows object, not values |
Wrap with list() or tuple()
|
Forgetting to import functools for reduce
|
reduce(...) ā NameError |
from functools import reduce |
String .append()
|
str1.append('x') |
Strings are immutable ā use += or concatenation |
šÆ Interview Points
"Difference between parameter and argument?"
ā Parameter is the variable name in the function definition. Argument is the actual value passed when calling the function."Difference between local and global variables?"
ā Local variables exist only inside the function where they're defined. Global variables are defined outside any function and accessible everywhere ā but a function can't modify a global variable without theglobalkeyword."What does the
globalkeyword do?"
ā It tells Python that an assignment inside a function should modify the OUTER (global) variable instead of creating a new local one."Difference between
print()andreturninside a function?"
āprint()just displays output to console ā the function still returnsNone.returnsends the value back to the caller so it can be stored or reused."What happens to code written after a
returnstatement?"
ā It never executes āreturnimmediately exits the function."Difference between
*argsand `kwargs?"**args
ācollects extra positional arguments into a tuple.*kwargs` collects extra keyword arguments into a dictionary."Difference between
filter()andmap()?"
āfilter()returns only the elements that satisfy a condition (output may be smaller).map()applies a transformation to every element (output is always the same size)."Why do you need to import
reducebut notfilter/map?"
āfilter()andmap()are built-in functions.reduce()lives in thefunctoolsmodule and must be explicitly imported."What is a lambda function and when would you use it?"
ā An anonymous, single-expression function ā used for short, throwaway logic, typically as an argument tofilter(),map(),reduce(), orsorted()."Can a function return multiple values?"
ā Yes ā Python packs them into a tuple automatically:return c, dā caller receives(c, d).
š Knowledge Base ā Quick Revision
# āā FUNCTION BASICS āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
def func_name(param1, param2): # definition
...
return value # optional
func_name(arg1, arg2) # call ā this is what executes it
# āā SCOPE āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
x = 10 # global
def f():
x = 20 # LOCAL ā does NOT affect global x
def g():
global x
x = 20 # modifies the actual global x
# āā ARGUMENT TYPES āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
def f(a, b): pass # positional
f(a=1, b=2) # keyword
def f(a, b=10): pass # default (b optional)
def f(*args): pass # variable positional ā tuple
def f(**kwargs): pass # variable keyword ā dict
# Rule: positional args must come BEFORE keyword args in a call
# āā RETURN VS PRINT āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
def f():
return 5 # value usable later: x = f()
def g():
print(5) # just displays; g() itself returns None
# āā LAMBDA āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
lambda x, y: x + y # basic
lambda x: 'Even' if x % 2 == 0 else 'Odd' # ternary inside lambda
# āā FILTER / MAP / REDUCE āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
list(filter(lambda x: condition, iterable)) # keep matching items
list(map(lambda x: expression, iterable)) # transform every item
from functools import reduce
reduce(lambda x, y: expression, iterable) # aggregate to ONE value
# āā MODULES āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
import module_name
module_name.function_name()
šļø Practice Questions
Easy
- Write a function
square(n)that takes a number and returns its square. Call it and print the result. - Write a function
greet(name, greeting='Hello')with a default argument. Call it once with just a name, and once overriding the greeting. - Use
lambdato write a one-line function that checks if a number is positive, negative, or zero.
Medium
- Write a function
total(*args)that accepts any number of numbers and returns their sum usingreduce(). - Demonstrate the difference between local and global scope: create a global variable
counter = 0, write a function that tries to increment it withoutglobal, show it fails to update, then fix it using theglobalkeyword. - Given
cpu_list = [45, 78, 92, 33, 88, 67], usefilter()to get servers with CPU > 70, andmap()to convert all values to strings with a%symbol (e.g.,'45%').
DevOps-Focused
-
Service Manager Function: Write a function
manage_service(action, service_name, region='ap-south-1')that prints a message like"Performing 'restart' on nginx in ap-south-1". Call it 3 times: once with all positional args, once with keyword args in different order, and once overriding the region. - Cost Calculator with reduce(): Given a list of dicts representing AWS services and their monthly costs:
services = [
{'name': 'EC2', 'cost': 120.50},
{'name': 'S3', 'cost': 45.25},
{'name': 'RDS', 'cost': 300.10},
]
Use map() to extract just the costs into a list, then use reduce() (with functools) to calculate the total. Print: "Total AWS monthly cost: $465.85".
Top comments (0)