Python Functions are one of the most important building blocks of clean and reusable Python code. Instead of writing the same logic repeatedly, you can put that logic inside a function and call it whenever you need it.
But Python functions can do much more than simply accept arguments and return values.
With the right techniques, functions can become:
- Cleaner
- Shorter
- More reusable
- Easier to test
- More readable
- More flexible
- More powerful
In this guide, we’ll explore 25+ Python function tricks and shortcuts, from beginner-friendly techniques to modern professional patterns.
1. The Basic Python Function
The simplest function uses the def keyword:
def greet():
return "Hello, Python!"
print(greet())
Output
Hello, Python!
The basic structure is:
def function_name(parameters):
# logic
return result
A function can contain logic once and reuse it many times.
2. Use Parameters Instead of Duplicating Functions
Instead of creating multiple functions:
def greet_dhruv():
return "Hello Dhruv"
def greet_rahul():
return "Hello Rahul"
Use one parameterized function:
def greet(name):
return f"Hello {name}"
print(greet("Dhruv"))
print(greet("Rahul"))
This is one of the most important principles of programming:
Write the logic once, reuse it everywhere.
3. Use Default Arguments as Smart Shortcuts
Default arguments allow a function to work even when the caller doesn’t provide every value.
def greet(name="Developer"):
return f"Hello, {name}!"
print(greet())
print(greet("Python Developer"))
Output:
Hello, Developer!
Hello, Python Developer!
This is extremely useful for configuration-style functions.
Example
def connect(host="localhost", port=8000):
print(f"Connecting to {host}:{port}")
connect()
connect("example.com", 443)
4. Keyword Arguments Make Code More Readable
Instead of:
create_user("Divesh", 17, "Python")
you can write:
create_user(
name="Divesh",
age=17,
skill="Python"
)
Keyword arguments make function calls easier to understand.
They become especially useful when a function has several parameters.
5. The Professional * Trick: Keyword-Only Arguments
One of the most useful modern function techniques is the bare *.
def create_user(name, *, active=True, role="user"):
return {
"name": name,
"active": active,
"role": role
}
Now this works:
create_user("Alex", active=True, role="admin")
But this does not:
create_user("Alex", True, "admin")
Why?
Everything after * must be passed by keyword.
Python’s documentation specifically supports * for defining keyword-only parameters.
Why professionals use this
It makes APIs self-documenting:
send_email(
"hello@example.com",
subject="Welcome",
priority="high"
)
is easier to understand than:
send_email(
"hello@example.com",
"Welcome",
"high"
)
6. The / Trick: Positional-Only Arguments
Python also supports positional-only parameters using /.
def power(base, exponent, /):
return base ** exponent
You must call it like:
power(2, 3)
Not:
power(base=2, exponent=3)
This can be useful when you want to control how an API is called.
Python introduced positional-only syntax using / as part of PEP 570.
7. Combine / and * for Professional APIs
You can combine all parameter styles:
def calculate(
amount,
/,
tax=0,
*,
currency="USD",
rounded=True
):
result = amount + tax
if rounded:
result = round(result, 2)
return f"{result} {currency}"
Now:
calculate(100, 18, currency="INR")
This gives you precise control over your function interface.
The three major categories are:
before / → positional-only
normal → positional or keyword
after * → keyword-only
8. *args: Accept Unlimited Positional Arguments
Suppose you don’t know how many numbers the caller will provide.
Instead of:
def total(a, b, c, d):
return a + b + c + d
use:
def total(*numbers):
return sum(numbers)
print(total(10, 20))
print(total(10, 20, 30, 40))
Output:
30
100
Inside the function, numbers is a tuple.
def show(*args):
print(args)
show(1, 2, 3)
Output:
(1, 2, 3)
9. **kwargs: Accept Unlimited Keyword Arguments
**kwargs collects additional keyword arguments into a dictionary.
def profile(**details):
return details
print(profile(
name="Alex",
language="Python",
level="Advanced"
))
Output:
{
'name': 'Alex',
'language': 'Python',
'level': 'Advanced'
}
Python’s documentation describes *args as collecting positional arguments and **kwargs as collecting keyword arguments.
10. The Ultimate Flexible Function Pattern
You can combine normal parameters, *args, keyword-only arguments, and **kwargs.
def process(name, *items, verbose=False, **options):
print("Name:", name)
print("Items:", items)
print("Verbose:", verbose)
print("Options:", options)
Example:
process(
"Python",
10,
20,
30,
verbose=True,
mode="fast",
debug=True
)
This pattern is especially useful for wrapper functions and frameworks.
11. Unpack Arguments with *
You can also use * when calling a function.
def add(a, b, c):
return a + b + c
numbers = [10, 20, 30]
print(add(*numbers))
Instead of:
add(numbers[0], numbers[1], numbers[2])
you can simply use:
add(*numbers)
Think of * as:
“Take this collection and unpack its values.”
12. Unpack Dictionaries with **
The same idea works with dictionaries.
def user(name, age, city):
return f"{name}, {age}, {city}"
data = {
"name": "Alex",
"age": 20,
"city": "Delhi"
}
print(user(**data))
**data maps dictionary keys to function parameter names.
This is particularly useful when working with configuration dictionaries and API-style data.
13. Return Multiple Values Without a Class
Python lets you return multiple values easily:
def get_user():
return "Alex", 20, "Python"
You can unpack them:
name, age, skill = get_user()
print(name)
print(age)
print(skill)
Technically, Python is returning a tuple:
("Alex", 20, "Python")
This is a very convenient shortcut.
14. Use Multiple Return Values for Calculations
Example:
def calculate(a, b):
return a + b, a - b, a * b
addition, subtraction, multiplication = calculate(10, 5)
This keeps related results together without requiring unnecessary structures.
15. Lambda Functions: Tiny One-Line Functions
A lambda is an anonymous function.
Instead of:
def square(x):
return x * x
you can write:
square = lambda x: x * x
Then:
print(square(5))
Output:
25
Best use
Lambda functions are most useful when the function is:
- Very small
- Used locally
- Passed as an argument
For larger logic, a normal def is usually more readable.
16. Sort Data with a Lambda Trick
One of the most useful real-world patterns:
users = [
{"name": "Alex", "age": 25},
{"name": "Sam", "age": 19},
{"name": "John", "age": 30}
]
users.sort(key=lambda user: user["age"])
Now users are sorted by age.
You can also sort descending:
users.sort(
key=lambda user: user["age"],
reverse=True
)
This is a classic Python shortcut.
17. Functions Can Be Stored in Variables
In Python, functions are objects.
That means you can assign a function to another variable:
def greet():
return "Hello!"
message = greet
print(message())
Here:
message
points to the same function.
This concept is fundamental to Python’s functional programming capabilities.
18. Pass Functions as Arguments
Functions can be passed into other functions.
def square(x):
return x * x
def apply(function, value):
return function(value)
print(apply(square, 5))
Output:
25
This is called using a higher-order function.
19. Create Functions That Return Functions
Functions can also return other functions.
def multiplier(n):
def multiply(x):
return x * n
return multiply
Now:
double = multiplier(2)
triple = multiplier(3)
print(double(10))
print(triple(10))
Output:
20
30
The inner function remembers n.
This is called a closure.
20. Use Closures for Reusable Configuration
A practical example:
def make_discount(rate):
def discount(price):
return price * (1 - rate)
return discount
student_discount = make_discount(0.10)
premium_discount = make_discount(0.20)
print(student_discount(1000))
print(premium_discount(1000))
Now you have specialized functions created from one function factory.
21. Decorators: The Superpower of Python Functions
A decorator allows you to modify or wrap another function.
Basic example:
def logger(function):
def wrapper():
print("Function started")
result = function()
print("Function finished")
return result
return wrapper
Use it like this:
@logger
def greet():
return "Hello!"
print(greet())
The @logger syntax is essentially applying the decorator to the function. Python’s language reference describes decorators as expressions that transform the function when it is defined.
22. Professional Decorators with *args and **kwargs
A decorator should usually be flexible enough to work with functions having different arguments.
from functools import wraps
def logger(function):
@wraps(function)
def wrapper(*args, **kwargs):
print(f"Running {function.__name__}")
result = function(*args, **kwargs)
print("Finished")
return result
return wrapper
Now:
@logger
def add(a, b):
return a + b
print(add(10, 20))
@wraps helps preserve useful metadata from the original function.
23. Cache Expensive Function Results
If a function repeatedly calculates the same result, caching can save work.
Python’s functools module provides cache for this purpose.
from functools import cache
@cache
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
Now repeated calls can reuse previously calculated results.
Simple rule
Use caching when:
same input → same output
and the calculation is expensive enough for caching to matter.
Don’t blindly cache every function.
24. functools.partial() — Freeze Function Arguments
partial() creates a new callable with some arguments already filled in.
Example:
from functools import partial
def power(number, exponent):
return number ** exponent
square = partial(power, exponent=2)
cube = partial(power, exponent=3)
print(square(5))
print(cube(5))
Output:
25
125
Instead of repeatedly writing:
power(number, 2)
you can create:
square(number)
This is a powerful functional-programming technique.
25. Function Type Hints Make Code Professional
You can add type annotations:
def add(a: int, b: int) -> int:
return a + b
This tells readers and development tools what the function expects and returns.
Another example:
def greet(name: str) -> str:
return f"Hello, {name}"
Important:
Type annotations don’t automatically enforce the types at runtime.
They primarily provide information for humans and development/type-checking tools.
26. Use Docstrings for Self-Documenting Functions
A professional function should explain what it does.
def calculate_tax(price: float, rate: float) -> float:
"""
Calculate tax for a given price and tax rate.
"""
return price * rate
You can inspect the documentation:
print(calculate_tax.__doc__)
Docstrings make reusable code much easier to understand.
27. The return Shortcut
Instead of:
def is_even(number):
if number % 2 == 0:
return True
else:
return False
use:
def is_even(number):
return number % 2 == 0
This is shorter and clearer.
Rule
If you’re only returning a condition, return the condition directly.
28. Use Conditional Expressions Inside Functions
Instead of:
def status(age):
if age >= 18:
return "Adult"
else:
return "Minor"
you can write:
def status(age):
return "Adult" if age >= 18 else "Minor"
This is called a conditional expression.
Use it when the condition is simple enough to remain readable.
29. Avoid Mutable Default Arguments
This is one of the most important Python function pitfalls.
Avoid:
def add_item(item, items=[]):
items.append(item)
return items
The same list can be reused across calls.
Instead use:
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
Now each call can get a fresh list.
Remember
Avoid mutable defaults such as:
[]
{}
set()
when you intend to create a new object for each call.
30. Use operator Instead of Tiny Lambdas
Sometimes you can replace a lambda with a standard operator function.
Instead of:
numbers.sort(key=lambda x: x)
you may use functions from operator for appropriate cases.
For example:
from operator import itemgetter
users.sort(key=itemgetter("age"))
The operator module provides functions corresponding to many Python operators and is part of Python’s functional-programming toolkit.
This can make some data-processing code cleaner.
31. Function Factories for Reusable Logic
A function factory creates customized functions.
def make_greeter(prefix):
def greet(name):
return f"{prefix}, {name}!"
return greet
Then:
hello = make_greeter("Hello")
welcome = make_greeter("Welcome")
print(hello("Alex"))
print(welcome("Alex"))
This pattern appears in advanced Python applications, decorators, callbacks, and configurable systems.
32. Use Functions as a Strategy Pattern
Instead of a large if/elif structure:
def calculate(operation, a, b):
if operation == "add":
return a + b
elif operation == "subtract":
return a - b
elif operation == "multiply":
return a * b
You can map operations to functions:
operations = {
"add": lambda a, b: a + b,
"subtract": lambda a, b: a - b,
"multiply": lambda a, b: a * b
}
def calculate(operation, a, b):
return operations[operation](a, b)
Now adding a new operation is easier.
33. Use all() and any() Inside Functions
Instead of manually checking every item:
def all_positive(numbers):
for number in numbers:
if number <= 0:
return False
return True
use:
def all_positive(numbers):
return all(number > 0 for number in numbers)
Similarly:
def has_negative(numbers):
return any(number < 0 for number in numbers)
These are concise and expressive.
34. Use Generator Expressions for Large Data
Instead of creating a complete list:
def total_squares(numbers):
squares = [x * x for x in numbers]
return sum(squares)
you can write:
def total_squares(numbers):
return sum(x * x for x in numbers)
The second version avoids creating an intermediate list.
This can be particularly useful when processing large iterables.
35. Use map() When It Actually Improves Readability
Example:
numbers = [1, 2, 3, 4]
squares = list(map(lambda x: x * x, numbers))
But in modern Python, this is often clearer:
squares = [x * x for x in numbers]
Professional rule
Don’t use a function because it is shorter.
Use it when it makes the intent clearer.
Readable code beats clever code.
36. Use filter() Carefully
Example:
numbers = [1, 2, 3, 4, 5, 6]
even = list(filter(lambda x: x % 2 == 0, numbers))
A list comprehension is often easier to read:
even = [x for x in numbers if x % 2 == 0]
So the shortcut isn’t always the best solution.
37. Recursive Functions
A function can call itself.
def countdown(n):
if n <= 0:
return
print(n)
countdown(n - 1)
countdown(5)
Output:
5
4
3
2
1
Recursion is useful for problems naturally represented as nested structures, such as trees.
For ordinary counting loops, a loop is usually simpler.
38. Use raise to Validate Function Inputs
Professional functions should reject invalid input clearly.
def divide(a, b):
if b == 0:
raise ValueError("b cannot be zero")
return a / b
Now errors are explicit:
divide(10, 0)
Instead of allowing confusing behavior later.
39. Functions Should Usually Do One Job
Avoid giant functions:
def process_everything():
# database
# validation
# calculations
# email
# logging
# formatting
# API calls
Instead divide responsibilities:
def validate_user():
...
def calculate_total():
...
def save_user():
...
def send_notification():
...
This is the Single Responsibility Principle applied to functions.
Smaller functions are generally easier to:
- Test
- Debug
- Reuse
- Understand
- Maintain
40. The Ultimate Python Function Cheat Sheet
Basic
def hello():
return "Hello"
Parameter
def hello(name):
return f"Hello {name}"
Default
def hello(name="Developer"):
return f"Hello {name}"
Positional-only
def func(x, /):
...
Keyword-only
def func(*, x):
...
Unlimited positional arguments
def func(*args):
...
Unlimited keyword arguments
def func(**kwargs):
...
Unpack list/tuple
func(*values)
Unpack dictionary
func(**data)
Lambda
square = lambda x: x * x
Multiple returns
return a, b, c
Decorator
@decorator
def function():
...
Cache
from functools import cache
@cache
def function(x):
...
Partial function
from functools import partial
new_func = partial(function, value=10)
Type hints
def add(a: int, b: int) -> int:
return a + b
41. Best Modern Function Pattern
For production-quality code, a function can combine several techniques:
def calculate_total(
price: float,
quantity: int = 1,
/,
*,
tax_rate: float = 0.0,
discount: float = 0.0
) -> float:
"""
Calculate the final price after discount and tax.
"""
subtotal = price * quantity
subtotal -= subtotal * discount
subtotal += subtotal * tax_rate
return round(subtotal, 2)
Usage:
total = calculate_total(
1000,
2,
tax_rate=0.18,
discount=0.10
)
print(total)
This one example demonstrates:
- Type annotations
- Default parameters
- Positional-only parameters
- Keyword-only parameters
- Docstrings
- Return values
- Clear naming
- Reusable logic
42. The 10 Function Tricks You Should Memorize
If you want the fastest learning path, memorize these first:
Trick 1 — Default values
def greet(name="Developer"):
...
Trick 2 — Keyword-only arguments
def connect(host, *, timeout=10):
...
Trick 3 — Positional-only arguments
def calculate(value, /):
...
Trick 4 — Unlimited positional arguments
def total(*numbers):
return sum(numbers)
Trick 5 — Unlimited keyword arguments
def config(**options):
return options
Trick 6 — Unpack arguments
func(*items)
Trick 7 — Unpack dictionaries
func(**data)
Trick 8 — Small lambda
lambda x: x * 2
Trick 9 — Cache repeated calculations
@cache
def expensive(x):
...
Trick 10 — Decorators
@decorator
def function():
...
43. Python Functions: Beginner → Professional Roadmap
Level 1 — Fundamentals
Learn:
def
return
parameters
arguments
default values
Level 2 — Flexible Functions
Learn:
*args
**kwargs
*
/
argument unpacking
Level 3 — Functional Python
Learn:
lambda
map()
filter()
all()
any()
operator
Level 4 — Advanced Functions
Learn:
closures
decorators
function factories
higher-order functions
Level 5 — Professional Python
Learn:
type hints
docstrings
functools
cache
partial
testing
clean API design
Python’s standard library includes functools, itertools, and operator specifically for functional-style programming and callable operations.
Final Thoughts
Python functions are much more than reusable blocks of code.
Once you understand:
parameters
↓
*args / **kwargs
↓
* / parameter control
↓
lambda
↓
closures
↓
decorators
↓
functools
↓
function factories
you can write Python that is shorter without sacrificing readability.
The most important professional lesson is:
Don’t try to make every function clever. Make every function clear, reusable, predictable, and easy to test.
Use shortcuts when they improve readability—not simply because they reduce the number of lines.
With these techniques, your Python functions can move from simple beginner code to clean, flexible, production-quality code.
