Functions, Scope (Local/Global), Arguments, return, Lambda, filter()/map()/reduce(), Modules

μž‘μ„±μž

μΉ΄ν…Œκ³ λ¦¬:

← ν”Όλ“œλ‘œ
DEV Community · Tejas Shinkar · 2026-06-21 개발(SW)

πŸ“Œ 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 ...

Enter fullscreen mode Exit fullscreen mode

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()

Enter fullscreen mode Exit fullscreen mode

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

  1. Function Definition β€” written using def, contains the logic. Does NOT run on its own.
  2. 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)

Enter fullscreen mode Exit fullscreen mode

⚠️ 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

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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'

Enter fullscreen mode Exit fullscreen mode

☁️ 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

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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!

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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)

Enter fullscreen mode Exit fullscreen mode

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'>

Enter fullscreen mode Exit fullscreen mode

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())

Enter fullscreen mode Exit fullscreen mode

πŸ“₯ 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)

Enter fullscreen mode Exit fullscreen mode

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'

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

⚠️ 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'

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

*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

Enter fullscreen mode Exit fullscreen mode

`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'>

Enter fullscreen mode Exit fullscreen mode

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'

Enter fullscreen mode Exit fullscreen mode

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)))

Enter fullscreen mode Exit fullscreen mode

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']

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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)

Enter fullscreen mode Exit fullscreen mode

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}')

Enter fullscreen mode Exit fullscreen mode

❌ 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

  1. “Difference between parameter and argument?”
    β†’ Parameter is the variable name in the function definition. Argument is the actual value passed when calling the function.

  2. “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 the global keyword.

  3. “What does the global keyword do?”
    β†’ It tells Python that an assignment inside a function should modify the OUTER (global) variable instead of creating a new local one.

  4. “Difference between print() and return inside a function?”
    β†’ print() just displays output to console β€” the function still returns None. return sends the value back to the caller so it can be stored or reused.

  5. “What happens to code written after a return statement?”
    β†’ It never executes β€” return immediately exits the function.

  6. “Difference between *args and `kwargs?"**
    β†’
    args collects extra positional arguments into a tuple. *kwargs` collects extra keyword arguments into a dictionary.

  7. “Difference between filter() and map()?”
    β†’ 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).

  8. “Why do you need to import reduce but not filter/map?”
    β†’ filter() and map() are built-in functions. reduce() lives in the functools module and must be explicitly imported.

  9. “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 to filter(), map(), reduce(), or sorted().

  10. “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()

Enter fullscreen mode Exit fullscreen mode

πŸ‹οΈ Practice Questions

Easy

  1. Write a function square(n) that takes a number and returns its square. Call it and print the result.
  2. Write a function greet(name, greeting='Hello') with a default argument. Call it once with just a name, and once overriding the greeting.
  3. Use lambda to write a one-line function that checks if a number is positive, negative, or zero.

Medium

  1. Write a function total(*args) that accepts any number of numbers and returns their sum using reduce().
  2. Demonstrate the difference between local and global scope: create a global variable counter = 0, write a function that tries to increment it without global, show it fails to update, then fix it using the global keyword.
  3. Given cpu_list = [45, 78, 92, 33, 88, 67], use filter() to get servers with CPU > 70, and map() to convert all values to strings with a % symbol (e.g., '45%').

DevOps-Focused

  1. 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.
  2. 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},
   ]

Enter fullscreen mode Exit fullscreen mode

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".

μ›λ¬Έμ—μ„œ 계속 β†—

μ½”λ©˜νŠΈ

λ‹΅κΈ€ 남기기

이메일 μ£Όμ†ŒλŠ” κ³΅κ°œλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. ν•„μˆ˜ ν•„λ“œλŠ” *둜 ν‘œμ‹œλ©λ‹ˆλ‹€