[{"data":1,"prerenderedAt":178},["ShallowReactive",2],{"topic-python-functions":3},{"framework":4,"topic":15,"subtopics":24},{"id":5,"description":6,"extension":7,"icon":8,"meta":9,"name":10,"order":11,"slug":8,"stem":12,"tier":13,"__hash__":14},"frameworks\u002Fframeworks\u002Fpython.yml","Python interview questions across language fundamentals, data structures and common gotchas for backend, data and automation roles.","yml","python",{},"Python",3,"frameworks\u002Fpython",1,"QsijsotyAr-3rnhJDWWZmc7hE6HAhylS5t1dKpigMOA",{"id":16,"description":17,"extension":7,"frameworkSlug":8,"meta":18,"name":19,"order":20,"slug":21,"stem":22,"__hash__":23},"topics\u002Ftopics\u002Fpython-functions.yml","Arguments and unpacking, closures, decorators and higher-order functions — how Python treats functions as first-class objects.",{},"Functions",4,"functions","topics\u002Fpython-functions","A7vY4l7qHsjEdCjRLnpcHG6gaVS2ZfcWNuyO4ISlSJQ",[25,68,108,143],{"id":26,"title":27,"body":28,"description":32,"difficulty":35,"extension":36,"framework":10,"frameworkSlug":8,"meta":37,"navigation":38,"order":13,"path":39,"questions":40,"related":62,"seo":63,"seoDescription":64,"stem":65,"subtopic":27,"topic":19,"topicSlug":21,"updated":66,"__hash__":67},"qa\u002Fpython\u002Ffunctions\u002Fdecorators.md","Decorators",{"type":29,"value":30,"toc":31},"minimark",[],{"title":32,"searchDepth":33,"depth":33,"links":34},"",2,[],"hard","md",{},true,"\u002Fpython\u002Ffunctions\u002Fdecorators",[41,46,50,54,58],{"id":42,"difficulty":43,"q":44,"a":45},"what-is-decorator","medium","What is a decorator and how does it work?","A **decorator** is a **callable that takes a function and returns a (usually\nwrapped) function**, letting you add behaviour **without modifying** the original.\nThe `@decorator` syntax above a `def` is just sugar for **reassigning the name** to\nthe decorator's result: `func = decorator(func)`.\n\n```python\ndef log_calls(func):\n    def wrapper(*args, **kwargs):    # accept any signature\n        print(f\"calling {func.__name__}\")\n        return func(*args, **kwargs) # delegate to the original\n    return wrapper\n\n@log_calls\ndef add(a, b):\n    return a + b\n# equivalent to: add = log_calls(add)\n\nadd(2, 3)   # prints \"calling add\", returns 5\n```\n\nThis works because functions are **first-class objects** — they can be passed\naround and returned. Decorators are the idiomatic way to factor out\n**cross-cutting concerns** (logging, timing, caching, access control).\n",{"id":47,"difficulty":35,"q":48,"a":49},"functools-wraps","Why should you use functools.wraps in a decorator?","Without it, the wrapper **replaces the original function's identity**: the\ndecorated object reports the **wrapper's** `__name__`, `__doc__`, signature, and\n`__module__`, which breaks introspection, debugging, and tools that rely on\nmetadata. **`functools.wraps`** copies that metadata from the original onto the\nwrapper.\n\n```python\nimport functools\n\ndef log_calls(func):\n    @functools.wraps(func)       # copy name, docstring, __wrapped__, etc.\n    def wrapper(*args, **kwargs):\n        return func(*args, **kwargs)\n    return wrapper\n\n@log_calls\ndef greet():\n    \"say hello\"\n    ...\n\ngreet.__name__   # \"greet\"  (without wraps -> \"wrapper\")\ngreet.__doc__    # \"say hello\"\n```\n\nIt also sets `__wrapped__`, so `inspect.signature` and unwrapping still work.\nRule of thumb: **always** apply `@functools.wraps(func)` to your wrapper — it's\neffectively free and prevents subtle bugs.\n",{"id":51,"difficulty":35,"q":52,"a":53},"decorator-with-arguments","How do you write a decorator that takes arguments?","You add **another layer of nesting**: an outer function takes the **decorator's\narguments** and returns the actual decorator, which takes the function and returns\nthe wrapper. So `@repeat(3)` first **calls** `repeat(3)` to get a decorator, which\nis then applied to the function.\n\n```python\nimport functools\n\ndef repeat(n):                       # takes the decorator argument\n    def decorator(func):             # takes the function\n        @functools.wraps(func)\n        def wrapper(*args, **kwargs):\n            for _ in range(n):\n                result = func(*args, **kwargs)\n            return result\n        return wrapper\n    return decorator\n\n@repeat(3)                           # repeat(3) returns 'decorator'\ndef ping():\n    print(\"pong\")\n```\n\nThe mental model: `@repeat(3)` is `ping = repeat(3)(ping)` — three calls deep.\nRemember the parentheses: `@repeat(3)` (with args) differs from `@repeat` (passing\nthe function directly), and forgetting them is a common bug.\n",{"id":55,"difficulty":35,"q":56,"a":57},"class-based-decorator","How do you implement a decorator as a class?","A class becomes a decorator by being **callable** — define **`__call__`**. The\n`__init__` receives the decorated function; `__call__` runs the wrapping logic on\neach invocation. This is handy when the decorator needs to **hold state** (like a\ncall count) in a clean, attribute-based way.\n\n```python\nimport functools\n\nclass CountCalls:\n    def __init__(self, func):\n        functools.update_wrapper(self, func)  # the class-based wraps\n        self.func = func\n        self.count = 0\n    def __call__(self, *args, **kwargs):\n        self.count += 1\n        print(f\"call #{self.count}\")\n        return self.func(*args, **kwargs)\n\n@CountCalls\ndef hello():\n    print(\"hi\")\n\nhello(); hello()      # \"call #1\" then \"call #2\"\nhello.count           # 2 — state lives on the instance\n```\n\nUse `functools.update_wrapper` (the function-form of `wraps`) to preserve\nmetadata. Class decorators shine for **stateful** decorators; for simple stateless\nones, a nested function with a `nonlocal` closure is usually lighter.\n",{"id":59,"difficulty":43,"q":60,"a":61},"stacking-decorators","When you stack multiple decorators, in what order do they apply?","Decorators apply **bottom-up** (nearest the function first) at **definition\ntime**, but the resulting wrappers **execute top-down** at **call time**. Stacking\nis just nested application: the top decorator wraps the result of the ones below\nit.\n\n```python\n@a\n@b\ndef f(): ...\n# equivalent to: f = a(b(f))   — b wraps first, a wraps outermost\n\ndef bold(fn):\n    return lambda: \"\u003Cb>\" + fn() + \"\u003C\u002Fb>\"\ndef italic(fn):\n    return lambda: \"\u003Ci>\" + fn() + \"\u003C\u002Fi>\"\n\n@bold\n@italic\ndef text():\n    return \"hi\"\n\ntext()   # \"\u003Cb>\u003Ci>hi\u003C\u002Fi>\u003C\u002Fb>\"  — bold is outer, runs around italic\n```\n\nSo the **closest** decorator is applied first but its logic runs **innermost**.\nOrder matters whenever decorators have side effects or transform results — e.g.\nput `@staticmethod` outermost, or `@app.route` above `@login_required` so auth\nruns before the view.\n",null,{"description":32},"Python interview questions on decorators, functools.wraps, decorators with arguments, class-based decorators, stacking order, and real-world use cases.","python\u002Ffunctions\u002Fdecorators","2026-06-18","lkoUwwiWM-viu-zDimboEggNtVDCmWFyyrcd9HEU_xI",{"id":69,"title":70,"body":71,"description":32,"difficulty":43,"extension":36,"framework":10,"frameworkSlug":8,"meta":75,"navigation":38,"order":33,"path":76,"questions":77,"related":62,"seo":103,"seoDescription":104,"stem":105,"subtopic":106,"topic":19,"topicSlug":21,"updated":66,"__hash__":107},"qa\u002Fpython\u002Ffunctions\u002Farguments.md","Arguments",{"type":29,"value":72,"toc":73},[],{"title":32,"searchDepth":33,"depth":33,"links":74},[],{},"\u002Fpython\u002Ffunctions\u002Farguments",[78,82,87,91,95,99],{"id":79,"difficulty":43,"q":80,"a":81},"args-kwargs","What do *args and **kwargs do?","In a function signature, **`*args`** collects extra **positional** arguments\ninto a tuple, and **`**kwargs`** collects extra **keyword** arguments into a\ndict. They let a function accept a variable number of arguments. The names\nare convention — only the `*`\u002F`**` matter.\n\n```python\ndef log(level, *args, **kwargs):\n    print(level, args, kwargs)\n\nlog(\"INFO\", 1, 2, user=\"ada\", id=7)\n# INFO (1, 2) {'user': 'ada', 'id': 7}\n```\n\n`args` is always a `tuple` and `kwargs` always a `dict`. They're essential\nfor writing wrappers\u002Fdecorators that forward arbitrary arguments through to\nanother callable.\n",{"id":83,"difficulty":84,"q":85,"a":86},"positional-vs-keyword","easy","What is the difference between positional and keyword arguments?","**Positional arguments** are matched to parameters by their **order**.\n**Keyword arguments** are matched by **name** (`param=value`), so order\ndoesn't matter among them. At the call site you can mix the two, but every\npositional argument must come **before** any keyword argument.\n\n```python\ndef greet(name, greeting): ...\n\ngreet(\"Ada\", \"Hello\")              # both positional\ngreet(name=\"Ada\", greeting=\"Hi\")   # both keyword (order free)\ngreet(\"Ada\", greeting=\"Hi\")        # mix: positional first\ngreet(name=\"Ada\", \"Hi\")            # SyntaxError — kw before positional\n```\n\nKeyword arguments make calls self-documenting and let you skip over earlier\nparameters that have defaults. Use them for clarity on boolean flags and\nlong argument lists.\n",{"id":88,"difficulty":84,"q":89,"a":90},"default-args","How do default argument values work?","A parameter with `name=value` is **optional** — if the caller omits it, the\ndefault is used. Defaults are evaluated **once**, when the `def` runs, so\nusing a **mutable** default (`[]`, `{}`) is a classic trap: the same object\npersists across calls.\n\n```python\ndef connect(host, port=5432, timeout=30):\n    ...\nconnect(\"db\")                 # uses port=5432, timeout=30\nconnect(\"db\", timeout=5)      # override one by keyword\n\ndef bad(item, bucket=[]):     # DON'T — shared list\n    bucket.append(item); return bucket\n```\n\nThe safe pattern for a mutable default is `bucket=None` plus\n`if bucket is None: bucket = []` inside the body. Parameters with defaults\nmust come after those without.\n",{"id":92,"difficulty":43,"q":93,"a":94},"keyword-only","What are keyword-only arguments?","Any parameter listed **after a bare `*`** (or after `*args`) is\n**keyword-only** — it can never be passed positionally and must be named at\nthe call site. This forces clearer calls and prevents accidental\npositional mistakes.\n\n```python\ndef make_request(url, *, timeout=30, verify=True):\n    ...\n\nmake_request(\"http:\u002F\u002Fx\", timeout=5)     # OK\nmake_request(\"http:\u002F\u002Fx\", 5)             # TypeError — timeout is kw-only\n```\n\nKeyword-only parameters are great for optional flags whose meaning isn't\nobvious from position (especially booleans). The lone `*` is just a\nseparator; it doesn't collect anything.\n",{"id":96,"difficulty":35,"q":97,"a":98},"positional-only","What are positional-only parameters?","Parameters listed **before a `\u002F`** in the signature are **positional-only**\n(Python 3.8+) — they cannot be passed by keyword. This is useful for APIs\nwhere the parameter name is an implementation detail you don't want callers\nto depend on.\n\n```python\ndef divide(a, b, \u002F):\n    return a \u002F b\n\ndivide(10, 2)          # OK\ndivide(a=10, b=2)      # TypeError — a, b are positional-only\n```\n\nIt also frees those names for use in `**kwargs`. Many built-ins (like\n`len`, `pow`) are positional-only. Combined with `*`, a signature can have\npositional-only, normal, and keyword-only sections.\n",{"id":100,"difficulty":43,"q":101,"a":102},"param-ordering","What is the correct order of parameters in a signature?","A full signature follows a fixed order:\n**positional-only `\u002F`, then normal, then `*args`, then keyword-only, then\n`**kwargs`**. Within each group, parameters without defaults precede those\nwith defaults.\n\n```python\ndef f(pos_only, \u002F, normal, *args, kw_only, **kwargs):\n    ...\n\n# call-site unpacking mirrors this:\ndef g(a, b, c): ...\nnums = [1, 2, 3]\ng(*nums)                 # spread list into positionals\ng(**{\"a\": 1, \"b\": 2, \"c\": 3})   # spread dict into keywords\n```\n\nGetting the order wrong is a `SyntaxError`. The `*`\u002F`\u002F` markers partition\nthe signature; remember the sequence \"positional-only → normal → varargs →\nkeyword-only → varkwargs.\"\n",{"description":32},"Python interview questions on args and kwargs, positional vs keyword arguments, defaults, keyword-only and positional-only parameters, unpacking at the call site, and parameter ordering rules.","python\u002Ffunctions\u002Farguments","Function Arguments","T4lWvDZqp8gjS6SokbQyTXGimya-uvBG8xPkeyfFJ4k",{"id":109,"title":110,"body":111,"description":32,"difficulty":35,"extension":36,"framework":10,"frameworkSlug":8,"meta":115,"navigation":38,"order":11,"path":116,"questions":117,"related":62,"seo":138,"seoDescription":139,"stem":140,"subtopic":141,"topic":19,"topicSlug":21,"updated":66,"__hash__":142},"qa\u002Fpython\u002Ffunctions\u002Fclosures.md","Closures",{"type":29,"value":112,"toc":113},[],{"title":32,"searchDepth":33,"depth":33,"links":114},[],{},"\u002Fpython\u002Ffunctions\u002Fclosures",[118,122,126,130,134],{"id":119,"difficulty":35,"q":120,"a":121},"what-is-a-closure","What is a closure and what are free variables?","A **closure** is a nested function that **remembers variables from its\nenclosing scope** even after that outer function has returned. The\nremembered names are called **free variables** — they're neither local\nparameters nor globals. Python stores them on the function's `__closure__`\nattribute.\n\n```python\ndef multiplier(factor):\n    def multiply(n):\n        return n * factor      # 'factor' is a free variable\n    return multiply\n\ndouble = multiplier(2)\ndouble(5)                      # 10\ndouble.__closure__[0].cell_contents   # 2 — captured value\n```\n\nThe inner function keeps the binding alive via a **cell object**, which is\nwhy `multiplier` can return and `double` still works. Closures are how\nPython functions carry private state without a class.\n",{"id":123,"difficulty":43,"q":124,"a":125},"nonlocal","What does the nonlocal keyword do?","By default, assigning to a name inside a function creates a **new local**.\n**`nonlocal`** tells Python that an assignment should instead **rebind a\nvariable in the nearest enclosing function scope** — letting a closure\nmutate, not just read, the captured variable.\n\n```python\ndef counter():\n    count = 0\n    def increment():\n        nonlocal count        # rebind outer 'count'\n        count += 1\n        return count\n    return increment\n\nc = counter()\nc(); c()                       # 1, then 2\n```\n\nWithout `nonlocal`, `count += 1` would raise `UnboundLocalError` (it reads\nthen assigns a local). Use `nonlocal` for enclosing-function scope and\n`global` for module scope.\n",{"id":127,"difficulty":35,"q":128,"a":129},"late-binding","Why do closures in a loop all capture the same value?","Closures capture **variables, not values** — this is **late binding**. A\nfunction created in a loop looks up the loop variable when it's *called*, not\nwhen it's defined, so every closure sees the variable's **final** value.\n\n```python\nfuncs = [lambda: i for i in range(3)]\n[f() for f in funcs]           # [2, 2, 2]  — all see final i\n\n# fix: bind the current value via a default argument\nfuncs = [lambda i=i: i for i in range(3)]\n[f() for f in funcs]           # [0, 1, 2]\n```\n\nThe default-argument trick works because **defaults are evaluated at\ndefinition time**, snapshotting `i` per iteration. A factory function that\ntakes `i` as a parameter achieves the same. This is a favorite interview\ngotcha.\n",{"id":131,"difficulty":35,"q":132,"a":133},"closure-cell","How can you inspect a closure's captured variables?","A function with free variables has a non-`None` **`__closure__`** — a tuple\nof **cell** objects, each holding one captured binding accessible via\n`cell_contents`. The matching names are listed in\n`__code__.co_freevars`. Functions with no closure have `__closure__ is\nNone`.\n\n```python\ndef make(x, y):\n    def inner():\n        return x + y\n    return inner\n\nf = make(3, 4)\nf.__code__.co_freevars               # ('x', 'y')\n[c.cell_contents for c in f.__closure__]   # [3, 4]\n```\n\nThis is mostly useful for debugging or teaching how closures actually\nstore state. The cells are shared live, so `nonlocal` rebinds are visible\nthrough `cell_contents`.\n",{"id":135,"difficulty":43,"q":136,"a":137},"closures-vs-classes","When should you use a closure instead of a class?","Both bundle **behavior with state**. A **closure** is lighter and ideal\nwhen you need a *single* method and a little hidden state. A **class** wins\nwhen you need multiple methods, inheritance, or explicit, inspectable\nstate. Common closure uses include **factories, decorators, and callbacks**.\n\n```python\n# closure: tiny stateful function\ndef make_adder(n):\n    return lambda x: x + n\nadd10 = make_adder(10)\n\n# class: equivalent but heavier\nclass Adder:\n    def __init__(self, n): self.n = n\n    def __call__(self, x): return x + self.n\n```\n\nRule of thumb: one behavior + private state → closure; many behaviors or\nshared interface → class. Decorators are the canonical real-world closure.\n",{"description":32},"Python interview questions on closures and free variables, __closure__, the nonlocal keyword, late binding in loops and the default-argument fix, closures vs classes, and common closure uses.","python\u002Ffunctions\u002Fclosures","Closures & Scope","UgESsdHC55Ja_QpbICRE7AnqAyUYkc7CLH5xgyGMyz8",{"id":144,"title":145,"body":146,"description":32,"difficulty":43,"extension":36,"framework":10,"frameworkSlug":8,"meta":150,"navigation":38,"order":20,"path":151,"questions":152,"related":62,"seo":173,"seoDescription":174,"stem":175,"subtopic":176,"topic":19,"topicSlug":21,"updated":66,"__hash__":177},"qa\u002Fpython\u002Ffunctions\u002Flambdas.md","Lambdas",{"type":29,"value":147,"toc":148},[],{"title":32,"searchDepth":33,"depth":33,"links":149},[],{},"\u002Fpython\u002Ffunctions\u002Flambdas",[153,157,161,165,169],{"id":154,"difficulty":84,"q":155,"a":156},"lambda-syntax","What is a lambda and what are its limitations?","A **lambda** is an anonymous, single-**expression** function:\n`lambda args: expression`. It returns the expression's value automatically\n(no `return`). Its limitation is exactly that — it can hold only **one\nexpression**, no statements, assignments, loops, or annotations.\n\n```python\nsquare = lambda x: x * x\nsquare(5)                  # 25\n\nadd = lambda a, b=1: a + b # defaults allowed\nadd(10)                    # 11\n\n# NOT allowed: lambda x: (y = x; return y)  — no statements\n```\n\nBecause it's an expression, a lambda can be passed inline wherever a\nfunction is expected. Keep them short; anything needing multiple lines or a\ndocstring should be a named `def`.\n",{"id":158,"difficulty":43,"q":159,"a":160},"lambda-vs-def","When should you use a lambda versus a def?","Use a **lambda** for a tiny throwaway function passed **inline** as an\nargument (a sort key, a callback). Use **`def`** for anything reused, named,\ndocumented, or non-trivial. A named function gives a useful `__name__` in\ntracebacks; a lambda just shows `\u003Clambda>`.\n\n```python\n# good lambda: inline, one-off\nsorted(words, key=lambda w: len(w))\n\n# prefer def: reused \u002F needs a name\ndef by_length(w):\n    return len(w)\n```\n\nPEP 8 even discourages **assigning** a lambda to a name\n(`f = lambda x: ...`) — if you need a name, just use `def`. Lambdas shine as\narguments, not as definitions.\n",{"id":162,"difficulty":43,"q":163,"a":164},"higher-order-functions","What is a higher-order function?","A **higher-order function** is one that **takes a function as an argument\nand\u002For returns a function**. They enable composing and parameterizing\nbehavior. Built-in examples include `map`, `filter`, `sorted`, and the\n`functools` tools.\n\n```python\ndef apply_twice(fn, x):\n    return fn(fn(x))           # takes a function\n\napply_twice(lambda n: n + 3, 10)   # 16\n\nlist(map(str.upper, [\"a\", \"b\"]))   # ['A', 'B']\nlist(filter(lambda n: n > 0, [-1, 2, -3, 4]))  # [2, 4]\n```\n\nHigher-order functions are the foundation of functional-style Python and of\ndecorators (which both take and return functions). They let you pass\n*behavior* around as data.\n",{"id":166,"difficulty":43,"q":167,"a":168},"key-argument","How does the key argument work in sorted, max, and min?","`key` takes a **function** applied to each element to derive the value used\nfor **comparison** — the elements themselves aren't changed, only how\nthey're ranked. It's used by `sorted`, `list.sort`, `max`, and `min`.\n\n```python\nwords = [\"banana\", \"kiwi\", \"apple\"]\n\nsorted(words, key=len)                 # ['kiwi', 'apple', 'banana']\nmax(words, key=len)                    # 'banana'\nsorted(words, key=str.lower)           # case-insensitive\n\npeople = [(\"ada\", 36), (\"grace\", 45)]\nmax(people, key=lambda p: p[1])        # ('grace', 45)\n```\n\n`key` is called **once per element** (efficient), unlike the old `cmp`\nstyle. For multi-level sorts, return a **tuple**:\n`key=lambda p: (p.last, p.first)`.\n",{"id":170,"difficulty":43,"q":171,"a":172},"first-class-functions","What does it mean that functions are first-class objects?","In Python, functions are **first-class objects**: they can be assigned to\nvariables, stored in data structures, passed as arguments, and **returned**\nfrom other functions — just like any value. This is what makes higher-order\nfunctions and closures possible.\n\n```python\ndef shout(s): return s.upper() + \"!\"\n\nf = shout                 # assign to a variable\nf(\"hi\")                   # 'HI!'\n\ndispatch = {\"loud\": shout}        # store in a dict\ndispatch[\"loud\"](\"hey\")           # 'HEY!'\n\ndef make_op(op):                  # return a function\n    return (lambda a, b: a + b) if op == \"+\" else (lambda a, b: a - b)\nmake_op(\"+\")(2, 3)                # 5\n```\n\nTreating functions as values enables strategy\u002Fdispatch tables, callbacks,\nand decorators. There's no separate \"function pointer\" concept — the\nfunction *is* the object.\n",{"description":32},"Python interview questions on lambda syntax and limitations, lambda vs def, higher-order functions, the key argument in sorted\u002Fmax\u002Fmin, and functions as first-class objects.","python\u002Ffunctions\u002Flambdas","Lambdas & Higher-Order Functions","9_y3LjVbDK5c4cIpcmC5IQFqaQxIZJqZxiPop420_2E",1781808674994]