Understanding Python Variable Arguments, Lambdas, Packages, Generators, and Decorators
This article explains Python's variable‑length arguments (*args, **kwargs), anonymous lambda functions, package creation with __init__.py, memory‑efficient generators using yield, and powerful decorators—including practical code examples for each concept.
Python functions can accept an arbitrary number of arguments using *args (which collects extra positional arguments into a tuple) and **kwargs (which collects extra keyword arguments into a dictionary). Example:
def funA(a, b, *args):
print(a)
print(b)
print(args)
funA(1, 2, 3, 5, 6, 7)
# Output:
# 1
# 2
# (3, 5, 6, 7)
def funB(a, b, **vardict):
print(a)
print(b)
print(vardict)
print(vardict['l'])
funB(1, 2, l=3, m=4)
# Output:
# 1
# 2
# {'l': 3, 'm': 4}
# 3Anonymous (lambda) functions are single‑expression functions that can take any number of parameters. They are useful for short, non‑reusable code snippets. Example:
p = lambda x, y: x + y
print(p(4, 6)) # 10
a = lambda x: x * x
print(a(3)) # 9
b = lambda x, y, z: (x + 8) * y - z
print(b(5, 6, 8)) # 46A Python package is simply a directory containing an __init__.py file. To create one, create a folder named for the package and add an empty (or initialization) __init__.py inside.
Generators provide a memory‑efficient way to produce sequences on‑the‑fly. They use the yield keyword to return a value and suspend execution until the next call. Example of a generator expression:
L = [x * x for x in range(10)]
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
g = (x * x for x in range(10))
print(g) # <generator object <genexpr> at 0x...>A more elaborate generator can produce Pascal's triangle:
def triangle():
_list, new_list = [], []
while True:
length = len(_list)
if length == 0:
new_list.append(1)
else:
for i in range(length + 1):
if i == 0 or i == length:
new_list.append(1)
else:
new_list.append(_list[i - 1] + _list[i])
yield new_list
_list = new_list.copy()
new_list.clear()
n = 0
for row in triangle():
n += 1
print(row)
if n == 10:
breakAnother common generator example is the Fibonacci sequence:
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n += 1Decorators allow adding functionality to existing functions without modifying their code. A simple timing decorator:
import time
def time_it(func):
def inner():
start = time.time()
func()
end = time.time()
print('Elapsed: {} seconds'.format(end - start))
return inner
@time_it
def func1():
time.sleep(2)
print('Func1 is running')
if __name__ == '__main__':
func1()To preserve the original function’s metadata, use functools.wraps inside the decorator.
Nested functions (inner functions) are often used in decorators. Simple example:
def outer():
x = 1
def inner():
y = x + 1
print(y)
inner()
outer() # prints 2Returning the inner function creates a closure that can be called later:
def outer():
x = 1
def inner():
print(x + 1)
return inner
f = outer()
f() # prints 2A generic decorator template using wraps :
from functools import wraps
def hint(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f'{func.__name__} is running')
return func(*args, **kwargs)
return wrapper
@hint
def hello():
print('Hello!')Class‑based decorators can also be defined, with or without parameters, following the same principles.
Python Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.